XAML 组合样式超越 BasedOn?

2024-04-06

有没有办法在 XAML 中组合多种样式来创建具有所有所需设置的新样式?

例如(伪代码);

<Style x:key="A">
 ...
</Style>

<Style x:key="B">
 ...
</Style>

<Style x:key="Combined">
 <IncludeStyle Name="A"/>
 <IncludeStyle Name="B"/>
 ... other properties.
</Style>

我知道有一个BasedOn样式属性,但该功能只能带您到目前为止。我实际上只是在寻找一种简单的方法(在 XAML 中)来创建这些“组合”样式。但就像我之前说的,我怀疑它是否存在,除非有人听说过这样的事情?


您可以创建自定义标记扩展,将样式属性和触发器合并为单个样式。您需要做的就是添加一个MarkupExtension-派生类到您的命名空间MarkupExtensionReturnType属性已定义,您就可以开始运行了。

这是一个扩展,允许您使用“类似 css”的语法合并样式。

多样式扩展.cs

[MarkupExtensionReturnType(typeof(Style))]
public class MultiStyleExtension : MarkupExtension
{
    private string[] resourceKeys;

    /// <summary>
    /// Public constructor.
    /// </summary>
    /// <param name="inputResourceKeys">The constructor input should be a string consisting of one or more style names separated by spaces.</param>
    public MultiStyleExtension(string inputResourceKeys)
    {
        if (inputResourceKeys == null)
            throw new ArgumentNullException("inputResourceKeys");
        this.resourceKeys = inputResourceKeys.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
        if (this.resourceKeys.Length == 0)
            throw new ArgumentException("No input resource keys specified.");
    }

    /// <summary>
    /// Returns a style that merges all styles with the keys specified in the constructor.
    /// </summary>
    /// <param name="serviceProvider">The service provider for this markup extension.</param>
    /// <returns>A style that merges all styles with the keys specified in the constructor.</returns>
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        Style resultStyle = new Style();
        foreach (string currentResourceKey in resourceKeys)
        {
            object key = currentResourceKey;
            if (currentResourceKey == ".")
            {
                IProvideValueTarget service = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
                key = service.TargetObject.GetType();
            }
            Style currentStyle = new StaticResourceExtension(key).ProvideValue(serviceProvider) as Style;
            if (currentStyle == null)
                throw new InvalidOperationException("Could not find style with resource key " + currentResourceKey + ".");
            resultStyle.Merge(currentStyle);
        }
        return resultStyle;
    }
}

public static class MultiStyleMethods
{
    /// <summary>
    /// Merges the two styles passed as parameters. The first style will be modified to include any 
    /// information present in the second. If there are collisions, the second style takes priority.
    /// </summary>
    /// <param name="style1">First style to merge, which will be modified to include information from the second one.</param>
    /// <param name="style2">Second style to merge.</param>
    public static void Merge(this Style style1, Style style2)
    {
        if(style1 == null)
            throw new ArgumentNullException("style1");
        if(style2 == null)
            throw new ArgumentNullException("style2");
        if(style1.TargetType.IsAssignableFrom(style2.TargetType))
            style1.TargetType = style2.TargetType;
        if(style2.BasedOn != null)
            Merge(style1, style2.BasedOn);
        foreach(SetterBase currentSetter in style2.Setters)
            style1.Setters.Add(currentSetter);
        foreach(TriggerBase currentTrigger in style2.Triggers)
            style1.Triggers.Add(currentTrigger);
        // This code is only needed when using DynamicResources.
        foreach(object key in style2.Resources.Keys)
            style1.Resources[key] = style2.Resources[key];
    }
}

然后,您的示例将通过以下方式解决:

<Style x:key="Combined" BasedOn="{local:MultiStyle A B}">
      ... other properties.
</Style>

我们通过在内置样式中合并其他两种样式“A”和“B”来定义一种名为“Combined”的新样式BasedOn属性(用于样式继承)。我们可以选择像往常一样将其他属性添加到新的“组合”样式中。

其他例子:

在这里,我们定义了 4 种按钮样式,并且可以以各种组合方式使用它们,而无需重复:

<Window.Resources>
    <Style TargetType="Button" x:Key="ButtonStyle">
        <Setter Property="Width" Value="120" />
        <Setter Property="Height" Value="25" />
        <Setter Property="FontSize" Value="12" />
    </Style>
    <Style TargetType="Button" x:Key="GreenButtonStyle">
        <Setter Property="Foreground" Value="Green" />
    </Style>
    <Style TargetType="Button" x:Key="RedButtonStyle">
        <Setter Property="Foreground" Value="Red" />
    </Style>
    <Style TargetType="Button" x:Key="BoldButtonStyle">
        <Setter Property="FontWeight" Value="Bold" />
    </Style>
</Window.Resources>

<Button Style="{local:MultiStyle ButtonStyle GreenButtonStyle}" Content="Green Button" />
<Button Style="{local:MultiStyle ButtonStyle RedButtonStyle}" Content="Red Button" />
<Button Style="{local:MultiStyle ButtonStyle GreenButtonStyle BoldButtonStyle}" Content="green, bold button" />
<Button Style="{local:MultiStyle ButtonStyle RedButtonStyle BoldButtonStyle}" Content="red, bold button" />

您甚至可以使用“." 语法将类型的“当前”默认样式(依赖于上下文)与一些附加样式合并:

<Button Style="{local:MultiStyle . GreenButtonStyle BoldButtonStyle}"/>

上面将合并默认样式TargetType="{x:Type Button}"与两个补充样式。

Credit

我找到了最初的想法MultiStyleExtension at bea.stollnitz.com https://web.archive.org/web/20120103082937/http://bea.stollnitz.com/blog/?p=384并修改它以支持“." 引用当前样式的符号。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

XAML 组合样式超越 BasedOn? 的相关文章

  • WPF 窗口关闭后不会释放内存

    我创建了一个测试代码 private void Application Startup 1 object sender StartupEventArgs e ShutdownMode System Windows ShutdownMode
  • WPF XAML 绑定和 CurrentCulture 显示

    当 CurrentCulture 更改时 我发现 XAML 文档出现一些无效行为 当我在窗口中有一些这样的元素时
  • MVVM 中动态创建 MenuItem-Separator 的 WPF 光学样式

    我有一个MenuItem从动态创建其子菜单项ItemsSource 财产 对于分组 我在菜单中有分隔符 分隔符是由 ItemsSource 集合中的 ControlTemplate 为每个空条目创建的MenuItem ItemContain
  • 如何从注册表获取安装的软件路径?

    我需要替换安装在任何驱动器 如 C D E 中的文件 我想从注册表中找到安装的文件路径并将该文件替换为其他文件 软件将安装在任何驱动器中 我想替换文件 我正在使用这段代码 如何使用注册表查找安装的文件路径并替换为 C 中的其他文件 stri
  • Caliburn micro 处于无应用程序对象模式,就像在 AutoCAD dll 插件中一样

    我正在使用 Caliburn Micro 开发 WPF 应用程序 该应用程序的一些视图需要加载到 AutoCAD 环境中 AutoCAD 编程环境允许开发 AutoCAD 插件 dll 类型 并将其加载到 AutoCAD 环境中 由于 Au
  • WPF ComboBox 中具有本地化名称的枚举

    我有一个列出枚举的组合框 enum StatusEnum Open 1 Closed 2 InProgress 3
  • WPF MVVM 在窗口关闭时调用 ViewModel Save 方法

    我已经弄清楚如何从我的 ViewModel 关闭窗口 现在我需要从另一侧解决窗口关闭问题 当用户单击窗口的关闭按钮时 我需要在 ViewModel 中触发 Save 方法 我正在考虑将 Command 属性绑定到 Window 的关闭事件
  • 如何制作wpf倒计时器?

    我想创建 wpf 倒数计时器 将结果显示为hh mm ss进入文本框 我将感谢任何人的帮助 您可以使用DispatcherTimer class msdn http msdn microsoft com en US library syst
  • 我可以将一个 WPF 窗口叠加在另一个窗口之上吗?

    我有一个 WPF 窗口 其中包含一个WindowsFormsHost元素 我需要在这个元素之上绘制东西 但是它的本质WindowsFormsHost意味着它始终位于绘图堆的顶部 因为我无法在同一 WPF 窗口中绘制WindowsFormsH
  • OxyPlot 中日期时间轴上的不规则间隔

    我有一个 WPF 应用程序 其中使用 OxyPlot 来绘制图表 我不断地将点添加到图表中的线系列中 X 轴是日期时间轴 其间隔类型设置为秒 点不断添加到线系列中 当第一个点和最后一个点之间的时间跨度是特定的秒数时 我删除第一个点并使绘图无
  • 如何在 MVVM 中使用应用程序命令

    我想使用 ApplicationCommands Cut 复制 粘贴 保存 它们看起来很有趣 因为命令路由 键绑定以及某些控件使用它们的事实 我了解如何绑定到虚拟机上的中继 委托命令 但我似乎无法理解应用程序命令 我找到了一些旧的答案 但没
  • 当绑定值为 null 时出现 WPF 日期选择器验证错误

    我有一个 WPF 应用程序 其中使用绑定到实体框架 带有 SQL Server 实体的日期字段的日期选择器 我将其绑定如下
  • 值转换器是否在 WPF 中按绑定实例化?

    是否为使用特定值转换器类的每个绑定实例化一个单独的 WPF 值转换器对象 我正在尝试创建一个双向位到布尔值转换器 我希望能够绑定一个bool财产 如IsChecked 到值类型中的一个位 例如ushort 我正在使用转换器parameter
  • 将 System.Drawing.Image 转换为 System.Windows.Media.ImageSource 但没有结果

    我想在我的 WPF 应用程序中将 Image 转换为 ImageSource 我使用正常工作的 Code128 库 已在 WinForms 应用程序中检查 下面的函数返回具有适当大小的 ImageSource 但没有任何内容可见 priva
  • 如何从 WPF 窗口显示 Winforms 对话框?

    这个问题的反面已经被回答过很多次了 public static void SetOwner object activeWindow object dialog if IsWindow dialog IsWindow activeWindow
  • Xamarin - 在 xmlns clr 命名空间中找不到类型

    我正在制作一个 Xamarin Forms 应用程序 解决方案称为RESTTest 我的共享项目名为RestApp 在我的共享项目中 我有一个名为ViewModels 其中包含一个名为MainViewModel cs 我有一个名为MainP
  • WPF中ViewModel是否应该继承DependencyObject?

    我尝试创建一个简单的UserControl在 WPF 中使用 MVVM 现在我需要为UserControl 所以我尝试在中创建依赖属性UserControlViewModel 我不想处于代码隐藏状态 为了创建依赖属性UserControlV
  • ComboBox.ItemTemplate 未正确显示选择

    在问题中c wpf 无法同时设置 DisplayMemberPath 和 ItemTemplate https stackoverflow com questions 18273415 c sharp wpf cannot set both
  • 如何创建自动滚动文本框

    我有一个 WPF 应用程序 其中包含一个多行文本框 用于显示调试文本输出 如何设置文本框 以便将文本附加到框中时 它会自动滚动到文本框的底部 我正在使用 MVVM 模式 理想情况下 纯 XAML 方法会很好 TextBox 本身不一定是焦点
  • wpf 的 prism 与 mvvm light

    我们正在启动一个带有 MVVM 的 WPF 项目 并且必须决定使用 PRISM 还是 MVVM Light 我对这两个框架都是新手 我已经阅读了一些帖子 但仍然有一些问题 有人可以阐明以下几个方面吗 两个框架 性能 无论出于何种原因 其中一

随机推荐