WPF。主题中定义的样式不起作用

时间:2014-10-21 13:53:12

标签: wpf styles themes

我有两个主题: Aero.NormalColor.xaml Classic.xaml 。我的窗户上有按钮。

<Grid>
    <Button Grid.Row="0" 
            Name="_first" 
            Content="Fisrt">
    </Button>
</Grid>

我在bouth主题中为Button定义了样式。

Aero.NormalColor.xaml

<Style TargetType="{x:Type ButtonBase}">
        <Setter Property="Background" Value="Red"/>
</Style>

Classic.xaml

<Style TargetType="{x:Type ButtonBase}">
        <Setter Property="Background" Value="Violet"/>
</Style>

并像这样设置汇编属性。

[assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly,
                     ResourceDictionaryLocation.SourceAssembly)]

我希望选择 Aero 主题时 - 按钮将为Red,当选择经典主题时,按钮将为Violet。但没有任何反应。无论选择什么主题,按钮都有默认的Gray颜色。我做错了什么?

2 个答案:

答案 0 :(得分:1)

解。事实证明,它比我想象的更复杂,但现在它有效。

首先创建一个派生按钮:

public partial class ImageButton : Button
{
    // Very important!
    static ImageButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
        typeof(ImageButton),
        new FrameworkPropertyMetadata(typeof(ImageButton)));
    }

    public ImageButton()
    {
        InitializeComponent();
    }
}

<Button x:Class="TestProjectTheme.ImageButton"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Button>

其次,正确设置程序集属性:

[assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly,
                 ResourceDictionaryLocation.SourceAssembly)]

第三,为windows主题定义资源词典:

<强> Aero.NormalColor.xaml

<Style TargetType="{x:Type Local:ImageButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Local:ImageButton}">
                    <Border Background="Aquamarine">
                        <ContentPresenter
                                  Margin="{TemplateBinding Padding}"
                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                  RecognizesAccessKey="True"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

<强> Classic.xaml

<Style TargetType="{x:Type Local:ImageButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Local:ImageButton}">
                    <Border Background="Red">
                        <ContentPresenter
                                  Margin="{TemplateBinding Padding}"
                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                  RecognizesAccessKey="True"/>
                    </Border>

                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

第四,在 MainWindow 中定义 ImageButton

<Local:ImageButton Content="look here!"
                    Width="100"
                    Height="100">

</Local:ImageButton>

第五,在 Windows-&gt; Personalizaton 中运行应用程序并将主题从经典切换到 Aero ,反之亦然 第六 - 享受:)

答案 1 :(得分:0)

不幸的是,在WPF中切换主题的机制比看起来更复杂。 Here你可以看到有关这方面的信息和解决方案,有些引用:

  

我越是想到这一点,我越发现所有这些问题都是由于我将系统主题(aero.normalcolor)应用于实际系统主题之上的风格而不是实际上改变它。所以我开始在Reflector中探索WPF如何选择当前主题。这听起来很难,而且实际上比它听起来要困难得多。经过十几个小时(分散了几个星期)和博客的一些指导非常接近(不幸的是,我的链接现在已经死了),我发现无论如何WPF在uxtheme.dll中调用本机方法获取实际的系统主题,然后将结果存储在MS.Win32.UxThemeWrapper,一个内部静态类(当然)。此外,类的属性是只读的(也标记为内部),因此更改它的最佳方法是直接操作私有字段。

通常,切换主题由“手”完成。

示例:

App.xaml

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="/Resources/Themes/DefaultSkin.xaml"/>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

App.xaml.cs

public partial class App : Application
{
    public void ChangeTheme(Uri uri)
    {
        var resourceDict = Application.LoadComponent(uri) as ResourceDictionary;
        Application.Current.Resources.MergedDictionaries.Clear();
        Application.Current.Resources.MergedDictionaries.Add(resourceDict);
    }
}

MainWindow.xaml

<StackPanel>
    <Button Width="100" Height="100" Content="Test" />
    <Button Width="100" Height="100" Content="Click Me" Click="Button_Click" />
</StackPanel>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var app = App.Current as App;
        app.ChangeTheme(new Uri(@"/Resources/Themes/BlueSkin.xaml", UriKind.Relative));
    }
}

DefaultSkin.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Style TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Red" />
    </Style>
</ResourceDictionary>

BlueSkin.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Style TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Blue" />
    </Style>
</ResourceDictionary>