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

스타일에는 'BasedOn'속성이 있지만 그 기능은 지금까지만 사용할 수 있습니다. 나는이 '결합 된'스타일을 만드는 쉬운 방법 (XAML에서)을 찾고 있습니다. 그러나 내가 전에 말했던 것처럼, 누군가 그런 것들에 대해 들어 본 적이 없다면 그것이 존재하는지 의심 스럽습니까?

+1

존재하지 않으며, 이것은 물론 이전에 물어 보았지만 지금 당장은 찾을 수 없습니다 ... –

+1

@HB. 네, 정말 열심히 보였지만 찾아 낼 수 없었습니다. –

+0

내 대답이 그것을 풀어 낸 경우 (게시 한 이후로 아무런 활동이 없었다면) 여기에 오는 다른 사람들이 지시를 받도록 받아 들여주십시오. –

답변

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! 내가 뭘 찾고 있었는지. –

+4

2 개의 스타일을 결합하는 데 성공적으로 사용했습니다. 그러나, 나는 작은 장애에 직면했다. VS 2010 WPF Designer에는이 접근 방식에 문제가 있습니다. 스타일을 결합하고 여기서 설명한대로 MultiStyle을 정확히 사용할 수 있으며 문제없이 코드를 작성/실행할 수 있습니다. 그러나 WPF 디자이너는 DataTemplate 내부에서이 접근 방식을 사용하는 것에 대해 불평합니다. 누구든지이 문제를 겪었거나 해결 했습니까? –

+2

@JoeK 나는 똑같은 문제가 있었고 여기에 대한 질문을 게시했습니다 : http://stackoverflow.com/questions/8731547/markup-extension-staticresourceextension-requires-ixamlschemacontextprovider. 지금까지 내가 가진 유일한 해결책은 디자인 모드에서 확장 기능을 사용하지 않는 것입니다. – Alain