c# - XAML 样式的变量

标签 c# wpf xaml

我有以下样式:

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

相关文章:

c# - C# 中的捕获设备列表(例如麦克风、立体声混音...)

c# - 使用 BindableObject 实现 IValueConverter 并且绑定(bind)的 Property 始终为默认值

c# - listview刷新时焦点不是 "holding"

c# - 如何以编程方式从 View 模型中选择 ListView 项?

c# - 如何从 Xaml 中的 Style 中提取 Setter 值属性?

c# - 我可以在单击按钮时淡入淡出每个文本 block 吗?

c# - 为什么在构造函数之前调用类的成员方法

c# - IoC 容器不适用于 WebForms

c# - 判断某月第一天、最后一天等的函数。

c# - “does not contain a static '主要' method”错误