2011-04-21 108 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