I have a datagrid bound to a list of a custom “model” class.
In one of the cell I have 4 rectangles, representing 4 different string properties of my model class.
The rectangles are supposed to be black if the corresponding property is empty, red otherwise.
I achieve this using a DataTrigger on each rectangle and it works fine but i have to write four time the same datatrigger with only the bound path changing. It seems like it could be more efficient.
Is there a clever way to define a DataTrigger once, and use a different bound path for each element (in my case rectangles) it is applied to ?
Thanks.
This is my model class:
class myModel
{
[...]
public string pr1 { get; set; }
public string pr2 { get; set; }
public string pr3 { get; set; }
public string pr4 { get; set; }
[...]
}
This is the datagrid bound to a List<myModel> :
<DataGrid AutoGenerateColumns="False" Height="200" Name="myDg" ItemsSource="{Binding}">
<DataGrid.Columns>
[...]
<DataGridTemplateColumn Header="prs">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Name="spRow" Orientation="Horizontal">
<Rectangle Height="15" Name="rPr1" Width="10">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Rectangle.Stroke" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=pr1}" Value="">
<Setter Property="Rectangle.Stroke" Value="Black"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
<Rectangle Height="15" Name="rPr2" Width="10">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Rectangle.Stroke" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=pr2}" Value="">
<Setter Property="Rectangle.Stroke" Value="Black"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
<Rectangle Height="15" Name="rPr3" Width="10">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Rectangle.Stroke" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=pr3}" Value="">
<Setter Property="Rectangle.Stroke" Value="Black"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
<Rectangle Height="15" Name="rPr4" Width="10">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Rectangle.Stroke" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=pr4}" Value="">
<Setter Property="Rectangle.Stroke" Value="Black"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
There are two ways…
Solution 1:
You can generalize the style at the ancestor level and then specialize the model properties in each rectangle.
The way you can do this is by biding specific
prproperty toTagof each Rectangle and then useTagas a generic data trigger source.So in above example when you clear the individual textbox you get a corresponding red rectangle. Notice that we have used Tag through a
DataTriggerbut we can also use a normal Trigger…Solution 2:
Use
ItemsControland then 4 (orn) items in your model to hold pr1..pr4 values.EDIT
….
Change you model to include a list of
probjects. I am usingSourceFilterclass just to hold the two way editable string value that was held bypr'n'properties… You can use any class that holds a string value through a property.Then I load the four properties as four
SourceFilterobjects…And then I use ItemsControl’s
ItemPanel,ItemsTemplate,ItemsSourceto achieve exactly same effect from Step 1…Advantage is here you do not have to specify specific pr1..pr4 bindings anywhere. Plus its extensible (as
prcan hold anynvalues and will generate same number of rectangles automatically).