2011-04-21 71 views
33

我不是这个很有希望,但有什么办法复式风格在XAML结合起来,使具有所有所需设置一个新的风格?XAML组合样式

例如(伪码);

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

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

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

我知道,有一个“支持算法FMP”属性的风格,但该功能只需要你这么远。我真的只是寻找一种简单的方法(在XAML中)来创建这些“组合”风格。但就像我之前说过的,我怀疑它是否存在,除非有人听说过这样的事情?

+1

不存在,这无疑已经问为好,现在不能,但... – 2011-04-21 13:55:34

+1

@HB找到它。是的,我看起来很努力,但也找不到它。 – 2011-04-21 14:35:54

+0

如果我的回答解决了这个问题(没有任何活动,因为我的贴吧),请接受它让其他人来这里有方向。 – 2011-04-24 13:29:26

回答

46

您可以创建一个标记扩展,将合并的风格属性,并触发到一个单一的风格。

通过谷歌搜索结果来看,最流行的是从这个博客:http://bea.stollnitz.com/blog/?p=384

这将允许您合并使用CSS的语法风格。

例如

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

你也可以定义新的样式,被合并的风格。

你的榜样将通过去解决:

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

所有你需要做的就是添加这个类做你的命名空间,你就大功告成了:

[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]; 
    } 
} 

如果您使用上面的代码,这些代码是从原来的博客上稍微修改而来的,您可以另外使用当前的默认样式进行类型合并,使用“。”。语法:

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

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

+0

booya!正是我在找的东西。 – 2011-09-22 12:40:08

+4

我已经成功地用它来组合2种风格;然而,我遇到了一个小麻烦。 VS 2010 WPF设计器在这种方法中存在问题。我可以将这些样式结合起来,并像这里详细描述的那样使用MultiStyle,并且毫无问题地构建/运行代码。但WPF设计师抱怨在DataTemplate中使用这种方法。有没有人遇到/解决过这个问题? – 2012-12-04 16:00:26

+2

@JoeK我有完全相同的问题,并在这里发布了一个关于它的问题:http://stackoverflow.com/questions/8731547/markup-extension-staticresourceextension-requires-ixamlschemacontextprovider。到目前为止,我唯一的解决方案是在设计模式下禁用扩展,这是不理想的。 – Alain 2012-12-04 16:14:26