我有以下样式
:
<Style x:Key="ButtonBase" TargetType="Button">
<Setter Property="Background" Value="#FF007BFF"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value=">
<Setter Property="Background" Value="Yellow" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
<Trigger Property="IsPressed" Value="False">
<Setter Property="Background" Value="#FF007BFF" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Setter.Value>
</Setter>
</Style>
和一个继承的样式
:
<Style x:Key="ElementButton" TargetType="Button" BasedOn="{StaticResource ButtonBase}">
<Setter Property="Margin" Value="10"/>
<Setter Property="Height" Value="200"/>
</Style>
我想做的是能够在基本样式中设置任意变量:
<Setter Variable="HoverColor" Value="Pink"/>
然后我就可以这样使用我的触发器了:
<Trigger Property="IsPressed" Value=">
<Setter Property="Background" Value="{TemplateBinding HoverColor}" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
最后,我可以用继承的样式覆盖它:
<Style x:Key="ElementButton" TargetType="Button" BasedOn="{StaticResource ButtonBase}">
<Setter Property="Margin" Value="10"/>
<Setter Property="Height" Value="200"/>
<Setter Variable="HoverColor" Value="Red"/>
</Style>
有办法实现吗?我已经看过静态资源,但这些不能被覆盖。另外,我不能使用任何需要代码隐藏的东西,因为我没有!
最佳答案
这是个好问题,我也遇到过这类问题。可能有某种仅 XAML 的方法可行,但我觉得如果有的话,它会让人觉得很笨拙。我有几个关于如何实现您想要的建议。
首先,快速观察。您说您“没有代码隐藏”并且您的 View 是“仅 XAML”。好吧,我从来没有见过至少没有任何代码隐藏文件的用户控件 View ,所以我假设你的意思是你只是不想将任何代码放在那里(除了强制性的 InitializeComponent()
)。话虽如此,我将概述的方法不需要代码隐藏文件中的代码。
归根结底,听起来您真正想要的是定义一些自定义“变量”。这些建议正是这样做的,尽管可能不是您最初设想的那样。
可以解决您的问题的第一种方法是子类化您对样式感兴趣的控件,并向其添加任何自定义依赖属性。例如,您可以子类化 Button
,比如 ButtonWithMyVariables
。其中一个自定义依赖属性将称为“HoverColor”,类型为 Color
,或者更恰本地说,类型为 Brush
的“HoverBrush”(如果您只想将其直接应用于背景或前景属性)。然后你的基础 Style 可以将 HoverColor 设置为任何它想要的,你的继承 Style 可以覆盖它,或者你可以直接在你的 XAML 中的元素上覆盖它。我没有为这种方法提供代码示例(现在,除非有要求),因为这是一种更常用的方法,我猜你已经熟悉了。
第二种方法 是定义一个自定义附加属性。我还没有看到这种方法被广泛用于严格处理样式问题,也许是因为在这种情况下,为了使附加的“行为”完全发挥作用,作者使用样式文件来使用react(绑定(bind)到)并应用基于视觉的更改在附加属性上,而不是附加属性中的代码改变了回调,在风格上做了一些事情(但我想它仍然可以那样做)。但是,这种方法对许多人来说感觉“重量更轻”,因为您不需要对任何现有控件进行子类化。
可以在 MahApps.Metro 库中找到第二种方法的示例,特别是 TextboxHelper class (其中包含附加属性)和 Controls.TextBox.xaml style file (绑定(bind)到那些附加的属性)。例如,我们在 TextBox 的控件模板中看到,这一行使用了 Watermark 附加属性:
<TextBlock x:Name="Message"
Text="{TemplateBinding Controls:TextboxHelper.Watermark}" Visibility="Collapsed"
Foreground="{TemplateBinding Foreground}" IsHitTestVisible="False" Opacity="0.6" HorizontalAlignment="Left" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="6,0,0,0"/>
现在您可以想象您可以将基本样式中的 Watermark 值设置为:
<Setter Property="Controls:TextboxHelper.Watermark"
Value="My helpful watermark for all!"/>
然后以继承的样式覆盖它:
<Setter Property="Controls:TextboxHelper.Watermark"
Value="A more specific watermark!"/>
无论使用哪种方法,我们都可以定义任何我们想要的“变量”,并轻松地在 Style setter 中设置它们,在继承的样式中覆盖它们,在控件模板中 TemplateBind
到它们,或者 Trigger
关闭它们。
关于c# - XAML 样式的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14725843/