gpt4 book ai didi

wpf - XAML 组合样式超越 BasedOn?

转载 作者:行者123 更新时间:2023-12-03 06:40:05 35 4
gpt4 key购买 nike

有没有办法在 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”的语法合并样式。

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>

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

其他示例:

这里,我们定义了 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}" 的默认样式与两个补充样式合并。

信用

我在 bea.stollnitz.com 找到了 MultiStyleExtension 的原始想法并将其修改为支持“.”表示法来引用当前样式。

关于wpf - XAML 组合样式超越 BasedOn?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5745001/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com