65

I am trying to set the default Style for every window in my WPF Windows application in my app.xaml. So far i have this in app.xaml:

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

I can get the window to appear with this style when running the app (but not in VS designer) by specifically telling the window to use this style via:

Style="{DynamicResource WindowStyle}

This works, but is not ideal. So how do I:

  1. Have all windows automatically use the style (so i don't have to specify it on every window)?
  2. Have VS designer show the style?

Thanks!

4

8 回答 8

49

补充一下Ray所说的:

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

如果 FrameworkElement 没有明确指定的样式,它将始终使用自己的类型作为键来查找样式资源
- Programming WPF (Sells, Griffith)

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

  • 使用您指定为要应用该样式的每个窗口的 Style 属性的键控样式。设计器将显示样式化的窗口。

.

    <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 类(它有自己的怪癖)派生,您可以在 Ctor/Initialization/Load 阶段设置 Style 属性一次。然后所有派生将自动应用该样式。但是设计器不会注意到您的样式您需要运行您的应用程序才能看到正在应用的样式。我猜设计器只是运行 InitializeComponent (这是自动/设计器生成的代码),因此应用了 XAML 但不是自定义的代码隐藏。

所以我想说明确指定的样式是最少的工作。无论如何,您都可以集中更改样式的各个方面。

于 2009-01-20T10:34:40.133 回答
24

知道这是几年后的事了,但是由于问题仍然存在...

  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>
    

    参考以下网站:引用包含合并字典的资源字典时遇到 问题 “有一个错误:如果您的所有默认样式都嵌套在合并字典中三层深(或更深),则顶部字典不会被标记,因此搜索会跳过它。解决方法是在根词典中为某事、任何事物设置一个默认样式。” 它似乎可以可靠地解决问题。去搞清楚...

  4. 最后,在 Window 下,可能在 Title 之后,但在最终 Window '>' 之前:

    Style="{DynamicResource windowStyle}"
    
  5. 您需要将第 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}" />
    

如上所述,需要在每个 project.XAML 文件中重复第 3 步和第 4 步,但是,您可以在解决方案中获得统一的 Windows!同样的过程也适用于任何你想要具有统一外观的控件、按钮等等。

对于迟到的任何人,希望这会有所帮助,因为我确信原始海报几年前就已经弄清楚了。

保罗

于 2012-03-27T21:11:41.867 回答
8

The designer is not working because you're specifying a DynamicResource. Please change this to StaticResource and all will be well.

To apply to all windows, you should remove the x:Key from the style. Setting the TargetType implicitly sets the x:Key to whatever is in TargetType. However, in my tests, this is not working, so I am looking into it.

If I set the TargetType to x:Type TextBlock, the designer works perfectly, it just seems to be the Window that is showing different behaviour.

于 2009-01-10T23:23:18.553 回答
7

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

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

在此之后,应用于Window类型的样式也将应用于派生自的所有类型Window

于 2017-01-31T15:15:23.447 回答
3

我已经调查了几天,并通过我的自定义窗口类的构造函数使它工作:

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

希望它可以帮助某人

于 2015-02-25T09:58:17.313 回答
1

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

注意:出于特定于我的项目的原因(我的产品的消费者使用我的通用可重用样式库并创建自己的布局/窗口等)所以我真的很想找出一个可行的解决方案,我愿意忍受任何副作用

需要遍历所有实例化的窗口并简单地强制它们使用您为 Window 类型定义的新自定义样式。这对于已经启动的窗口非常有用,但是当实例化窗口或子窗口时,它不会知道使用已为其基类型声明的新/自定义类型;香草窗口类型。所以我能想到的最好的办法是在 MainWindow 上使用 LostKeyBoardFocus 以在它失去对 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);
    }
}
于 2013-05-10T17:06:10.887 回答
0

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

于 2014-02-02T09:32:58.650 回答
-2
  1. 您将所有样式保存在一个 xaml 文件中(示例 design.xaml)

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

喜欢:

<ResourceDictionary.MergedDictionaries>
                <ResourceDictionary  Source="Design.xaml"/>                
</ResourceDictionary.MergedDictionaries>
于 2013-11-18T09:25:21.070 回答