Setting different styles for Dual level grouping with DataTrigger - wpf

I have a dual level grouping and thought I could define different styles with DataTriggers.
Thinking that GroupStyles.HeaderTemplate would bind to CollectionViewGroup I tried DataBinding to IsBottomLevel property.
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock x:Name="GroupName"
Text="{Binding Path=Name}"
Foreground="Red" />
<DataTemplate.Triggers>
<DataTrigger Binding="IsBottomLevel" Value="True" >
<Setter TargetName="GroupName" Property="Foreground" Value="Blue" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
Can I get this to work somehow?

Define your trigger in the Style of the TextBlock itself, TargetName normally is for ControlTemplates, then you can just drop that.
This is not a binding:
Binding="IsBottomLevel"
You should replace it with the following of course:
Binding="{Binding IsBottomLevel}"
<TextBlock Text="{Binding Name}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsBottomLevel}" Value="True">
<Setter Property="Foreground" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
If you set the red Foreground directly in the TextBlock declaration the trigger will have no effect due to precedence.

Related

WPF: Can not find the Trigger target 'cc'. The target must appear before any Setters, Triggers

what is wrong about the following code?
I get this error during compilation:
The property 'TargetName' does not represent a valid target for the 'Setter' because an element named 'cc' was not found. Make sure that the target is declared before any Setters, Triggers or Conditions that use it.
How do I have to refactor my code so I can compile it without error?
I just want to switch a datatemplate with DataTrigger bound to a value in my PersonViewModel!
<ContentControl x:Name="cc" Grid.Column="1">
<DataTemplate>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=CurrentPersonViewModel.IsNew}" Value="True">
<Setter TargetName="cc" Property="ContentTemplate" Value="{DynamicResource NewPersonId}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=CurrentPersonViewModel.IsNew}" Value="False">
<Setter TargetName="cc" Property="ContentTemplate" Value="{DynamicResource SelectedPersonId}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl>
Update
You can use a Style for the ContentControl and change the ContentTemplate from there
<ContentControl Name="cc" Grid.Column="1">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{DynamicResource SelectedPersonId}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CurrentPersonViewModel.IsNew}" Value="True">
<Setter Property="ContentTemplate" Value="{DynamicResource NewPersonId}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
UPDATE
I don't understand why the View's in the DataTemplate doesn't inherit the DataContext. Got it working by using this but I can't see why this is necessary
<DataTemplate x:Key="NewPersonId">
<local:NewPersonView DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContentControl}}, Path=DataContext.CurrentPersonViewModel}" />
</DataTemplate>
<DataTemplate x:Key="SelectedPersonId">
<local:SelectedPersonView DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContentControl}}, Path=DataContext.SelectedPersonViewModel}"/>
</DataTemplate>
You do not need the whole DataTrigger stuff.
Just read this to make your DataTemplateSelector work properly:
http://joshsmithonwpf.wordpress.com/2007/03/18/updating-the-ui-when-binding-directly-to-business-objects-that-are-modified/

WPF Listbox - Empty List Display Message

Can anyone suggest the best way to display a Textblock (with a text such as "List Empty") so that it's visibility is bound to the Items.Count.
I have tried the following code and can't get it to work, so think that I must be doing it wrong.
<ListBox x:Name="lstItems"
ItemsSource="{Binding ListItems}">
</ListBox>
<TextBlock Margin="4" FontStyle="Italic" FontSize="12" Text="List is empty" Visibility="Collapsed">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lstItems, Path=Items.Count}" Value="0">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
The problem in your code is that setting the value of Visibility in the text block itself has higher priority than setting it in the style. So, even when the trigger occurs, the setting inside the trigger has no effect. Change the XAML to:
<TextBlock Margin="4" FontStyle="Italic" FontSize="12" Text="List is empty" >
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lstItems, Path=Items.Count}" Value="0">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Where the setting of Visibility is all in the style and it works (at least in my demo project).

WPF: How do I set the Foreground property of a TextBlock using DataTrigger

This is my XAML:
<TextBlock Name="SeverityText"
Grid.Column="1"
Grid.Row="0"
Foreground="Red">
<TextBlock.Triggers>
<DataTrigger Binding="{Binding Path=Severity}">
<DataTrigger.Value>
<sm:Severity>Warning</sm:Severity>
</DataTrigger.Value>
<Setter TargetName="SeverityText"
Property="Foreground"
Value="Yellow" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Severity}">
<DataTrigger.Value>
<sm:Severity>Information</sm:Severity>
</DataTrigger.Value>
<Setter TargetName="SeverityText"
Property="Foreground"
Value="White" />
</DataTrigger>
</TextBlock.Triggers>
<TextBlock>Severity:</TextBlock>
<TextBlock Text="{Binding Path=Severity}" />
</TextBlock>
This is my error message:
Cannot find the static member 'ForegroundProperty' on the type 'ContentPresenter'.
sm:Severity is an enumeration I imported.
Your triggers and setters need to be defined in a style, rather than on the TextBlock directly:
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Severity}">
<DataTrigger.Value>
<sm:Severity>Warning</sm:Severity>
</DataTrigger.Value>
<Setter TargetName="SeverityText"
Property="Foreground"
Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Writing the full path of the property also works:
So
Property="Foreground" -> Property="TextBlock.Foreground"
However as suggested in the previous answer, you get:
System.InvalidOperationException: Triggers collection members must be of type EventTrigger.
...if you don't put it in a style.

Can't update textbox property using DataBinding

I have a custom window which have two depencency properties: Boolean? ValidationStatus, and string ValidationMessage. Binding these properties works fine but trigger doesn't seem to be triggered when these values change. What am I doing wrong?
<TextBlock x:Name="validationTextBox"
Grid.Row="1"
Grid.ColumnSpan="2"
Text="{Binding ElementName=_this, Path=ValidationMessage}"
TextAlignment="Center"
Background="Green">
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Value="False" Binding="{Binding ElementName=_this, Path=ValidationStatus}">
<Setter Property="Panel.Background" Value="Red"/>
<Setter Property="TextBox.Text" Value="Outer checkbox is not checked"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Style Setters do not override local attribute settings. Therefore the data trigger's values are being ignored because you have specified the Text and Background properties on the TextBlock. To fix the problem set the default values of these properties in the style as shown in the following code:
<TextBlock x:Name="validationTextBox"
Grid.Row="1"
Grid.ColumnSpan="2"
TextAlignment="Center">
<TextBlock.Style>
<Style>
<Setter Property="TextBox.Text" Value="{Binding ElementName=_this, Path=ValidationMessage}"/>
<Setter Property="TextBox.Background" Value="Green"/>
<Style.Triggers>
<DataTrigger Value="False" Binding="{Binding ElementName=_this, Path=ValidationStatus}">
<Setter Property="TextBox.Background" Value="Red"/>
<Setter Property="TextBox.Text" Value="Outer checkbox is not checked"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>

How can I "Click Through" a control in WPF?

I have an order entry form that has a ListBox with a list of line items. I have my items template, and one of the values is a ComboBox in each of my Items.
Now, my form can also create Credit memo's in addition to purchase orders, but when I am creating a credit memo, I want to put the words "Credit Memo" over the list box, however, the TextBlock covers the ComboBox in two of my line items. I would like to pass my click event through the TextBlock to the ComboBoxes but I'm not sure how to do it.
This is what I have, ( Maybe I am coming at this totally wrong, I am kinda a noob with WPF )
<ListBox SelectionMode="Single" Grid.Row="2"
ItemsSource="{Binding Path=LineItems}" HorizontalContentAlignment="Stretch"
IsSynchronizedWithCurrentItem="True" Background="#66FFFFFF">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="WhiteSmoke"/>
<Setter Property="BorderThickness" Value="1" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsPartBackOrder}" Value="True">
<Setter Property="Background" Value="Orange" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type Entities:SalesOrderLineItem}" >
<OrderEntry:SalesOrderLineItemCreate DataContext="{Binding}" DeleteSalesOrderLineItem="DeleteSalesOrderLineItem" Margin="0,3,3,0" >
<OrderEntry:SalesOrderLineItemCreate.Resources>
<Style TargetType="{x:Type OrderEntry:SalesOrderLineItemCreate}">
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource=
{
RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}
},
Path=IsSelected
}" Value="True">
<Setter Property="Background" Value="LightBlue" />
<Setter Property="Foreground" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</OrderEntry:SalesOrderLineItemCreate.Resources>
</OrderEntry:SalesOrderLineItemCreate>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Grid.Row="2"
Text="Credit Memo"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="48" Height="Auto"
FontStyle="Italic"
Foreground="Red"
Opacity=".25">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=OrderType}" Value="CR">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=OrderType}" Value="CU">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock IsHitTestVisible="False" .../>

Resources