如何参数化WPF样式?
我正在寻找一种最简单的方法来删除 WPF 代码中的重复项。
下面的代码是一个简单的交通灯,有 3 个灯 - 红色
、琥珀色
、绿色
。它绑定到一个 ViewModel,该 ViewModel 有一个枚举属性 State
,采用这 3 个值之一。
声明 3 个省略号的代码非常重复。现在我想添加动画,以便每个灯光淡入和淡出 - 样式会变得更大,重复会变得更糟。
是否可以使用 State
和 Color
参数对样式进行参数化,以便我可以在描述灯光行为的资源中使用单一样式,然后使用它 3 次 - 对于“红色” ”、“琥珀色”和“绿色”灯?
<UserControl.Resources>
<l:TrafficLightViewModel x:Key="ViewModel" />
</UserControl.Resources>
<StackPanel Orientation="Vertical" DataContext="{StaticResource ViewModel}">
<StackPanel.Resources>
<Style x:Key="singleLightStyle" TargetType="{x:Type Ellipse}">
<Setter Property="StrokeThickness" Value="2" />
<Setter Property="Stroke" Value="Black" />
<Setter Property="Height" Value="{Binding Width, RelativeSource={RelativeSource Self}}" />
<Setter Property="Width" Value="60" />
<Setter Property="Fill" Value="LightGray" />
</Style>
</StackPanel.Resources>
<Ellipse>
<Ellipse.Style>
<Style TargetType="{x:Type Ellipse}" BasedOn="{StaticResource singleLightStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="Red">
<Setter Property="Fill" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse>
<Ellipse.Style>
<Style TargetType="{x:Type Ellipse}" BasedOn="{StaticResource singleLightStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="Amber">
<Setter Property="Fill" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse>
<Ellipse.Style>
<Style TargetType="{x:Type Ellipse}" BasedOn="{StaticResource singleLightStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="Green">
<Setter Property="Fill" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</StackPanel>
I'm looking for a simplest way to remove duplication in my WPF code.
Code below is a simple traffic light with 3 lights - Red
, Amber
, Green
. It is bound to a ViewModel that has one enum property State
taking one of those 3 values.
Code declaring 3 ellipses is very duplicative. Now I want to add animation so that each light fades in and out - styles will become even bigger and duplication will worsen.
Is it possible to parametrize style with State
and Color
arguments so that I can have a single style in resources describing behavior of a light and then use it 3 times - for 'Red', 'Amber' and 'Green' lights?
<UserControl.Resources>
<l:TrafficLightViewModel x:Key="ViewModel" />
</UserControl.Resources>
<StackPanel Orientation="Vertical" DataContext="{StaticResource ViewModel}">
<StackPanel.Resources>
<Style x:Key="singleLightStyle" TargetType="{x:Type Ellipse}">
<Setter Property="StrokeThickness" Value="2" />
<Setter Property="Stroke" Value="Black" />
<Setter Property="Height" Value="{Binding Width, RelativeSource={RelativeSource Self}}" />
<Setter Property="Width" Value="60" />
<Setter Property="Fill" Value="LightGray" />
</Style>
</StackPanel.Resources>
<Ellipse>
<Ellipse.Style>
<Style TargetType="{x:Type Ellipse}" BasedOn="{StaticResource singleLightStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="Red">
<Setter Property="Fill" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse>
<Ellipse.Style>
<Style TargetType="{x:Type Ellipse}" BasedOn="{StaticResource singleLightStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="Amber">
<Setter Property="Fill" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse>
<Ellipse.Style>
<Style TargetType="{x:Type Ellipse}" BasedOn="{StaticResource singleLightStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="Green">
<Setter Property="Fill" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</StackPanel>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
只要您的“交通灯”包含在控件内(看起来确实如此),我认为这并不可怕。每个椭圆都有明确的定义并具有不同的触发器,每个触发器都指示其自己的状态。您已经将公共部分分解到基本样式中,这很好。
您可以将各个省略号包装在另一个具有
ActiveState
属性和ActiveFill
属性的用户控件(不需要支持 ViewModel)内。然后您的 TrafficLight 看起来像这样:这可以让您将所有 Ellipse 样式包装在 Indicator 控件内,并且该控件唯一需要担心的是将
State
与ActiveState
进行比较> 确定是否应使用ActiveFill
画笔填充自身。至于这是否值得付出努力,这取决于您周围有多少个这些,以及您是否在交通灯用户控制范围之外使用它们。记住:你不会需要它。
As long as your "Traffic Light" is wrapped up inside a control, which it appears it is, I don't think this is horrible. Each ellipse is well defined and has different triggers, each indicating its own state. You've already factored the common parts out into the base style, which is good.
You could wrap the individual ellipses inside another user control (which wouldn't need a backing ViewModel) that had an
ActiveState
property and anActiveFill
property. Then your TrafficLight looks something like:This lets you wrap up all your Ellipse styling inside your Indicator control and the only thing that control needs to worry about is comparing the
State
to theActiveState
to determine if it should fill itself with theActiveFill
brush.As to if this is worth the effort or not, that depends on how many of these you have floating around and if you use them outside of your Traffic Light user control. Remember: You Ain't Gonna Need It.