문제
에 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" />
하지만 확장할 수 있습니다에서 또 다른..을 살펴에 따라 객실
<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>
결과:
당신이 접촉되지 않는 어떤 특정 속성을 얻을 수있는,모든 기준 및 일반적인 속성이 있는 스타일의 대상이 유형은 다음과 같습니다 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 요소는 바뀌는,내에 응답하는 내 자신의 질문에 여기에 여기: