XAML 组合样式超越了BasedOn? [英] XAML Combine styles going beyond BasedOn?

查看:24
本文介绍了XAML 组合样式超越了BasedOn?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is there any way to combine mutliple styles in XAML to make a new style that has all of the desired settings?

例如(伪代码);

<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 中)来创建这些组合"样式.但就像我之前说的,我怀疑它是否存在,除非有人听说过这样的事情??

I know that there is a BasedOn property for styles, but that feature will only take you so far. I am really just looking for an easy way (in XAML) to create these 'combined' styles. But like I said before, I doubt it exists, unless anyone has heard of such a thing??

推荐答案

您可以制作自定义标记扩展,将样式属性和触发器合并为一个样式.您需要做的就是将 MarkupExtension 派生类添加到您的命名空间,并定义了 MarkupExtensionReturnType 属性,然后您就可以正常运行了.

You can make a custom markup extensions that will merge styles properties and triggers into a single style. All you need to do is add a MarkupExtension-derived class to your namespace with the MarkupExtensionReturnType attribute defined and you're off and running.

这是一个扩展程序,它允许您使用类似 css"的样式合并样式.语法.

Here is an extension that will allow you to merge styles using a "css-like" syntax.

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

我们定义了一个名为Combined"的新样式.通过合并另外两种风格A"和B"在内置的 BasedOn 属性中(用于样式继承).我们可以选择向新的组合"添加其他属性.一如既往的风格.

We have defined a new style named "Combined" by merging two other styles "A" and "B" within the built-in BasedOn attribute (used for style inheritance). We can optionally add other properties to the new "Combined" style as per usual.

其他示例:

这里,我们定义了 4 种按钮样式,并且可以以不同的组合使用它们,重复性极低:

Here, we define 4 button styles, and can use them in various combinations with little repetition:

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

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

You can even use the "." syntax to merge the "current" default style for a type (context-dependent) with some additional styles:

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

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

The above will merge the default style for TargetType="{x:Type Button}" with the two supplemental styles.

信用

我在 bea.stollnitz.com 并对其进行了修改以支持.";引用当前样式的符号.

I found the original idea for the MultiStyleExtension at bea.stollnitz.com and modified it to support the "." notation to reference the current style.

这篇关于XAML 组合样式超越了BasedOn?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆