WPF Datagrid Button Datatrigger - wpf

Working on a WPF Datagrid.
The datagrid has a bound source with a column "DateInSource."
The value in the column "DateInSource" can either be NULL or a date.
If the value is null I want the button RED and the words on the button should be the "Receive Work."
IF the value is not null I want the button GREEN and the words on the button should be the value of DateInSource.
I have created a style resource:
<Style TargetType="{x:Type Button}" x:Key="ButtonFormatStyle" >
<Setter Property="Background" Value="Green"/>
<Setter Property="Content" Value="{Binding}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding DateInSource}" Value="X:null" >
<Setter Property="Background" Value="Red" />
<Setter Property="Content" Value="Receive Work" />
</DataTrigger>
</Style.Triggers>
</Style>
I have created a button:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="BtnDateInSource" Click="ReceiveWork" Content="{Binding DateInSource}" Style="{StaticResource ButtonFormatStyle}"></Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
It does not appear that my data trigger is working. Suggestions?

Value="X:null" is not valid null-check. it is comparison with "X:null" string.
change it like Value="{x:Null}"

Related

WPF DataGrid AlternatingRowBackground overriding the Style DataTrigger for background

I have a DataGrid where I show many lines of data. To help visually differentiate the rows I've added a background colour to alternating rows.
But, there are some rows that contains very interesting data that I want to attract the user's attention to, and so I use a Style DataTrigger to highlight those specific rows.
My problem is that the alternating background colour takes precedence - only the odd rows (no background colour) show the highlight.
Note, this is a data-bound DataGrid using the MVVM pattern (no "code-behind").
The (very cutdown) code is as follows:
<DataGrid ItemsSource="{Binding FilteredTraceMessages, Mode=OneWay}"
AlternatingRowBackground="AliceBlue"
.......>
<DataGrid.Columns>
....
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Severity}" Value="Error">
<Setter Property="Background" Value="LightSalmon"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Severity}" Value="Warning">
<Setter Property="Background" Value="LemonChiffon"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
You have to set the Backround on the same precedence level. See Dependency Property Setting Precedence List
Delete AlternatingRowBackground="AliceBlue" from the DataGrid and put AlternationCount="2" there. Then add at the first place a trigger for AlternationIndex.
<DataGrid ItemsSource="{Binding FilteredTraceMessages, Mode=OneWay}" AlternationCount="2"
.......>
<DataGrid.Columns>
....
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="AlternationIndex" Value="1">
<Setter Property="Background" Value="AliceBlue"/>
</Trigger>
<DataTrigger Binding="{Binding Severity}" Value="Error">
<Setter Property="Background" Value="LightSalmon"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Severity}" Value="Warning">
<Setter Property="Background" Value="LemonChiffon"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>

binding a checkbox value with a textblock text on xaml

I want to bind a checkbox values ischecked=true or ischecked=false with a textblock text "Activé" or "Désactivé" only on Xaml and without using a code behind is that possible?
Check out datatriggers.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.datatrigger?view=netframework-4.7.2
https://www.wpf-tutorial.com/styles/trigger-datatrigger-event-trigger/
And here is an example that should work for you.
<CheckBox Name="MyCheckBox" Content="IsActive"/>
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="Activé"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyCheckBox, Path=IsChecked}" Value="False">
<Setter Property="Text" Value="Désactivé"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>

Bind DataGridCell style directly to its contents

I have a StatusCell style for DataGridCell that I would like to use in several place in my application. I would like to externalize the Style tag so that I can reuse it easily without having to duplicate the code in my XAML everywhere.
Every other source I've found has required me to bind the trigger off the property from my ViewModel. But across the application, the column might be bound to MyStatusProperty or SubObject.MyStatusProperty, etc, so I want to do this to allow me to have one style that will apply to all of these without having to specify where it's binding from.
I am able to do this with a TextBlock with the following style. This lets me bind the TextBlock to whatever I want and the style binding doesn't matter where it's coming from.
<Style x:Key="StatusLabel" TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Text" Value="Completed">
<Setter Property="Foreground" Value="Green"/>
</Trigger>
</Style.Triggers>
</Style>
and when I create a textblock that I want to use this styling, all I have to do is
<TextBlock Style="{StaticResource StatusLabel}" Text="{Binding Whatever}" />
But with a DataGridCell it doesn't let me do this
<Style x:Key="StatusCell" TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="Content" Value="Completed">
<Setter Property="Background" Value="Green"/>
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
<DataGridTextColumn Header="Status" Binding="{Binding MyStatusProperty}"
CellStyle="{StaticResource StatusCell}" />
I also tried setting up the trigger like this:
<DataTrigger Binding="{Binding Content, RelativeSource={RelativeSource Self}}" Value="Reviewed">
<Setter Property="Background" Value="Green"/>
<Setter Property="Foreground" Value="White" />
</DataTrigger>
But neither of these work. I have also tried swapping out "Content" in the last example for "Binding" and "Text"
Is there another property I can bind to in the DataGridCell that will let bind the style trigger to the contents of the cell without knowing the binding path?
As usual, I found a workaround shortly after asking. Since it's working with TextBlocks, I just have to use TemplateColumns instead of TextColumns, although I'd still prefer to be able to use TextColumns since they'd use 6 less lines of XAML.
<DataGridTemplateColumn Header="Status">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding MyProperty}" Style="{StaticResource StatusCellTextBlock}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Using the style:
<Style x:Key="StatusCellTextBlock" TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Text" Value="Completed">
<Setter Property="Background" Value="Green"/>
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>

Using Picture or Icon instead of DataGridCheckBoxColumn in WPF

I want to change the CheckBox which is inside of a DataGridColumn into an image when it is checked and another when it is unchecked, How can i do ?
Ps: My DataGridCheckBoxColumn is defined like this:
<DataGridCheckBoxColumn Header="Priority" Binding="{Binding PRIORITY, Converter={StaticResource converter}}"/>
Converter is converting bytes to boolean.
Use the ElementStyle and EditingElementStyle properties to create and set a different Template for the CheckBox which fits that.
e.g.
<DataGridCheckBoxColumn Binding="{Binding IsActive}">
<DataGridCheckBoxColumn.ElementStyle>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Image MaxWidth="32" MaxHeight="32">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="Images/Error.ico" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=CheckBox}}" Value="True">
<Setter Property="Source" Value="Images/Default.ico" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>
This makes the column display an image based on IsChecked, the URIs are just hardcoded and the CheckBox is disabled because editing in the ElementStyle does not change any properties on the bound object. Its only purpose is to display the approriate image.
(The EditingElementStyle is not set here so if the user clicks the cell again to edit it a normal CheckBox appears which can be checked or unchecked.)

I can't set validation on WPF datagrid template column that contains datepicker and textblock

There is datagrid template column contains datepicker and textblock, the datepicker for editing and the textbox for showing.
I try to apply a style on this column to validate it, but it just be applied on the datepicker not the textblock:
<Style x:Key="DateEditStyle" TargetType="{x:Type my:DatePicker}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="Plase check the data in the cell"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="TextBlockEditStyle" TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="Plase check the data in the cell"/>
</Trigger>
</Style.Triggers>
</Style>
<my:DataGridTemplateColumn x:Name="SrvDateCol" Header="Date" Width="100">
<my:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<my:DatePicker SelectedDate="{Binding srvdate,StringFormat=d, ValidatesOnExceptions=True}"
SelectedDateChanged="DatePicker_SelectedDateChanged"
Style="{StaticResource DateEditStyle}"></my:DatePicker>
</DataTemplate>
</my:DataGridTemplateColumn.CellEditingTemplate>
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding srvdate,StringFormat=d,ValidatesOnExceptions=True}"/>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
When I enter error date in the cell, the style works good, but when I leave it the style disappeares, and the cell return back to its original state. So how to apply the style on the TextBlock also??
I hope my question is clear.

Resources