문제

에 WPF,어떻게 적용하 여러 스타일 FrameworkElement?예를 들면,나는 통제는 이미 스타일입니다.도 별도의 스타일에 추가하고 싶다하지 않고 그것을 거리에 있습니다.스타일이 다른 TargetTypes,그러니까 연장 한다.

도움이 되었습니까?

해결책

나는 생각 간단한 대답할 수 있는지(적어도 이전 버전의 WPF)당신이 무엇을하려고 노력하고 있습니다.

즉,어떤 특별한 요소 중 하나는 스타일을 적용할 수 있습니다.

그러나,다른 사람이 위에 언급된 어쩌면 당신은 사용할 수 있습니다 BasedOn 이 당신을 도울 수 있습니다.다음의 조각 xaml.에서 그것은 당신이 볼 수 있는 기본 스타일을 설정 시설에 존재하는 기본 클래스의 요소에 적용하고 싶 두 가지 스타일이다.그리고,두 번째 스타일을 기반으로 기본 스타일,설정이 다른을 제공합니다.

그래서 아이디어는 여기...입할 수 있다면 어떻게든 별도의 속성을 설정하려면 원하는...에 따라 상속의 계층 구조 요소를 설정하려면 다양한 스타일에...이 있을 수 있습 해결 방법입니다.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <Style x:Key="baseStyle" TargetType="FrameworkElement">
            <Setter Property="HorizontalAlignment" Value="Left"/>
        </Style>
        <Style TargetType="Button" BasedOn="{StaticResource baseStyle}">
            <Setter Property="Content" Value="Hello World"/>
        </Style>
    </Page.Resources>
    <Grid>
        <Button Width="200" Height="50"/>
    </Grid>
</Page>


이게 도움이 되었으면 좋겠습니다.

참고:

특히 한 가지를 참고.을 변경하는 경우 TargetType 에서 두 번째 스타일(에서는 먼저의 설정 xaml 위) ButtonBase, 고,두 가지 스타일하지 않을 얻을 적용됩니다.그러나,다음을 확인 xaml 얻으려면 아래 주위에는 제한이 있습니다.기본적으로,그 뜻을 제공하는 데 필요한 스타일에는 키에 참조로는 키입니다.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <Style x:Key="baseStyle" TargetType="FrameworkElement">
            <Setter Property="HorizontalAlignment" Value="Left"/>
        </Style>
        <Style x:Key="derivedStyle" TargetType="ButtonBase" BasedOn="{StaticResource baseStyle}">
            <Setter Property="Content" Value="Hello World"/>
        </Style>
    </Page.Resources>
    <Grid>
        <Button Width="200" Height="50" Style="{StaticResource derivedStyle}"/>
    </Grid>
</Page>

다른 팁

Bea Stollnitz 했 좋은 블로그에 포스트 를 사용에 대한 마크업 확장을 위해 이 헤더에서"어떻게 설정할 수 있습니 여러 스타일에 WPF?"

는 블로그는 죽은 지금,그래서 내가 여기 게시물 재생


WPF 및 Silverlight 모두 할 수있는 기능을 제공합을 도출하는 스타일에서 또 다른 스타일을 통해"에 따라"을 제공합니다.이 기능을 통해 개발자들을 정리하는 스타일을 사용하여 계층과 유사한 클래스를 상속입니다.다음 스타일

<Style TargetType="Button" x:Key="BaseButtonStyle">
    <Setter Property="Margin" Value="10" />
</Style>
<Style TargetType="Button" x:Key="RedButtonStyle" BasedOn="{StaticResource BaseButtonStyle}">
    <Setter Property="Foreground" Value="Red" />
</Style>

이 구문을 사용하는 버튼을 RedButtonStyle 있을 것이다 그것의 전경 시설에 빨간색과 여유산 10 으로 설정되어 있습니다.

이 기능은 주변에서 WPF 오랜 시간,그리고 새로운 Silverlight3.

무엇을 설정하려는 경우에는 하나 이상의 스타일에를 받으려면 어떻게 해야 합니까?도 WPF 도 Silverlight 에 대한 솔루션을 제공이 문제입니다.다행히 방법이 있 이 동작을 구현하기 위해서 WPF 는 내용에 대해서는 이 블로그 글을 참조하십시오.

WPF 및 Silverlight 태그를 사용 확장자를 제공하는 속성을 가진 값을 필요로 하는 몇 가지 논리를 얻을 수 있습니다.태그 확장 쉽게 알아볼 수 있의 존재에 의해 중괄호 주변에서 그들을 XAML.예를 들어,Binding}태그 확장직을 포함하고 가져 오기 값을 데이터 소스 및 업데이트 사항이 변경되었을 때;the{StaticResource}태그 확장직을 포함하고 잡아서 값을 리소스 사전에 기반한 핵심입니다.다행히도 우리를 위해,WPF 사용자가 자신을 작성하는 사용자 정의 마크업 확장을 확장합니다.이 기능은 아직 존재하지 않습니다 Silverlight,그래서 해결책이 블로그에서만 적용 가능한 WPF.

다른 사람 가 작성한 솔루션을 병합하는 두 가지 스타일 마크업을 사용한 확장자.그러나 내가 원하는 솔루션을 제공합 병합하는 기능을 무제한 스타일에 조금 더 까다롭습니다.

쓰 태그를 확장하는 것은 간단합니다.첫 번째 단계는 클래스를 만드는 MarkupExtension 에서 파생되고 사용 MarkupExtensionReturnType 특성을 나타내고자 하는 반환하는 값에서 당신의 마크업 확장을 형식의 스타일입니다.

[MarkupExtensionReturnType(typeof(Style))]
public class MultiStyleExtension : MarkupExtension
{
}

지정을 입력하 태그 확장

우리에게 주고 싶고,사용자의 우리의 마크업 확장 간단한 방법으로 지정한 스타일을 병합됩니다.기본적으로 두 가지 방법으로는 사용자를 지정할 수 있습한 입력을 마크업 확장.사용자 속성을 설정할 수 있습니다 또는 통과 매개 변수를 생성자입니다.기 때문에서 이 시나리오 사용자 요구를 지정하는 기능을 무제한 스타일을 나의 첫번째 방식을 만들었다는 생성자의 번호를 사용하여 문자열"params"키워드:

public MultiStyleExtension(params string[] inputResourceKeys)
{
}

나의 목표를 작성할 수 있는 입력 다음과 같다:

<Button Style="{local:MultiStyle BigButtonStyle, GreenButtonStyle}" … />

주의 쉼표로 분리하여 다른 스타일 키를 사용합니다.불행하게도,사용자 정의 마크업 확장을 지원하지 않는 무제한 숫자의 생성자 매개변수,그래서 이 방법을 컴파일 오류가 있습니다.면 나는 사전에 얼마나 많은 스타일이고 싶었을 병합,나는 사용할 수 있는 동 XAML 구문으로 생성자를 복용의 원하는 번호로 문자열:

public MultiStyleExtension(string inputResourceKey1, string inputResourceKey2)
{
}

문제 해결 방법으로,가 결정 생성자를 매개 변수 하나의 문자열을 지정하는 스타일의 이름을 공백으로 구분됩니다.구문을 너무 나쁘지 않:

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.");
    }
}

을 계산하는 출력의 확장자 태그

을 계산하는 출력의 마크업 확장을,우리를 재정의하는 방법에서 MarkupExtension"라고 providevalue 의".반환되는 값에서 이 방법을 설정할 대상에 태그의 확장입니다.

시작했을 작성하여 확장을 위한 방법는 방법을 알고 있는 스타일을 병합하는 두 스타일입니다.에 대한 코드를 이 방법은 매우 간단하다:

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

논리와 함께 위의 첫 번째 스타일의 수정을 포함하는 모든 정보에서 두 번째입니다.충돌이 있는 경우(예:모두는 스타일이 세터 같은 시설),두 번째 스타일의 승리합니다.통지하는 이외에도 스타일을 복사 및 트리거 또한 계정으로 된 targettype 과에 따라 값을 뿐만 아니라 모든 자원이 두 번째 스타일을 할 수 있습니다.대 된 targettype 의 병합된 스타일 내가 사용 유형에 관계없이 더 많은 파생됩니다.두 번째 스타일에 따라 스타일에,내가 병합의 계층 구조의 스타일을 재귀적으로.이 있는 경우,자원 내가 그들을 복사상 첫 번째 스타일입니다.는 경우 이러한 자원을 사용하여 참조{StaticResource},그들은 정적으로 해결되기 전에 이 병합 코드를 실행하고,따라서 그것은 필요가 없다 그들을 이동합니다.추가 이 코드는 경우에는 우리가 사용하는 DynamicResources.

장 방법은 위와 같이 사용하면 다음과 같은 이점이 있습니 syntax:

style1.Merge(style2);

이 구문은 유용한 제공하는 경우의 스타일에 providevalue 를.만,나는 하지 않습니다.모든 나에서 얻을 생성자의 명부 문자열을 키한 스타일이다.면에 대한 지원이 있었다 params 에서 생성자를 매개 변수를 사용할 수 있는 다음과 같은 구문을 실제 스타일의 인스턴스:

<Button Style="{local:MultiStyle {StaticResource BigButtonStyle}, {StaticResource GreenButtonStyle}}" … />
public MultiStyleExtension(params Style[] styles)
{
}

하지만 그것은 작동하지 않는다.과하는 경우에도 params 제한이 존재하지 않았다,우리는 아마 다른 제한 마크업 확장을,우리가 우리가 사용하는 속성 요소로 구문을 대신 특성 구문을 지정합니 정원은 자세한 정보고 복잡(내가 이것을 설명 버그에서 더 나은 이전 블로그 글).과는 경우에도 그러한 제한은 존재하지 않았다,나는 여전히 오히려 쓰는 목록의 스타일을 사용하여 그들의 이름은 짧고 간단하게 읽어보다 StaticResource 에 대한 각각의 하나입니다.

는 솔루션을 만드는 staticresourceextension 사용하는 코드입니다.스타일의 열쇠를 입력 문자열과 서비스 공급자,사용할 수 있는 staticresourceextension 를 검색하는 실제적인 스타일의 인스턴스입니다.구문은 다음과 같습니다:

Style currentStyle = new StaticResourceExtension(currentResourceKey).ProvideValue(serviceProvider) as Style;

지금 우리가 모든 필요한 조각을 쓰 providevalue 메서드:

public override object ProvideValue(IServiceProvider serviceProvider)
{
    Style resultStyle = new Style();

    foreach (string currentResourceKey in resourceKeys)
    {
        Style currentStyle = new StaticResourceExtension(currentResourceKey).ProvideValue(serviceProvider) as Style;

        if (currentStyle == null)
        {
            throw new InvalidOperationException("Could not find style with resource key " + currentResourceKey + ".");
        }

        resultStyle.Merge(currentStyle);
    }
    return resultStyle;
}

여기에는 것은 완전한 예제의 사용량의 MultiStyle 태그를 확장자:

<Window.Resources>
    <Style TargetType="Button" x:Key="SmallButtonStyle">
        <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="BoldButtonStyle">
        <Setter Property="FontWeight" Value="Bold" />
    </Style>
</Window.Resources>

<Button Style="{local:MultiStyle SmallButtonStyle GreenButtonStyle BoldButtonStyle}" Content="Small, green, bold" />

enter image description here

하지만 확장할 수 있습니다에서 또 다른..을 살펴에 따라 객실

<Style TargetType="TextBlock">
      <Setter Property="Margin" Value="3" />
</Style>

<Style x:Key="AlwaysVerticalStyle" TargetType="TextBlock" 
       BasedOn="{StaticResource {x:Type TextBlock}}">
     <Setter Property="VerticalAlignment" Value="Top" />
</Style>

WPF/XAML 을 제공하지 않는 이 기능을 기본적으로,그러나 그것을 제공하지 않는 확장성을 할 수 있도록 당신이 무엇을 원합니다.

우리의 필요,결국 우리 자신을 만들기 XAML 태그를 확장자(우리는 소위"MergedStylesExtension")을를 만들 수 있도록 새로운 스타일에서 두 개의 다른 스타일(는,필요하다면,아마 여러 번 사용될에서 행하는 상속에서 더 많은 스타일).

인 WPF/XAML 버그를 사용해야 합성 요소는 구문에 그것을 사용하려면,하지만 다른 것보다는 작동하는 것 같다 확인.E.g.,

<Button
    Content="This is an example of a button using two merged styles">
    <Button.Style>
      <ext:MergedStyles
                BasedOn="{StaticResource FirstStyle}"
                MergeStyle="{StaticResource SecondStyle}"/>
   </Button.Style>
</Button>

나는 최근에 쓴 그것에 대해 여기:http://swdeveloper.wordpress.com/2009/01/03/wpf-xaml-multiple-style-inheritance-and-markup-extensions/

이것이 가능해 만드는 데 사용할 수 있는 도우미 클래스를 사용하고 감싸는 스타일입니다.CompoundStyle 급 그것을 수행하는 방법을 보여줍니다.여러 가지 방법이 있지만,가장 쉬운 방법은 다음 작업을 수행:

<TextBlock Text="Test"
    local:CompoundStyle.StyleKeys="headerStyle,textForMessageStyle,centeredStyle"/>

는 희망 도움이 됩니다.

AttachedProperty 을 설정하는 다양한 스타일을 같은 다음과 같은 코드:

public class Css
{

    public static string GetClass(DependencyObject element)
    {
        if (element == null)
            throw new ArgumentNullException("element");

        return (string)element.GetValue(ClassProperty);
    }

    public static void SetClass(DependencyObject element, string value)
    {
        if (element == null)
            throw new ArgumentNullException("element");

        element.SetValue(ClassProperty, value);
    }


    public static readonly DependencyProperty ClassProperty =
        DependencyProperty.RegisterAttached("Class", typeof(string), typeof(Css), 
            new PropertyMetadata(null, OnClassChanged));

    private static void OnClassChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ui = d as FrameworkElement;
        Style newStyle = new Style();

        if (e.NewValue != null)
        {
            var names = e.NewValue as string;
            var arr = names.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var name in arr)
            {
                Style style = ui.FindResource(name) as Style;
                foreach (var setter in style.Setters)
                {
                    newStyle.Setters.Add(setter);
                }
                foreach (var trigger in style.Triggers)
                {
                    newStyle.Triggers.Add(trigger);
                }
            }
        }
        ui.Style = newStyle;
    }
}

Usege:

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:style_a_class_like_css"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="325">
    <Window.Resources>

        <Style TargetType="TextBlock" x:Key="Red" >
            <Setter Property="Foreground" Value="Red"/>
        </Style>

        <Style TargetType="TextBlock" x:Key="Green" >
            <Setter Property="Foreground" Value="Green"/>
        </Style>

        <Style TargetType="TextBlock" x:Key="Size18" >
            <Setter Property="FontSize" Value="18"/>
            <Setter Property="Margin" Value="6"/>
        </Style>

        <Style TargetType="TextBlock" x:Key="Bold" >
            <Setter Property="FontWeight" Value="Bold"/>
        </Style>

    </Window.Resources>
    <StackPanel>

        <Button Content="Button" local:Css.Class="Red Bold" Width="75"/>
        <Button Content="Button" local:Css.Class="Red Size18" Width="75"/>
        <Button Content="Button" local:Css.Class="Green Size18 Bold" Width="75"/>

    </StackPanel>
</Window>

결과:

enter image description here

당신이 접촉되지 않는 어떤 특정 속성을 얻을 수있는,모든 기준 및 일반적인 속성이 있는 스타일의 대상이 유형은 다음과 같습니다 FrameworkElement.그 후,당신은 만들 수 있습니다 특정한 맛 각 대상에 대한 유형을 필요 없이,필요 복사하는 모든 일반적인 속성을 다시합니다.

당신은 아마 얻을 수 있습니다 비슷한을 신청하는 경우 이의 수집 항목을 사용하여 StyleSelector,내가 이것을 사용하여 접근 방식은 유사한 문제에서 사용하여 다양한 스타일에 TreeViewItems 에 따라 행 개체의 유형에 나무입니다.을 수정해야 할 수 있습니다 클래스는 아래에 약간을 조정하는 특별한 접근 방식이지만 희망이 당신을 얻을 것이기 시작

public class MyTreeStyleSelector : StyleSelector
{
    public Style DefaultStyle
    {
        get;
        set;
    }

    public Style NewStyle
    {
        get;
        set;
    }

    public override Style SelectStyle(object item, DependencyObject container)
    {
        ItemsControl ctrl = ItemsControl.ItemsControlFromItemContainer(container);

        //apply to only the first element in the container (new node)
        if (item == ctrl.Items[0])
        {
            return NewStyle;
        }
        else
        {
            //otherwise use the default style
            return DefaultStyle;
        }
    }
}

당신은 그 적용으로 이것도

 <TreeView>
     <TreeView.ItemContainerStyleSelector
         <myassembly:MyTreeStyleSelector DefaultStyle="{StaticResource DefaultItemStyle}"
                                         NewStyle="{StaticResource NewItemStyle}" />
     </TreeView.ItemContainerStyleSelector>
  </TreeView>

때로는 당신이 접근 할 수 있습이 중첩하여 패널이 있습니다.말을 하는 스타일 변경 다른 크기 변경을 적용할 수 있습니다 후에 하나 감속/가속 함수는 windows 런타임 및 격자는 그 스타일이 먼저 하나입니다.이 도움이 될 수 있습과될 수 있는 가장 쉬운 방법은 어떤 경우에는,비록 그것이 해결되지 않는 모든 문제입니다.

무시할 때 SelectStyle 을 얻을 수 있습 GroupBy 시설을 통해 반사는 아래와 같다:

    public override Style SelectStyle(object item, DependencyObject container)
    {

        PropertyInfo p = item.GetType().GetProperty("GroupBy", BindingFlags.NonPublic | BindingFlags.Instance);

        PropertyGroupDescription propertyGroupDescription = (PropertyGroupDescription)p.GetValue(item);

        if (propertyGroupDescription != null && propertyGroupDescription.PropertyName == "Title" )
        {
            return this.TitleStyle;
        }

        if (propertyGroupDescription != null && propertyGroupDescription.PropertyName == "Date")
        {
            return this.DateStyle;
        }

        return null;
    }

하려는 경우 적용되는 독특한 스타일을 단 하나의 요소 에 추가로 기지 스타일이 완전히 다른 방식으로 이렇게 하는 이럴 훨씬 더 나은에 대한 읽을 수 있고 유지 관리할 수 코드입니다.

그것은 매우 일반적인을 조정할 필요가 매개 변수별 개별 요소입니다.정의 사전 스타일에 사용하기 위해 요소는 것은 매우 복잡하거나 유지는 의미이다.을 피하는 스타일을 만들만을 위한 one-off 요소는 바뀌는,내에 응답하는 내 자신의 질문에 여기에 여기:

https://stackoverflow.com/a/54497665/1402498

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top