My requirement is to change foreground color to white if the background color of the Grid cell is Red.
I am using below template for the cell. But, its not triggering.
<DataTemplate x:Key="NumericThreeDecimalCellTemplate">
<TextBlock HorizontalAlignment="Right"
VerticalAlignment="Center">
<TextBlock.Text>
<Binding Path="Value"
StringFormat="###,###,###,###,###,###,##0.000;(###,###,###,###,###,###,##0.000)" />
</TextBlock.Text>
<TextBlock.Foreground>
<Binding Path="Value"
Converter="{StaticResource negativeToBrushConvertor}" />
</TextBlock.Foreground>
</TextBlock>
<DataTemplate.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Background.Color,RelativeSource={RelativeSource Mode=Self}}" Value="#FF0000">
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataTemplate.Resources>
</DataTemplate>`
Let me know if am doing anything wrong.
A local value, such as the returned by your negativeToBrushConverter, takes precedence over a value set by a style setter: https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-value-precedence
So no matter what you set the Foreground property to in your Style, it won't be applied unless you remove this part:
<TextBlock.Foreground>
<Binding Path="Value" Converter="{StaticResource negativeToBrushConvertor}" />
</TextBlock.Foreground>
You should set the default value for the Foreground property in the Style. And you should set the AncestorType of the {RelativeSource} to whatever the property of your cell is:
<DataTemplate>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Center">
<TextBlock.Text>
<Binding Path="Value" StringFormat="###,###,###,###,###,###,##0.000;(###,###,###,###,###,###,##0.000)" />
</TextBlock.Text>
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground">
<Setter.Value>
<Binding Path="Value" Converter="{StaticResource negativeToBrushConvertor}" />
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Background.Color,RelativeSource={RelativeSource AncestorType=dxg:GridCellContentPresenter}}" Value="#FF0000">
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
Related
I have following ControlTemplate which works fine
<ControlTemplate x:Key="TotalCostsStatisticTemplate">
<StackPanel x:Name="ContentHolderPanel" Visibility="Collapsed"
Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock x:Name="ValueTextBlock" VerticalAlignment="Center"
Style="{DynamicResource PhasingValueTextStyle}">
<TextBlock.Text>
<MultiBinding Converter="{ttConverters:CustomDisplayFormatConverter}">
<Binding Path="FormatSettings" />
<Binding Path="AvailableStatistics.CostsFormat"/>
<Binding Path="TotalCosts" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ShowTotalCosts}" Value="True">
<Setter TargetName="ContentHolderPanel" Property="Visibility" Value="Visible"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
But if I add another DataTrigger then the MultiBinding on TextBlock.Text doesn't work when control using this template is loaded for first time i.e. the converter CustomDisplayFormatConverter fires only once with all values as UnsetValue and doesn't fire again (it works fine on reloading the window again).
<ControlTemplate x:Key="TotalCostsStatisticTemplate">
<StackPanel x:Name="ContentHolderPanel" Visibility="Collapsed"
Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock x:Name="ValueTextBlock" VerticalAlignment="Center"
Style="{DynamicResource PhasingValueTextStyle}">
<TextBlock.Text>
<MultiBinding Converter="{ttConverters:CustomDisplayFormatConverter1}">
<Binding Path="FormatSettings" />
<Binding Path="AvailableStatistics.CostsFormat"/>
<Binding Path="TotalCosts" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ShowTotalCosts}" Value="True">
<Setter TargetName="ContentHolderPanel" Property="Visibility" Value="Visible"/>
</DataTrigger>
<!--Trigger causing problem (breaking TextBlock.Text multi binding on first load) -->
<DataTrigger Binding="{Binding IsCostsComplete}" Value="False">
<Setter TargetName="ValueTextBlock" Property="Foreground"
Value="{DynamicResource ManagerErrorBrush}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
If I place this DataTrigger inside TextBlock.Style it works fine!
Any idea what's wrong?
Update:
Here's how its getting used
<ControlTemplate x:Key="PhasingStatisticValuesTemplate">
<StackPanel x:Name="ContentHolderPanel" Orientation="Horizontal" Visibility="{Binding IsValid, Converter={StaticResource boolToVisibilityConverter}}">
<!-- Other control elements based on various templates -->
<Control Margin="20,10" Template="{DynamicResource TotalCostsStatisticTemplate}"/>
</StackPanel>
</ControlTemplate>
This PhasingStatisticValuesTemplate is used in another ControlTemplate, which is then used inside a DataTemplate, so there is a long hierarchy of ControlTemplates -
<ControlTemplate x:Key="PhasingStatisticsTemplate">
<Grid>
<ScrollViewer Style="{DynamicResource CompactHorizontalScrollViewerStyle}" Name="ScrollContainer">
<Grid Name="ScrollViewerGrid" Background="Transparent">
<ContentControl Template="{DynamicResource PhasingStatisticValuesTemplate}" Name="ScrollViewerContent" />
</Grid>
</ScrollViewer>
</Grid>
</ControlTemplate>
Another useful info. might be that existing style on that TextBlock also updated Foreground, not sure how that can cause this behavior -
<Style x:Key="PhasingValueTextStyle" TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsComplete}" Value="False">
<Setter Property="Foreground" Value="{DynamicResource ManagerErrorBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
I am trying to change the foreground (text) color of one of the items in a ListBox based on an index value. For example, if the index was 1, then the item at index 1 would have a different text color than all the other items. The index isn't the list selection index but my own value.
I searched around on Google and found some ideas to use AlternationIndex but I can't get it to work that. The converter is either receiving 0 (zero) or DependencyProperty#Unset for the AlternationIndex binding.
Here is my code:
<ListBox x:Name="videoList" SelectionMode="Single" AlternationCount="{Binding Mode=OneWay, Path=Items.Count}" Grid.Column="1" SelectionChanged="videoList_SelectionChanged">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Mode="OneWay" Converter="{StaticResource EqualityConverter}">
<MultiBinding.Bindings>
<Binding ElementName="videoWindow" Mode="OneWay" Path="VideoIndex" />
<Binding RelativeSource="{RelativeSource AncestorType=ListBoxItem}" Path="(ItemsControl.AlternationIndex)" />
</MultiBinding.Bindings>
</MultiBinding>
</DataTrigger.Binding>
<DataTrigger.Setters>
<Setter Property="Foreground" Value="Blue" />
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
For the RelativeSource I've tried: Self, TemplatedParent and AncestorType=ListBoxItem.
I also tried lots of different combinations with the Path value.
I can't get it to work. Any suggestions?
Solution: With the help from Clemens, turns out it was because the binding for the ListBox AlternationCount was incorrect. Oops!
<ListBox x:Name="videoList"
SelectionMode="Single"
AlternationCount="{Binding RelativeSource={RelativeSource Self}, Mode=OneWay, Path=Items.Count}"
Grid.Column="1"
SelectionChanged="videoList_SelectionChanged">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Mode="OneWay" Converter="{StaticResource EqualityConverter}">
<MultiBinding.Bindings>
<Binding ElementName="videoWindow" Mode="OneWay" Path="VideoIndex" />
<Binding RelativeSource="{RelativeSource Self}" Path="(ItemsControl.AlternationIndex)" />
</MultiBinding.Bindings>
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Foreground" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
It works with RelativeSource Self and a large enough AlternationCount, e.g. int.MaxValue.
<ListBox AlternationCount="2147483647" ...>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource EqualityConverter}">
<MultiBinding.Bindings>
<Binding ElementName="videoWindow"
Path="VideoIndex"/>
<Binding RelativeSource="{RelativeSource Self}"
Path="(ItemsControl.AlternationIndex)"/>
</MultiBinding.Bindings>
</MultiBinding>
</DataTrigger.Binding>
<DataTrigger.Setters>
<Setter Property="Foreground" Value="Blue"/>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
The alternate row style is defined as:
<Style TargetType="telerik:GridViewRow">
<Setter Property="Background" Value="{Binding Color,Converter={StaticResource dataToColorConverter}}">
</Style>
But I want to update the rowstyle depedninng on multiple values. I want to achieve something like this.
<Style>
<Setter Property="Background" >
<MultiBinding Converter={StaticResource dataToColorConverter}>
<Binding Path="Color"/>
<Binding ElementName="myListBox" Path="SelectedItem"/>
</MultiBinding>
</Setter>
</Style>
But getting the error "The type 'Setter' does not support direct content."
Because the Setter element doesn't support direct content, you must specify that you are setting the Value property (include "<Setter.Value>" in your XAML):
<Setter Property="Background" >
<Setter.Value>
<MultiBinding Converter="{StaticResource dataToColorConverter}" >
<Binding Path="Color" />
<Binding ElementName="myListBox" Path="SelectedItem" />
</MultiBinding>
</Setter.Value>
</Setter>
I would like to combine the DisplayNames from two different ViewModels, but only IF the first is not equal to a NullObject.
I could easily do this in either a converter or a parent view model, but am
This displays nothing at all:
<TextBlock Grid.Column="2" Grid.Row="0" >
<TextBlock.Inlines>
<Run Text="{Binding HonorificVm.DisplayName}"/>
<Run Text="{Binding PersonNameVm.DisplayName}"/>
</TextBlock.Inlines>
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding HonorificVm.Honorific}" Value="{x:Static model:Honorific.NullHonorific}">
<Setter Property="Text" Value="PersonNameVm.DisplayName"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Why?
I would split it into two TextBlocks and only change the visibility using a trigger. By using the Inlines and trying to change the Text in the triggers you probably run into precedence problems and the Inlines cannot be extracted to a Setter.
e.g.
<StackPanel Grid.Column="2" Grid.Row="0" Orientation="Horizontal">
<TextBlock Text="{Binding HonorificVm.DisplayName}" Margin="0,0,5,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding HonorificVm.Honorific}"
Value="{x:Static model:Honorific.NullHonorific}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Text="{Binding PersonNameVm.DisplayName}" />
</StackPanel>
An alternative would be a MultiBinding instead of Inlines:
<TextBlock Grid.Column="2" Grid.Row="0">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Text">
<Setter.Value>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="HonorificVm.DisplayName" />
<Binding Path="PersonNameVm.DisplayName" />
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding HonorificVm.Honorific}"
Value="{x:Static model:Honorific.NullHonorific}">
<Setter Property="Text" Value="{Binding PersonNameVm.DisplayName}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
I have the following TextBlock Style:
<Style TargetType="TextBlock" x:Key="MyValues">
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="Foreground" Value="DarkBlue"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMetric}" Value="True">
<Setter Property="Text">
<Setter.Value>
<MultiBinding StringFormat="F1">
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMetric}" Value="False">
<Setter Property="Text">
<Setter.Value>
<MultiBinding StringFormat="F3">
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
</Style.Triggers>
I then use TextBlocks as follows:
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=Breadth}" Style="{StaticResource MyValues}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=Depth}" Style="{StaticResource MyValues}"/>
<TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding Path=Area}" Style="{StaticResource MyValues}" />
The intention is to set the StringFormat depending on a bound property IsMetric. The Binding in the style are left empty because i want to apply the same style for multiple TextBlocks all bound to different properties. The triggers are working but the StringFormat` is ignored, any ideas?
Here you set Text property to be different things in TextBlock declaration and in DataTriggers. In the first case it's an instance of Binding class. In the second case it's an instance of MultiBinding class. Finally it is one of these. It cannot be both at the moment.
The following markup
<Setter Property="Text">
<Setter.Value>
<MultiBinding StringFormat="F1">
</MultiBinding>
</Setter.Value>
</Setter>
instantiates MultiBinding class instance and sets it to Text property.
The Text="{Binding Path=Breadth}" instantiates Binding class instance and sets it to Text property.