Style.TargetType、对话框和WPF控件的子类化

4
假设我想将应用程序中所有 StackPanel 的背景设置为某种颜色。 我在 App.xaml 中添加了以下内容:
<Style TargetType="StackPanel">
    <Setter Property="Background" Value="#222222" />
</Style>

只有在 StackPanel 是纯粹的 StackPanel 时,这个方法才有效,并且 StackPanel 必须在 App 下。然而,在弹出对话框中子类的 StackPanel 或者 StackPanel 的背景颜色将不会被改变。例如:

public class MyStackPanel : StackPanel { ... }

解决子类化问题的一种方法是扩展UserControl,并将StackPanel嵌入到UserControl中。只要您不需要访问StackPanel的属性,这样做就可以了。

有什么想法吗?

如何最好地进行WPF主题设置?


可能是 https://dev59.com/G3NA5IYBdhLWcg3wSrqa 的重复。 - Adi Lester
@AdiLester 那么在弹出对话框/窗口中的控件呢?有没有一种方法可以将相同的外观应用于它们,而不必复制样式? - David
2个回答

3
你可以为自定义类创建一个隐式样式,该样式继承自基类的样式。
<Style TargetType="StackPanel">
    <Setter Property="Background" Value="#222222" />
</Style>

<Style TargetType="{x:Type local:MyStackPanel}" 
       BasedOn="{StaticResource {x:Type StackPanel}}" />

1
@David 如果你将样式放在 Application.Resources 中,它们应该会应用于弹出对话框或其他窗口中的控件。否则,你可以将所有样式放在资源文件中,并在每个主要部分(例如 Window.Resources)中简单地导入该文件。 - Rachel
我尝试过了,不起作用。样式应用于子控件,但不适用于包含样式的控件。 - David
@David 如果您想将它应用于所有 MyStackPanel 的实例,请在 Application.ResourcesWindow.Resources 中设置它。如果您只想将其应用于特定的 MyStackPanel,请在 MyStackPanel.Style 中设置它。如果您想将其设置为特定 MyStackPanel 内的所有 MyStackPanel 实例,请在 MyStackPanel.Resources 中设置它。 - Rachel
当我尝试这个时,为什么会出现XamlParseException?它说我需要在TargetType和BasedOn中使用相同的类型,而不是不同的类型,你有什么建议? - ygoe
@LonelyPixel,你的自定义类型是否继承了你的“TargetType”?如果是,那么它应该可以工作... 如果不是这种情况,我建议您发布一个带有相关信息的新问题 :) - Rachel
显示剩余3条评论

0

覆盖 WPF 控件并不是一个好的实践。正如您所提到的,您需要为此设计一个 UserControl 子类。

您可以将您的 StackPanel(在您的 UserControl 内部)的属性绑定到您的 UserControl 子类的属性上,这些属性可以通过代码添加或绑定到 UserControl 的内置属性上。

<UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <StackPanel Background="{Binding Path=Background}">
    ...
    </StackPanel>
</UserControl>

谢谢,然而我不想走这条路。原因是需要额外的工作,而且不够灵活。例如,我将无法向堆栈面板添加控件。 - David
1
虽然这不适用于StackPanel示例:设计一个与本地主题不匹配的内置WPF主题也不是一个好的实践。微软在Windows 8中违反了这一点,并认为这很棒。因此,我们必须在我们的应用程序中修复它。对于所有控件都要如此。 - ygoe

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