如何在app.xaml中设置默认的WPF窗口样式?

时间:2009-01-10 23:11:22

标签: wpf c#-3.0 themes styles

我正在尝试为app.xaml中的WPF Windows应用程序中的每个窗口设置默认样式。到目前为止,我在app.xaml中有这个:

<Application.Resources>
    <ResourceDictionary>
        <Style x:Key="WindowStyle" TargetType="{x:Type Window}">
            <Setter Property="Background" Value="Blue" />
        </Style>
    </ResourceDictionary>
</Application.Resources>

通过专门告诉窗口通过以下方式使用此样式,我可以在运行应用程序时让窗口显示此样式(但不是VS设计器):

Style="{DynamicResource WindowStyle}

这有效,但并不理想。那么我该怎么做:

  1. 让所有窗口自动使用该样式(所以我不必在每个窗口上指定它)?
  2. 让VS设计师展示风格吗?
  3. 谢谢!

8 个答案:

答案 0 :(得分:45)

添加Ray所说的内容:

对于样式,您需要提供Key / ID或指定TargetType。

  

如果FrameworkElement没有   明确指定Style,它会   总是寻找Style资源,   使用自己的类型作为关键词    - 编程WPF(Sells,Griffith)

如果提供TargetType,则该类型的所有实例都将应用样式。然而,衍生类型不会......似乎。 <Style TargetType="{x:Type Window}">不适用于所有自定义派生/窗口。 <Style TargetType="{x:Type local:MyWindow}">仅适用于MyWindow。所以选项是

  • 使用您指定的键控样式作为要应用样式的每个窗口的样式属性。设计师将展示风格的窗口。

    <Application.Resources>
        <Style x:Key="MyWindowStyle">
            <Setter Property="Control.Background" Value="PaleGreen"/>
            <Setter Property="Window.Title" Value="Styled Window"/>
        </Style>
    </Application.Resources> ...
    <Window x:Class="MyNS.MyWindow" Style="{StaticResource MyWindowStyleKey}">  ...
  • 或者您可以从自定义BaseWindow类(具有its own quirks)派生,在Ctor / Initialization / Load阶段设置Style属性一次。然后,所有派生将自动应用样式。 但是设计师不会注意到你的风格你需要运行你的应用来看看正在应用的样式..我猜设计师只是运行InitializeComponent(这是自动/设计器生成的代码)所以应用XAML但不是自定义代码隐藏。

所以我说明确指定的样式是最不起作用的。你可以集中改变风格的各个方面。

答案 1 :(得分:20)

知道这是多年以后,但因为这个问题还在这里......

  1. 在项目中创建资源字典(右键单击项目...)

    我将在项目下创建一个名为“Assets”的新文件夹    将“resourceDict.XAML”放入其中。

  2. 将代码添加到resourceDict.XAML:

    <Style x:Key="WindowStyle" Target Type="Window" >
         <Setter Property="Background" Value="Blue" />
    </Style>
    
  3. 在Project XAML文件中,在Window:

    下添加以下内容
    <Window.Resources>
        <ResourceDictionary>
            <!-- Believe it or not the next line fixes a bug MS acknowledges -->
            <Style TargetType="{x:Type Rectangle}" />
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Assets/resourceDict.XAML" />
            </ResourceDictionary.MergedDictionaries>
        <ResourceDictionary>
    </Window.Resources>
    

    参考以下网站:Trouble referencing a Resource Dictionary that contains a Merged Dictionary “有一个错误:如果所有默认样式都嵌套在三个级别深度(或更深)的合并字典中,则顶级字典不会被标记,因此搜索会跳过它。解决方法是将默认样式放到某个东西,任何东西,在根词典中。“ 它似乎可靠地解决了问题。去图......

  4. 最后,在Window下,也许在Title之后,但在最后一个Window'&gt;'之前:

    Style="{DynamicResource windowStyle}"
    
  5. 您需要在第3步和第3步中添加代码。 4,您希望样式应用到的每个项目。

  6. 如果您想使用渐变背景而不是纯色,请将以下代码添加到resourceDict.XAML:

    <LinearGradientBrush x:Key="windowGradientBackground" StartPoint="0,0"
            EndPoint="0,1" >
    <GradientStop Color= "AliceBlue" Offset="0" />
    <GradientStop Color= "Blue" Offset=".75" />
    </LinearGradientBrush>
    
  7. 并修改样式设定器以获取背景颜色:

    <Setter Property="Background" Value="{DynamicResource
            windowGradientBackground}" />
    
  8. 步骤3&amp; 4需要在每个project.XAML文件中重复如上所述,但是,嘿,你在整个解决方案中获得统一的Windows!并且相同的过程可以应用于您想要具有统一外观的任何控件,按钮等等。

    对于那些迟到的人来说,希望这会有所帮助,因为我确信最初的海报在几年前就已经解决了。

答案 2 :(得分:8)

设计器无法正常工作,因为您正在指定DynamicResource。请将此更改为StaticResource,一切都会好的。

要应用于所有窗口,您应该从样式中删除x:Key。设置TargetType隐式地将x:Key设置为TargetType中的任何内容。但是,在我的测试中,这不起作用,所以我正在研究它。

如果我将TargetType设置为x:Type TextBlock,设计师工作得很好,它似乎就是显示不同行为的Window。

答案 3 :(得分:3)

我现在对这个问题进行了几天调查,并通过我的自定义Window类的构造函数使其工作:

public class KWindow : Window
{
        public KWindow()
        {
            this.SetResourceReference(StyleProperty, typeof(KWindow));
        }

        static KWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(KWindow), new FrameworkPropertyMetadata(typeof(KWindow)));

        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            // gets called finally
        }
}

希望它有助于某人

答案 4 :(得分:3)

您可以将此代码添加到App.xaml.cs文件中:

        FrameworkElement.StyleProperty.OverrideMetadata(typeof(Window), new FrameworkPropertyMetadata
        {
            DefaultValue = Application.Current.FindResource(typeof(Window))
        });

在此之后,应用于Window类型的样式也将适用于从Window

派生的所有类型

答案 5 :(得分:1)

对于那些努力解决问题的人:如何将自定义样式自动应用于我的所有Window派生类型?以下是我提出的解决方案

注意:我真的不想从Window类型派生,或者必须在每个窗口上插入XAML以强制样式更新等,这是因为我的项目特定的原因(我的产品的消费者是我的通用可重用样式库和创建他们自己的布局/窗口等)所以我真的积极找出一个解决方案,我愿意和任何副作用一起生活

需要遍历所有实例化的窗口,只需强制它们使用您为Window类型定义的新自定义样式。这适用于已经启动的窗口,但是当实例化窗口或子窗口时,它将不知道使用已为其基本类型声明的新/自定义类型;香草窗口类型。因此,我能想到的最好的方法是在MainWindow上使用LostKeyBoardFocus,当它失去Focus到ChildWindow时(IOW当创建子窗口时),然后调用此FixupWindowDerivedTypes()。

如果有人在实例化任何类型的窗口派生类型时有一个更好的“检测”解决方案,那么调用FixupWindowDerivedTypes()就会很棒。在此区域中处理WM_WINDOWPOSCHANGING可能会有用。

所以这个解决方案不是很优雅,但是我可以完成工作,而不必触及与我的窗口相关的任何代码或XAML。

   public static void FixupWindowDerivedTypes()
    {
        foreach (Window window in Application.Current.Windows)
        {
           //May look strange but kindly inform each of your window derived types to actually use the default style for the window type

                    window.SetResourceReference(FrameworkElement.StyleProperty, DefaultStyleKeyRetriever.GetDefaultStyleKey(window));
                }
            }
        }
    }


//Great little post here from Jafa to retrieve a protected property like DefaultStyleKey without using reflection.
http://themechanicalbride.blogspot.com/2008/11/protected-dependency-properties-are-not.html

//Helper class to retrieve a protected property so we can set it
internal class DefaultStyleKeyRetriever : Control
{
    /// <summary>
    /// This method retrieves the default style key of a control.
    /// </summary>
    /// <param name="control">The control to retrieve the default style key 
    /// from.</param>
    /// <returns>The default style key of the control.</returns>
    public static object GetDefaultStyleKey(Control control)
    {
        return control.GetValue(Control.DefaultStyleKeyProperty);
    }
}

答案 6 :(得分:0)

考虑到 Gishu 的回答,我想出了另外一个解决方法。但它可能有点奇怪。 如果使用MVVM模式,则可以删除窗口的代码隐藏和XAML文件中的x:Class标记。因此,您将获得一个窗口或自定义窗口的实例,但不会获得从'Window'类派生并标记为partial的'MainWindow'类的某个实例。 我正在制作类似于VS的窗口,所以我必须继承窗口类并扩展它的功能。在这种情况下,可以将新的窗口类作为部分,以允许我们在没有继承的情况下进行代码隐藏。

答案 7 :(得分:-2)

  1. 您将所有样式保存在一个xaml文件中(例如design.xaml)

  2. 然后像这样在所有页面中调用(design.xaml)xaml文件

  3. 喜欢:

    <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary  Source="Design.xaml"/>                
    </ResourceDictionary.MergedDictionaries>