样式中的代码可重用性

Code reusability in Styles

我有一个样式元素,其中有少量修改,大部分是重复的。我如何让它更通用 - 所以 setter 属性是根据值设置的,而不是重复代码两次

<ResourceDictionary>
<Style x:Key="TextBlockStyleEnvironment" TargetType="{x:Type TextBlock}">
    <Setter Property="Margin" Value="5,4,0,0" />
    <Setter Property="FontSize" Value="8" />
    <Setter Property="HorizontalAlignment" Value="Stretch" />
    <Setter Property="VerticalAlignment" Value="Stretch" />
    <Setter Property="FontWeight" Value="Bold" />
</Style>
<Style x:Key="TextBlockStyleLocation" TargetType="{x:Type TextBlock}">
    <Setter Property="Margin" Value="5,4,0,0" />
    <Setter Property="FontSize" Value="10" />
    <Setter Property="HorizontalAlignment" Value="Stretch" />
    <Setter Property="VerticalAlignment" Value="Stretch" />
    <Setter Property="FontWeight" Value="Bold" />
</Style>
</ResourceDictionary>

正如您从代码中看到的,所有 setter 属性都相同,除了 Margin 和 FontSize。还附上了它在渲染时的截图。

请注意 - 希望将此自身包含在一个样式中,而不是在使用时在 XAML 中的本地级别声明。

Env 的可能值可以是 Dev、QA、Prod,location 的可能值可以是 TK、LN

使用 XAML 片段如下:

<Grid DataContext="{....}">
   <StackPanel>
     <TextBlock Text="{Binding Environment}" Style="{StaticResource TextBlockStyleEnvironment}"/>
     <TextBlock Text="{Binding Location}" Style="{StaticResource TextBlockStyleLocation}"/>

您可以使用样式继承:

<ResourceDictionary>
  <Style x:Key="BaseTextBlockStyle" TargetType="{x:Type TextBlock}">
      <Setter Property="Margin" Value="5,4,0,0" />
      <Setter Property="FontSize" Value="8" />
      <Setter Property="HorizontalAlignment" Value="Stretch" />
      <Setter Property="VerticalAlignment" Value="Stretch" />
      <Setter Property="FontWeight" Value="Bold" />
  </Style>

  <Style x:Key="TextBlockStyleEnvironment" BasedOn="{StaticResource BaseTextBlockStyle}" TargetType="{x:Type TextBlock}" />

  <Style x:Key="TextBlockStyleLocation" BasedOn="{StaticResource BaseTextBlockStyle}" TargetType="{x:Type TextBlock}">
      <Setter Property="FontSize" Value="10" />
  </Style>
</ResourceDictionary>

此外,您还可以创建附加属性并绑定到控件模板中的那些属性。这使您可以灵活地创建数百种样式,而不必仅仅因为某些细节需要不同。

一个很好的例子就是带有图像的按钮。当鼠标悬停在图像上时,图像需要改变。通常,您必须为实现该行为的每个按钮创建一个新控件 template/style。但是,如果您创建两个附加属性 - NormalStateImageSource 和 MosueOverImageSource,您可以绑定到控件模板中的属性。这使您可以为按钮拥有一个完整的样式,然后为其他按钮声明单独的样式,这些样式仅更改这些附加属性的值。

WPF 世界中的技术很少。

首先,如果样式是同一类型,可以使用BasedOn属性:

<Style x:Key="GenericTextBlockStyle" TargetType="{x:Type TextBlock}">
    <Setter Property="Margin" Value="5,4,0,0" />
    <Setter Property="FontSize" Value="8" />
</Style>

<Style x:Key="TextBlockStyleEnvironment" 
        BasedOn="{StaticResource GenericTextBlockStyle}"
        TargetType="{x:Type TextBlock}">

</Style>

但是 BasedOn 属性有时会变得非常混乱。也可以这样做,这将适用于不同类型的元素:

<Thickness x:Key="LeftBorderMargin" Top="10" />

<Style x:Key="TextBlockStyleEnvironment" TargetType="{x:Type TextBlock}">
    <Setter Property="Margin" Value="{StaticResource LeftBorderMargin}" />
</Style>

通常的做法是重构 Style 元素中的所有颜色/边距,以实现可重用性。