XAML风格的变量

时间:2013-02-06 09:42:20

标签: c# wpf xaml

我有以下Style

<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

<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>

有没有办法实现这个目标?我已经查看了静态资源,但这些资源无法覆盖。另外,我不能使用任何需要代码隐藏的东西,因为我没有代码!

1 个答案:

答案 0 :(得分:2)

这是一个很好的问题,我也经历过这样的事情。可能有某种XAML方法可以工作,但我有一种感觉,如果有的话,它会觉得非常笨拙。我有几个关于如何实现你想要的建议。

首先,快速观察。你说你“没有代码隐藏”,你的观点是“仅限XAML”。好吧,我从未见过至少没有任何代码隐藏文件的UserControl视图,所以我假设你的意思是你只是不想要在那里放置任何代码(强制性InitializeComponent()除外)。话虽如此,我将概述的方法不需要代码隐藏文件中的代码。

在一天结束时,听起来你真正想要的是定义一些自定义的“变量”。这些建议就是这样做的,尽管可能不是你最初想象的那样。

解决问题的第一种方法对您感兴趣的控件进行样式化,并为其添加任何自定义依赖项属性。例如,您可以将Button子类化为ButtonWithMyVariables之类的内容。其中一个自定义依赖项属性称为“HoverColor”,类型为Color,或者更合适的是“HoverBrush”类型为Brush(如果您只想将其直接应用于后台)或前景属性)。然后你的基本样式可以将HoverColor设置为它想要的任何东西,你继承的样式可以覆盖它,或者你可以直接在XAML中的元素上覆盖它。我没有为这种方法提供代码示例(现在,除非请求),因为这是一种更常用的方法,我猜你已经熟悉了。

第二种方法将定义自定义附加属性。我没有看到这种方法用于严格处理样式问题,也许是因为在这种情况下附加的“行为”完全发挥作用,作者使用Style文件作出反应(绑定)并应用基于视觉的变化在附加属性上,而不是附加属性中的代码更改回调做一些风格(但我想它仍然可以这样做)。但是,这种方法对许多人来说感觉“重量轻”,因为您不需要对任何现有控件进行子类化。

第二种方法的一个例子可以在MahApps.Metro库中找到,特别是TextboxHelper class(包含附加属性)和Controls.TextBox.xaml style file(绑定到那些附加属性)。例如,我们在控件模板中看到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 off它们。