after having found much help on stackoverflow, I am now struggling with a problem I could not find an answer for yet. My goal is the following:
I have a datagrid in a wpf/c# application filled with figures. Dependending on whether the figure is positive or negative, I want to change the foreground font to green or red. The itemsource for the datagrid is a list of my own class which includes the following elements:
string description
a list of 12 doubles called totalMoney
I have manually configured the columns for the datagrid so that the first shows the description, then the value of totalMoney[0], then totalMoney[1] and so on. After some searching, I found a way to change the foreground colour of the individual cells based on the values here on stackoverflow via a datatrigger method plus IValueConverter with the following code:
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding totalMoney[2], Converter={StaticResource money}}" Value="1">
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding totalMoney[2], Converter={StaticResource money}}" Value="0">
<Setter Property="Foreground" Value="Black"/>
</DataTrigger>
<DataTrigger Binding="{Binding totalMoney[2], Converter={StaticResource money}}" Value="-1">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
However, as you see in the code, in WPF I have to reference the Binding to an individual item in my List (totalMoney[X]). I therefore have to manually set the style for each Column in my datagrid. As I want to use the style in several datagrids, this seems to me as highly unpractical.
My question is therefore - is it possible to define the style so that it changes depending on the value of a cell in general? Or is there maybe a completely different way to achieve my goal that I have overlooked?
Thank you for your help.
At first glance, you could use the following style for all totalMoney[] columns ...
<Style TargetType="{x:Type TextBlock}" x:Key="MoneyIndicatorStyle">
<Style.Triggers>
<DataTrigger
Binding="{Binding Text, RelativeSource={RelativeSource Self},
Converter={StaticResource money}}"
Value="1">
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
<DataTrigger
Binding="{Binding Text, RelativeSource={RelativeSource Self},
Converter={StaticResource money}}"
Value="0">
<Setter Property="Foreground" Value="Black"/>
</DataTrigger>
<DataTrigger
Binding="{Binding Text, RelativeSource={RelativeSource Self},
Converter={StaticResource money}}"
Value="-1">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
But here is a potential catch... if tommorrow you decide that the text of these textblocks is going to be a formatted currency like this... $(1,00) i.e. negative 100 dollars in accounting world, then the converter could have to cast this formatted string into a locale-neutral number i.e -100.00 and yield 0, 1 or -1 based on the current logic in converter.
Right now your converter is at ease because it receives a straightforward numeric value (totlaMoney[n]) from your model but using the above style it will rely on the Text displayed by the Textblock!
So the decision is yours.
Related
I currently have a DataGrid being styled by DataTriggers. I've run into the issue that a MultiDataTrigger will not style the row when one condition is present - a condition that works fine in a DataTrigger.
This Works:
<DataTrigger Binding="{Binding Type}" Value="Error">
<Setter Property="Background" Value="#FFFF88FF"/>
</DataTrigger>
This Works:
<DataTrigger Binding="{Binding BgColor}" Value="{x:Null}">
<Setter Property="Background" Value="#FFFF88FF"/>
</DataTrigger>
This does not work:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="Error"/>
<Condition Binding="{Binding BgColor}" Value="{x:Null}"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="#FFFF88FF"/>
</MultiDataTrigger>
What would influence the MultiDataTrigger to not work?
There are multiple instances where both conditions should be met.
Technically it should work ,you can cross verify by adding dummy converter to your XAML and bind the "Type" and "BgColor" to it then you can check exact value
I have a datagrid "Funds" bind to a listcollectionview.
I want to highlight specific rows in datagrid based on few rules. The fundGroupsList is the list of group names. The rule1 is to find the misalignment within members of a group.
One of the ways to do that is to create a boolean property (ex. IsRule1Failed) in Entries and save the fail result foreach row.
Then, in XAML use DataTriggers to change the background color.
<DataGrid.Resources>
<Style TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="BurlyWood" />
</Trigger>
<DataTrigger Binding="{Binding DataContext.IsRule1Failed}" Value="True">
<Setter Property="Background" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
You can also simply change the CSS Class of the row.
GridView.SelectedRowStyle.CssClass = "selectedrow";
I have a TextBlock and I want to set the property Visibility to Collapsed when the TextBlock has no text. I wonder me, for sure there should be a better way to check if the Lenght of the property Text is equal than 0.
<TextBlock Name="TextBlockHeader" Foreground="White" FontSize="18" FontWeight="Bold" Text="{Binding Header}" Margin="0,0,0,25">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=TextBlockHeader, Path=Text.Length}" Value="0">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Here I have to define a name for the TextBlock and I can reference it in the Datatrigger Binding="{Binding ElementName=TextBlockHeader, Path=Text.Length}"
But how can I achieve the same without having to define a name for the TextBlock?
You would usually use Triggers instead of DataTriggers, and compare the Text property to either null or an empty string.
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="Text" Value="">
<Setter Property="Visibility" Value="Collapsed"/>
</Trigger>
</Style.Triggers>
</Style>
As the TextBlock class seems to coerce the Text property value to be non-null, it may be sufficient to have only the second Trigger for an empty string.
I need to flip between two views dynamically based on a boolean flag in my ViewModel.
I thought it would be as simple as:
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Content" Value="{StaticResource View1}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsShowingView2}">
<Setter Property="Content" Value="{StaticResource View2}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
However, View2 never gets displayed, even if IsShowingView2 is always true.
Any ideas anyone? All the examples I can find seem to be altering the ContentTemplate instead, but I have no need to do that. I just want different content.
You're not actually setting a value for the DataTrigger
<DataTrigger Binding="{Binding IsShowingView2}" Value="True">
<Setter Property="Content" Value="{StaticResource View2}" />
</DataTrigger>
Also check for binding errors in the output window.
I am working on a c# WPF project which I am using a style trigger to style the background colour of the each row based on one of the cell values.
Below is my style trigger.
<Window.Resources>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Highest Alarm Level}" Value="Critical">
<Setter Property="Background" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding Highest Alarm Level}" Value="Medium">
<Setter Property="Background" Value="Orange" />
</DataTrigger>
<DataTrigger Binding="{Binding Highest Alarm Level}" Value="Warning">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
<DataTrigger Binding="{Binding Highest Alarm Level}" Value="Info">
<Setter Property="Background" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
What I need to be able to do, is under certain circumstances I don't want this style to be used, so what I am after, is if in the C# code a certain condition becomes to true, I want to disable all of the styling done above to not be used, i.e. all of the styling is turned off so the background colour of the rows are not set.
Add a Key to your custom DataGridRow Style
<Style TargetType="DataGridRow" x:Key="MyRowStyle">
<!-- Define Triggers -->
</Style>
Then you just need to switch between default and custom styles.
If you set Style with null, that means the default Style will be applied
dataGrid.RowStyle = _boolCondition ? this.FindResource("MyRowStyle") as Style : null;