定义无样式控件的默认样式






4.50/5 (3投票s)
无样式控件的默认样式
微软在WPF中引入了“无外观”控件的概念,这意味着控件定义其行为时没有任何关于它实际外观的信息,这就是模板和样式发挥作用的地方。然而,所有默认控件都提供默认外观,这与当前的Windows主题(Windows Vista中的Aero,Windows XP中的Luna、Metallic或Homestead等)保持一致。如果您正在为一般使用创建类库中的无外观控件,那么提供控件的默认外观也会有所帮助。要实现这一点,您需要做三件事。
注意:本文特别指的是自定义控件(即,从Control,FrameworkElement或类似控件继承的控件,而不是从UserControl继承的用户控件)。有关创建WPF控件的更多信息,请参阅MSDN网站上的控件创作概述。
1. 覆盖DefaultStyleKey属性的元数据
在您的控件的static
构造函数中,将默认样式键设置为类型名称,该名称用于对您的控件进行样式查找。以下代码示例显示了我正在创建的Wizard
类的static
构造函数。
1: static Wizard()
2: {
3: DefaultStyleKeyProperty.OverrideMetadata(
4: typeof(Wizard),
5: new FrameworkPropertyMetadata(typeof(Wizard)));
6: }
2. 定义您的默认样式
您可以为每个不同的Windows主题创建默认样式。要做到这一点,您需要在Themes文件夹中创建一个具有特定名称的资源字典,该文件夹是您的类库中包含您的控件的文件夹的子文件夹。下表提供了特定于主题的资源字典的文件名。
资源字典 | Windows主题 |
Classic.xaml | Windows XP上的“经典”Windows 9x/2000外观 |
Luna.NormalColor.xaml | Windows XP上的默认蓝色主题 |
Luna.Homestead.xaml | Windows XP上的橄榄色主题 |
Luna.Metallic.xaml | Windows XP上的银色主题 |
Royale.NormalColor.xaml | Windows XP Media Center Edition上的默认主题 |
Aero.NormalColor.xaml | Windows Vista上的默认主题 |
您不需要为每个主题都提供样式。如果没有特定于主题的资源,则使用控件的通用资源,该资源在Themes\generic.xaml资源字典中定义。
以下XAML代码示例显示了上面描述的Wizard
类在generic.xaml中的默认样式
1: <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2: xmlns:local="clr-namespace:DerekLakin.Libraries.Presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
4: <Style TargetType="{x:Type local:Wizard}">
5: <Setter Property="Template">
6: <Setter.Value>
7: <ControlTemplate TargetType="{x:Type local:Wizard}">
8: <DockPanel LastChildFill="True">
9: <WrapPanel DockPanel.Dock="Bottom"
10: HorizontalAlignment="Right"
11: Orientation="Horizontal"
12: Margin="10">
13: <Button x:Name="PART_Back"
14: Content="Back" />
15: <Button x:Name="PART_Next"
16: Content="Next"
17: Margin="4,0,0,0" />
18: <Button x:Name="PART_Cancel"
19: Content="Cancel"
20: Margin="4,0,0,0" />
21: <Button x:Name="PART_Finish"
22: Content="Finish"
23: Margin="4,0,0,0" />
24: </WrapPanel>
25: <Frame x:Name="PART_Frame"
26: NavigationUIVisibility="Hidden" />
27: </DockPanel>
28: </ControlTemplate>
29: </Setter.Value>
30: </Setter>
31: </Style>
32: </ResourceDictionary>
3. 将ThemeInfo属性添加到AssemblyInfo
最后一部分是公开您的程序集包含特定于控件的资源的事实,您可以通过使用ThemeInfo属性来实现。 GenericDictionaryLocation属性定义通用资源的位置,而ThemeDictionaryLocation属性定义主题资源的位置。 这两个属性的值都是一个ResourceDictionaryLocation枚举,其值为None、SourceAssembly或ExternalAssembly。
以下代码示例显示了包含前面描述的Wizard
类的类库项目的ThemeInfo属性,该属性没有特定于主题的资源,但确实指定了一个通用资源。
1: [assembly: ThemeInfo(ResourceDictionaryLocation.None,
2: ResourceDictionaryLocation.SourceAssembly)]
附注
如果您的自定义控件具有对控件操作至关重要的特定部分(例如前面描述的Wizard
示例中的按钮和框架),那么约定是使用“PART_
”前缀在控件模板中命名它们。 对于模板中的每个必需部分,您应该在类定义中添加一个TemplatePart属性,如以下代码示例所示
1: [TemplatePart(Name = "PART_Frame", Type = typeof(Frame))]
2: [TemplatePart(Name = "PART_Back", Type = typeof(Button))]
3: [TemplatePart(Name = "PART_Cancel", Type = typeof(Button))]
4: [TemplatePart(Name = "PART_Finish", Type = typeof(Button))]
5: [TemplatePart(Name = "PART_Next", Type = typeof(Button))]
6: public class Wizard : Window
您应该在类的OnApplyTemplate
重写中获取对这些命名的模板部分的引用,因为这是实际应用控件模板的地方。 通常不专门处理缺少的模板部分,以便在运行时引发异常(通常是NullReferenceException
),这清楚地表明某些内容已损坏。
以下代码示例显示了前面描述的Wizard
类的OnApplyTemplate
重写
1: public override void OnApplyTemplate()
2: {
3: base.OnApplyTemplate();
4:
5: // Get the template parts.
6: this.navigationFrame = this.GetTemplateChild("PART_Frame") as Frame;
7: this.back = this.GetTemplateChild("PART_Back") as Button;
8: this.cancel = this.GetTemplateChild("PART_Cancel") as Button;
9: this.finish = this.GetTemplateChild("PART_Finish") as Button;
10: this.next = this.GetTemplateChild("PART_Next") as Button;
11: }
有关设计无外观控件的更多信息,请参阅MSDN网站上的设计可样式化控件的指南。