您可以创建自定义的标记扩展,将样式属性和触发器合并为一个单独的样式。您只需要向您的命名空间添加一个MarkupExtension
-派生类,并定义MarkupExtensionReturnType
属性,然后就可以开始运行了。
这是一个扩展,它将允许您使用“类似于css”的语法合并样式。
MultiStyleExtension.cs
[MarkupExtensionReturnType(typeof(Style))]
public class MultiStyleExtension : MarkupExtension
{
private string[] resourceKeys;
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.");
}
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
{
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);
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”,在内置的BasedOn
属性(用于样式继承)中定义了一个名为“Combined”的新样式。按照惯例,我们可以选择向新的“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
的原始想法,并对其进行了修改,以支持“
.
”符号用于引用当前样式。