Is it possible to "select" a different control template based on a property of a viewmodel?
I have the following user control template:
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<RadioButton
GroupName="DisplayButtons"
Content="{TemplateBinding Content}"/>
</ControlTemplate>
</UserControl.Template>
Based on a boolean in the viewmodel, I want to use either a RadioButton or a Button.
How can I achieve that?
You could use a Style with a DataTrigger that sets the Template property:
<UserControl>
<UserControl.Style>
<Style TargetType="UserControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="UserControl">
<Button Content="Button" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ViewModelProperty}" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="UserControl">
<RadioButton Content="RadioButton" />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
</UserControl>
It is possible to use different views for each case but this method is more useful in the case of complicated templates.
For the current case, the easiest way is to use Triggers:
Method 1
<UserControl x:Class="Myusercontrolnamespace.Views.Myusercontrol"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" "
mc:Ignorable = "d" Height="auto" Width="auto" >
<UserControl.Resources>
<DataTemplate x:Key="RadioButtontTemplate">
<RadioButton/>
</DataTemplate>
<DataTemplate x:Key="ButtonTemplate">
<Button/>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentControl Content="{Binding }">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource RadioButtontTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsRadioButton}" Value="False">
<Setter Property="ContentTemplate" Value="{StaticResource ButtonTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
</UserControl>
Method 2
<UserControl x:Class="Myusercontrolnamespace.Views.Myusercontrol"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" "
mc:Ignorable = "d" Height="auto" Width="auto" >
<UserControl.Resources>
<DataTemplate x:Key="RadioButtontTemplate">
<RadioButton/>
</DataTemplate>
<DataTemplate x:Key="ButtonTemplate">
<Button/>
</DataTemplate>
</UserControl.Resources>
<Grid>
<DataTemplate x:Key="globalControlTemplate">
<ContentControl Content="{Binding }">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource RadioButtontTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ConsumerType}" Value="Business">
<Setter Property="ContentTemplate" Value="{StaticResource ButtonTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
<ContentControl Content="{Binding globalControlTemplate}" />
</Grid>
</UserControl>
Cordially
Related
I have a ListView Control in WPF which displays a list of boxes from which the user can select one from the collection. What I'm currently trying to accomplish is to have Selected Item's Background Property changed to a different color for a proper identification.
I found a Code Snippet which partially solves my problem, however, the Background value of the SelectedItem reverts back to its original when I press anywhere within the module.
What I'd like to happen is for the Background value to persist for the SelectedItem regardless if I press on other controls or even if the Window gets unfocused.
Below is my XAML Code Snippet with the Setters and Triggers I currently have in place.
<ListView Grid.Row="2"
ItemsSource="{Binding FakeDispatchBoxCollection}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<md:Card Margin="0,0,0,10"
Cursor="Hand">
<md:Card.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}" Value="true">
<Setter Property="md:Card.Background" Value="LightGray" />
</DataTrigger>
</Style.Triggers>
</Style>
</md:Card.Style>
<Grid Margin="5">
<!--#region Row & Column Definitions -->
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.60*" />
<ColumnDefinition Width="0.40*" />
</Grid.ColumnDefinitions>
<!--#endregion-->
<Label Grid.Row="0" Grid.Column="0"
Content="{Binding DispatchBoxName}"
FontWeight="ExtraBlack"
FontSize="15"
FontFamily="Baloo Bhai 2" />
<Label Grid.Row="1" Grid.Column="0"
Content="{Binding DispatchBoxType}"
FontWeight="SemiBold"
FontSize="13"
FontFamily="Baloo Bhai 2" />
<Label Grid.Row="0" Grid.Column="1"
Grid.RowSpan="2"
Content="{Binding UnitCount}"
VerticalAlignment="Center"
HorizontalAlignment="Right"
FontWeight="ExtraBlack"
FontSize="20"
FontFamily="Baloo Bhai 2" />
</Grid>
</md:Card>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In the Item's Data Template (ItemTemplate property), you don't have any items that can accept keyboard focus. There are only Labels.
And in the ListViewItem Template Trigger (ItemContainerStyle property), you set the IsSelected property dependency on the keyboard focus inside the ListViewItem.
Also, you shouldn't use a ListView if you don't specify columns. In this case it is better to use ListBox.
An example of a correct implementation:
<Window.Resources>
<!--To simplify the example.-->
<CompositeCollection x:Key="source">
<sys:String>First</sys:String>
<sys:String>Second</sys:String>
<sys:String>Third</sys:String>
<sys:String>Fourth</sys:String>
</CompositeCollection>
</Window.Resources>
<ListBox ItemsSource="{DynamicResource source}">
<ItemsControl.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label x:Name="label" Content="{Binding}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Value="true">
<Setter TargetName="label" Property="Background" Value="Coral" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
A UserControl has a button with Style="{StaticResource MenuIconByttonStyle}" defined in App.xaml, but using this UserControl in a window xaml gives error :
'MenuButton' TargetType does not match type of element 'Button'
Not sure what MenuButton refers to, as I can't find that defined anywhere.
If I use StaticResource MenuIconButtonStyle2, or FlatToolbarButton, I don't get this error.
Why may this be?
App.xaml :
<Application.Resources>
<Style x:Key="FlatToolbarButton" TargetType="Button">
<Setter Property="Width" Value="16"/>
<Setter Property="Height" Value="16"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="{x:Null}"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
</Style>
<Style x:Key="MenuIconButtonStyle" TargetType="Button" BasedOn="{StaticResource FlatToolbarButton}" >
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="#333333">
<Border CornerRadius="0" BorderThickness="0" BorderBrush="#333333">
<Image Source="{StaticResource MenuIcon}" Stretch="UniformToFill"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="Aqua">
<Border CornerRadius="0" BorderThickness="1" BorderBrush="Aqua">
<Image Source="{StaticResource MenuIcon}" Stretch="UniformToFill"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="MenuIconButtonStyle2" TargetType="Button" BasedOn="{StaticResource FlatToolbarButton}" >
<Setter Property="Background" Value="{StaticResource MenuIconBrush}"/>
</Style>
TradeListUC.xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="18"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Background="#333333" >
<Label x:Name="TitleLabel" FontSize="12" Content="Trade List" Height="16" Width="100"
VerticalAlignment="Top" Padding="4,0,0,0" Foreground="White" />
<StackPanel DockPanel.Dock="Right" HorizontalAlignment="Right" Orientation="Horizontal" >
<TextBox x:Name="SymbolEntryTb" Width="100" Margin="0,0,1,0"
Background="#999999" BorderBrush="#AAAAAA"
HorizontalAlignment="Right" Padding="0,-1,0,0" />
<Button x:Name="MenuBtn" Style="{StaticResource MenuIconButtonStyle}">
</Button>
</StackPanel>
</DockPanel>
MainWindow.xaml :
<TabItem Header="Trades">
<Grid>
<UC:TradeListUC/>
</Grid>
</TabItem>
ItemsSource of ListView shows loaded item but items are not visible in the screen.
<UserControl x:Class="...Controls.ControlToolbar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TuningInterfaceModel.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<local:StringFormatToImageSourceConverter x:Key="StringToImage" />
</UserControl.Resources>
<Grid>
<ListView ScrollViewer.VerticalScrollBarVisibility="Disabled" x:Name="tStack">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<Image Source="{Binding Path=Key, Converter={StaticResource StringToImage}
, ConverterParameter=../Images/ControlIcons/{0}.ico}" />
<TextBlock Text="{Binding Key}" FontSize="10px" Width="60px" Margin="2,0,0,0" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter Property="Cursor" Value="/Images/Cursor/grab.cur"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True" />
<Condition Property="local:MouseExtensions.IsMouseLeftButtonDown" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Cursor" Value="/Images/Cursor/Handover.cur" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</UserControl>
Your <Style TargetType="{x:Type ListViewItem}"> is at fault. It is setting Template as a ControlTemplate that only contains triggers without any content.
If my crystal balls don't fail me, you may want to remove the control template and use Style.Triggers instead.
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter Property="Cursor" Value="/Images/Cursor/grab.cur"/>
</Trigger>
</Style.Triggers>
<!-- More triggers -->
</Style>
I am trying to implement alternating background Color on my Rows.
I have an ItemsControl with an ItemTemplate in which I use Triggers on the Style Property of the Border.
But I end up with all RoyalBlue Rows instead of alternating with Red.
Can somene assist? Thank you very much!
<Page.Resources>
<DataTemplate x:Key="myTemplate" >
<Grid>
<Border BorderThickness="1" CornerRadius="2" Margin="2" VerticalAlignment="Stretch" Height="20" Width="Auto">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="Red" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="RoyalBlue" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="{Binding Name}"/>
</Grid >
</Border>
</Grid>
</DataTemplate>
</Page.Resources>
<ScrollViewer >
<StackPanel >
<ItemsControl ItemsSource="{Binding Path=myElements}" ItemTemplate="{StaticResource myTemplate}" AlternationCount="2"/>
</StackPanel>
</ScrollViewer>
ItemsControl.AlternationIndex will be set against direct child of ItemsControl panel (ContentPresenter) so you need to use DataTrigger with RelativeSource binding and because it's an attached property you need to put in brackets like Path=(ItemsControl.AlternationIndex)
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="1">
<Setter Property="Background" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="0">
<Setter Property="Background" Value="RoyalBlue" />
</DataTrigger>
</Style.Triggers>
</Style>
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 pr property to Tag of each Rectangle and then use Tag as a generic data trigger source.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBox Margin="5" x:Name="MyTextBox1" Text="pr1" />
<TextBox Margin="5" x:Name="MyTextBox2" Text="pr2" />
<TextBox Margin="5" x:Name="MyTextBox3" Text="pr3" />
<TextBox Margin="5" x:Name="MyTextBox4" Text="pr4" />
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="20"/>
<Setter Property="Stroke" Value="Black"/>
<Setter Property="StrokeThickness" Value="1"/>
<Setter Property="Margin" Value="5"/>
<Style.Triggers>
<DataTrigger
Binding="{Binding Tag,
RelativeSource={RelativeSource Self}}"
Value="">
<Setter Property="Fill" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<Rectangle Tag="{Binding Text, ElementName=MyTextBox1, Mode=OneWay}" />
<Rectangle Tag="{Binding Text, ElementName=MyTextBox2, Mode=OneWay}" />
<Rectangle Tag="{Binding Text, ElementName=MyTextBox3, Mode=OneWay}" />
<Rectangle Tag="{Binding Text, ElementName=MyTextBox4, Mode=OneWay}" />
</StackPanel>
</Grid>
So in above example when you clear the individual textbox you get a corresponding red rectangle. Notice that we have used Tag through a DataTrigger but we can also use a normal Trigger...
<Trigger Property="Tag" Value="">
<Setter Property="Fill" Value="Red"/>
</Trigger>
Solution 2:
Use ItemsControl and then 4 (or n) items in your model to hold pr1..pr4 values.
EDIT
....
Change you model to include a list of pr objects. I am using SourceFilter class just to hold the two way editable string value that was held by pr'n' properties... You can use any class that holds a string value through a property.
public List<SourceFilter> pr
{
get;
set;
}
Then I load the four properties as four SourceFilter objects...
pr = new List<SourceFilter>();
pr.Add(new SourceFilter("pr1"));
pr.Add(new SourceFilter("pr2"));
pr.Add(new SourceFilter("pr3"));
pr.Add(new SourceFilter("pr4"));
And then I use ItemsControl's ItemPanel, ItemsTemplate, ItemsSource to achieve exactly same effect from Step 1...
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ItemsControl Grid.Row="0" ItemsSource="{Binding pr, ElementName=MyWindow2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Margin="5"
Text="{Binding Path=Source,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Grid.Row="1" ItemsSource="{Binding pr, ElementName=MyWindow2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="20"/>
<Setter Property="Stroke" Value="Black"/>
<Setter Property="StrokeThickness" Value="1"/>
<Setter Property="Margin" Value="5"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Source}" Value="">
<Setter Property="Fill" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataTemplate.Resources>
<Rectangle />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Advantage is here you do not have to specify specific pr1..pr4 bindings anywhere. Plus its extensible (as pr can hold any n values and will generate same number of rectangles automatically).
Yes, you can create a class that derives from DataTrigger and has the unchanging details pre-set:
public class RedBlackDataTrigger : DataTrigger
{
public RedBlackDataTrigger()
{
Value = string.Empty;
Setters.Add(new Setter(Rectangle.StrokeProperty, new SolidColorBrush(Colors.Black)));
}
}
You can use it in XAML and just add the binding:
<Rectangle Height="15" Width="10">
<Rectangle.Style>
<Style TargetType ="Rectangle">
<Setter Property="Rectangle.Stroke" Value="Red"/>
<Style.Triggers>
<Your-Namespace:RedBlackDataTrigger Binding="{Binding Path=pr4}" />
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
Since you are also duplicating your Style, you can take it a step further and create a derived style class:
public class RectangleStyle : Style
{
public RectangleStyle()
{
TargetType = typeof (Rectangle);
Setters.Add(new Setter(Rectangle.StrokeProperty, new SolidColorBrush(Colors.Red)));
}
public string ColorTrigger
{
set
{
Triggers.Add(new RedBlackDataTrigger {Binding = new Binding(value) });
}
}
}
Now you've reduced things to:
<Rectangle Height="15" Width="10">
<Rectangle.Style>
<Your-Namespace:RectangleStyle ColorTrigger="pr4" />
</Rectangle.Style>
</Rectangle>
You can even take it one step further and create a derived Rectangle class to do it all.