为自定义控件创建默认样式

4
我目前正在创建一个自定义控件(基于WPF DataGrid)。我想要做的是设置DataGrid的默认样式。目前我正在设置Style属性,这个方法有效。但是当我创建一个样式来更改主应用程序app.xaml中的背景颜色时,我的“默认”样式就会丢失,DataGrid看起来很标准,只有背景属性被设置。
我已经尝试在我想应用默认值的每个网格属性上使用OverrideMetadata,但没有成功。我还尝试在构造函数中设置每个属性,但由于属性优先级,主应用程序的样式永远不会被应用。

你尝试过在自定义样式中设置“BasedOn”吗? - Kenan E. K.
我考虑过这个问题,但是要实现这一点,我必须在我的网格控件上创建一个属性来获取默认样式,然后在 app.xaml 中创建新样式时使用 BasedOn 属性。我只是认为应该有更好的解决方案。对于所有第三方控件,您都可以创建新样式并设置一些属性,而无需重新实现完整的样式。 - Daniel
2个回答

13

你是否在static构造函数中设置了这个?

DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomType), new FrameworkPropertyMetadata(typeof(MyCustomType)));

另外,你的资源的键(Key)是否等于自定义控件的类型(Type)?

即使将TargetType设置为你的控件,也不能设置其他Key。

程序集还应该标记有以下属性:

[assembly: ThemeInfo(
    //where theme specific resource dictionaries are located
    //(used if a resource is not found in the page, 
    // or application resource dictionaries)
    ResourceDictionaryLocation.None, 

    //where the generic resource dictionary is located
    //(used if a resource is not found in the page, 
    // app, or any theme specific resource dictionaries)
    ResourceDictionaryLocation.SourceAssembly 
)]

嘿,kek444我尝试过了,当我包含代码时,在网格渲染时没有显示任何内容(只有一个网格应该出现的空白区域)。我目前正在尝试让BasedOn自定义样式起作用。 - Daniel
答案提供附加信息。 - Kenan E. K.
我实际上没有将密钥设置为我的控件类型。我已经纠正了这个问题,但是仍然出现了控件应该出现的空白区域。我已经将样式放置在themes/generic.xaml文件中,并在assemblyinfo文件中添加了[assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly)]标记。这可能与此有关吗? - Daniel
1
你需要: 1)在Themes/Generic.xaml中设置默认样式,Style上不需要x:Key,但需要设置TargetType。 2)在控件的静态构造函数中设置DefaultStyleKeyProperty.OverrideMetadata语句,如上所述。 3)在程序集ThemeInfo中不需要做任何事情,如上所述。 - Tim Erickson
1
太棒了,我之前不明白为什么我的控件没有模板...在AssemblyInfo中的ThemeInfo解决了这个问题。 - Oliver

5
如果您创建一个没有字典键的样式,它将为您指定类型的所有对象进行样式设置。此样式将在导入样式字典的范围内生效(如果您将其指定在Window.Resources中,则仅对该窗口有效...如果您将其指定在App.xaml中...您懂的)。
  <Style TargetType="{x:Type Button}">
    <Setter Property="FontFamily" Value="Times New Roman" />
    <Setter Property="FontSize" Value="30" />
    <Setter Property="FontWeight" Value="Bold" />
    <Setter Property="Background" Value="#FFCA5132" />
  </Style>

这将使它们都具有相同的样式。

这是一个非常强大的功能。它允许您为任何对象设置样式,而不仅仅是UI元素。例如,您可以将数据实体之一(例如“人”对象)设置为样式,当这些元素在可视化使用时,比如将类型为Person的列表数据绑定到ListView上时,所有这些元素都将按照您指定的样式进行设置,即使它们不是本地的UI元素。这就是WPF可以对其控件“无外观”的原因。


问题在于我已经创建的默认样式在网格的资源字典中,没有被覆盖。我的默认样式如下:<Style TargetType="DataGrid"> <Setter Property="Background" Value="Black"/> <Setter Property="Foreground" Value="Yellow"/> </Style> 现在,如果我在主应用程序的app.xaml中创建一个新样式:<Style TargetType="DataGrid"> <Setter Property="Background" Value="Green"/> </Style> 背景将不会变成绿色,因为网格资源字典中的默认样式将具有优先权。 - Daniel
有没有一种方式可以为数据网格上的每个属性添加默认值,以便在控件上设置新样式时不会覆盖所有样式? - Daniel
你需要创建另一个样式,并将BasedOn属性设置为“DataGrid”,然后覆盖那些你想要针对特定实例进行覆盖的少数内容。 - Anderson Imes
请注意短语“没有字典键”!我自己也遇到了这个问题——原型使用了有键样式,当我将新控件添加到基线时忘记删除键——存在键意味着它永远不会作为默认样式起作用——所以,+1。 - Mark Mullin

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