65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (3投票s)

2009年4月14日

CC (Attr 3U)

3分钟阅读

viewsIcon

39416

无样式控件的默认样式

微软在WPF中引入了“无外观”控件的概念,这意味着控件定义其行为时没有任何关于它实际外观的信息,这就是模板和样式发挥作用的地方。然而,所有默认控件都提供默认外观,这与当前的Windows主题(Windows Vista中的Aero,Windows XP中的Luna、Metallic或Homestead等)保持一致。如果您正在为一般使用创建类库中的无外观控件,那么提供控件的默认外观也会有所帮助。要实现这一点,您需要做三件事。

注意:本文特别指的是自定义控件(即,从ControlFrameworkElement或类似控件继承的控件,而不是从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.xamlWindows XP上的“经典”Windows 9x/2000外观
Luna.NormalColor.xamlWindows XP上的默认蓝色主题
Luna.Homestead.xamlWindows XP上的橄榄色主题
Luna.Metallic.xamlWindows XP上的银色主题
Royale.NormalColor.xamlWindows XP Media Center Edition上的默认主题
Aero.NormalColor.xamlWindows 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枚举,其值为NoneSourceAssemblyExternalAssembly

以下代码示例显示了包含前面描述的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网站上的设计可样式化控件的指南

© . All rights reserved.