绑定到不同属性的数据触发器的分解代码
本文关键字:数据 触发器 分解 代码 属性 绑定 | 更新日期: 2023-09-27 18:09:02
我有一个绑定到自定义"model"类列表的数据网格。在其中一个单元格中,我有4个矩形,代表我的模型类的4个不同的字符串属性。
如果对应属性为空,则矩形应为黑色,否则为红色。我使用每个矩形上的DataTrigger实现了这一点,它工作得很好,但我必须编写四次相同的DataTrigger,只有绑定路径改变。这似乎可以更有效率。
是否有一种聪明的方法来定义一次datattrigger,并为它应用的每个元素(在我的例子中是矩形)使用不同的绑定路径?
谢谢。这是我的模型类:
class myModel
{
[...]
public string pr1 { get; set; }
public string pr2 { get; set; }
public string pr3 { get; set; }
public string pr4 { get; set; }
[...]
}
这是绑定到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>
有两种方法…
解决方案1:
您可以在祖先级别泛化样式,然后专门化每个矩形中的模型属性。
您可以做到这一点的方式是通过将特定的pr
属性绑定到每个矩形的Tag
,然后使用Tag
作为通用的数据触发器源。
<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>
所以在上面的例子中,当你清除单个文本框时,你会得到一个相应的红色矩形。注意,我们已经通过DataTrigger
使用了Tag,但我们也可以使用普通的Trigger…
<Trigger Property="Tag" Value="">
<Setter Property="Fill" Value="Red"/>
</Trigger>
解决方案2:
在你的模型中使用ItemsControl
和4(或n
)项来保持pr1..pr4值。
编辑
…
更改您的模型以包含pr
对象的列表。我使用SourceFilter
类只是为了保持由pr'n'
属性持有的双向可编辑字符串值…可以使用任何通过属性保存字符串值的类。
public List<SourceFilter> pr
{
get;
set;
}
然后我将四个属性加载为四个SourceFilter
对象…
pr = new List<SourceFilter>();
pr.Add(new SourceFilter("pr1"));
pr.Add(new SourceFilter("pr2"));
pr.Add(new SourceFilter("pr3"));
pr.Add(new SourceFilter("pr4"));
然后我使用ItemsControl的ItemPanel
, ItemsTemplate
, ItemsSource
来实现与步骤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>
优点是这里你不需要指定特定的pr1..Pr4绑定在任何地方。加上它的可扩展(因为pr
可以保存任何n
值,并将自动生成相同数量的矩形)。
是的,您可以创建一个从DataTrigger
派生的类,并预先设置不变的详细信息:
public class RedBlackDataTrigger : DataTrigger
{
public RedBlackDataTrigger()
{
Value = string.Empty;
Setters.Add(new Setter(Rectangle.StrokeProperty, new SolidColorBrush(Colors.Black)));
}
}
你可以在XAML中使用它,只需添加绑定:
<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>
既然你也复制了你的Style
,你可以更进一步,创建一个派生的样式类:
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) });
}
}
}
现在你已经把事情简化为:
<Rectangle Height="15" Width="10">
<Rectangle.Style>
<Your-Namespace:RectangleStyle ColorTrigger="pr4" />
</Rectangle.Style>
</Rectangle>
您甚至可以更进一步,创建一个派生的Rectangle
类来完成这一切。