继承应用程序样式(WPF)

4

我正在尝试继承我的WPF应用程序中某个Window的应用程序级样式,但我无法使其继承而不是简单地覆盖现有样式。

App.xaml(在App.Resources元素下)中,我定义了一个样式,如下所示:

<Style TargetType="Button">
    <Setter Property="Padding" Value="6"/>
    <Setter Property="FontWeight" Value="Bold"/>
</Style>

在某个Window的XAML中,我在Window.Resources下定义了以下内容:

<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
    <Setter Property="Padding" Value="6"/>
    <Setter Property="FontWeight" Value="Bold"/>
</Style>

这里的问题在于前者(应用程序)的样式被忽略,就好像后者(窗口)的样式覆盖了它一样。根据我所知,设置了“BasedOn”属性,旨在表明现有样式应该被继承。但是删除属性也无济于事。我能想到的唯一潜在原因是,“{StaticResource {x:Type Button}}”只引用了默认的WPF样式,而不是我在“App.xaml”中定义的样式。
我知道可以使用“x:Key”属性来实现这种样式行为,但我希望有一种更优雅的方式,允许我将继承样式应用于范围内的所有控件(即应用程序/窗口)。
更新
感谢你们两位的回答。你们确实正确,样例应用程序中的结果符合预期。区别在于我无意中未提及“App.xaml”中的样式包含在“ResourceDictionary”中,如下所示:
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>

            <ResourceDictionary Source="SettingsDictionary.xaml"/>

            <ResourceDictionary>

                <Style x:Key="DefaultButton" TargetType="Button">
                    <Setter Property="Padding" Value="4"/>
                    <Setter Property="HorizontalAlignment" Value="Center"/>
                    <Setter Property="VerticalAlignment" Value="Center"/>
                </Style>

            </ResourceDictionary>

        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

有什么建议可以在这种情况下解决问题吗?

如果您正在尝试为窗口或控件创建新的默认样式,那么这个假设是正确的,您的第二个样式声明也是如此。在您特定的示例中,默认样式的两个属性都将被新的默认样式覆盖。如果没有继承任何原始样式的属性,则可能存在不同的问题。您是否有动态更改样式属性的情况? - Jeff Wain
@Jeff:我根本没有动态更改样式。实际上,这些是当前应用程序中唯一定义的样式,所以我不知道还有什么可能会干扰。我仍然在想我是否误解了样式系统... - Noldorin
只是确认一下,在应用程序中为样式设置x:Key,并以此为基础为窗口设置样式完全没有问题。我正在寻找一种避免这种情况的方法,也许可以使用另一个绑定说明符。 - Noldorin
2个回答

5

编辑

经过一些研究,我发现如果设置了TargetType,则x:Key会自动生成。因此,App.xaml中的样式是正确的。然而,wpf设计师缺乏一些资源处理技巧,并且不能显示两种样式。如果您构建并运行项目,则会应用两种样式。

如果您的计算机和VS2008的行为与我测试您的代码的计算机相似。

希望这可以帮助您。

编辑2

App.xaml中的资源和合并字典始终有些棘手。我通过将第一个样式声明移出合并字典来解决了这个问题,像这样:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>

            <!--<ResourceDictionary Source="SettingsDictionary.xaml"/>-->

        </ResourceDictionary.MergedDictionaries>

        <Style TargetType="Button">
            <Setter Property="Foreground" Value="Red"/>
            <Setter Property="Padding" Value="4"/>
            <Setter Property="HorizontalAlignment" Value="Center"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
        </Style>

    </ResourceDictionary>
</Application.Resources>

需要注意的是,如果给样式设置一个与{x:Type Button}不同的显式键,则它将成为非默认样式,并且不会自动应用。

通常建议仅为来自另一个文件的资源以及上述默认空间中的编码资源指定合并的字典。


@kek44: 啊!的确可以修复问题。(我简直不敢相信我没尝试在那个位置放置样式元素;我一定尝试过其他几种方法。)现在从结构上看,以这种方式定义它们更有意义。无论如何,非常感谢。赏金归你了。 :) - Noldorin
只是为了最终确定事情:如果我需要在单独的ResourceDictionary XAML文件中定义某些样式(例如在程序集之间共享),是否仍然有办法使继承正常工作,就像我在这里想要的那样? - Noldorin
1
作为一个实验,尝试将你的第一个按钮样式放在单独的资源字典中,并在app.xaml合并字典中引用它。我没有检查过,但我敢打赌它会正常工作。主要的重点是让合并的字典真正合并外部文件,否则它也可以正常工作。 - Kenan E. K.

1

我赞同Jeff Wains的评论,对于你的方法无法按预期工作感到惊讶。事实上,我无法通过以下步骤重现您的问题:

  • 通过VS 2008 C# WPF应用程序向导创建了一个新项目。
    • 结果是App.xaml和Window1.xaml,就像您的示例一样
  • 从工具箱中添加了一个标准按钮到Window1。
  • 将您的代码片段原封不动地粘贴进去,每个属性都进行了修改,以便首先观察所需的效果(我猜您并不想展示相同属性/值)。

好吧,这很正常,即Window1中的按钮继承了两种样式的属性,并且在任何一个样式中修改属性都会正确地影响按钮。因此,在您的项目/环境中肯定有一些奇怪的事情发生?您已经尝试过像这样的简单复制案例了吗?


感谢回复,虽然看起来kek444已经从我的更新问题中找到了问题所在。 - Noldorin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接