使用 适用于 Visual Studio 的 WPF 设计器的扩展性模型,可以为各个属性类别创建自定义编辑器,这种编辑器称为类别编辑器。 使用类别编辑器,您可以提供一个自定义用户界面,使用户能够编辑属于同一个类别的相关属性,例如文本相关属性。 在本演练中,将生成一个类别编辑器,使用户能够编辑控件的文本相关属性。
在本演练中,您将执行下列任务:
创建 WPF 自定义控件项目。
创建可用来编辑该控件的文本相关属性的类别编辑器。
创建一个从 CategoryEditor 继承的类,该类表示控件的类别编辑器。
创建一个用来实现 IProvideAttributeTable 接口的类,以注册新的扩展编辑器。
在设计时测试类别编辑器。
系统必备
您需要以下组件来完成本演练:
- Visual Studio 2010.
创建自定义控件
第一步是为自定义控件创建项目。 该控件是一个带有少量设计时代码的简单按钮,该按钮使用 GetIsInDesignMode 方法来实现设计时行为。
创建自定义控件
使用 Visual C# 创建一个名为 CustomControlLibrary 的新 WPF 自定义控件库项目。
CustomControl1 的代码在“代码编辑器”中打开。
在 CustomControl1 的代码编辑器中,用下面的代码替换 CustomControlLibrary 命名空间中的代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace CustomControlLibrary { public class CustomControl1 : Button { public CustomControl1() { if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) { Content = "In design mode"; } } } }
将项目的输出路径设置为“bin\”。
生成解决方案。
创建封装属性信息的类
将要创建的类别编辑器需要一些有关字体和相关属性的信息,因此将创建一个封装这些信息的类。 类别编辑器将此类用作数据源。
创建封装字体属性信息的类
使用 Visual C# 向解决方案中添加一个名为 CustomControlLibrary.Design 的新 WPF 自定义控件库项目。
CustomControl1 的代码在“代码编辑器”中打开。
在**“解决方案资源管理器”**中,将 CustomControl1 文件从 CustomControlLibrary.Design 项目中删除。
在“解决方案资源管理器”中,将 Themes 文件夹从 CustomControlLibrary.Design 项目中删除。
添加对以下 WPF 设计器程序集的引用。
Microsoft.Windows.Design.Extensibility
Microsoft.Windows.Design.Interaction
添加对 CustomControlLibrary 项目的引用。
将项目的输出路径设置为“.. \CustomControlLibrary\bin\”。 这样可使控件的程序集与元数据程序集位于同一文件夹中,从而可为设计器启用元数据发现。
向 CustomControlLibrary.Design 项目中添加一个名为 FontList 的新类。
在 FontList 的代码编辑器中,用下面的代码替换自动生成的代码。
using System; using System.Linq; using System.Collections.Generic; using System.Text; using System.Windows.Media; using System.Collections.ObjectModel; using System.Windows; using System.Windows.Data; using System.Globalization; namespace CustomControlLibrary.Design { public class FontList : ObservableCollection<FontFamily> { public FontList() { foreach (FontFamily ff in Fonts.SystemFontFamilies) { Add(ff); } } } public class FontSizeList : ObservableCollection<double> { public FontSizeList() { Add(8); Add(9); Add(10); Add(11); Add(12); Add(14); Add(16); Add(18); Add(20); } } public class FontStyleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { FontStyle fs = (FontStyle)value; return fs == FontStyles.Italic; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null) { bool isSet = (bool)value; if (isSet) { return FontStyles.Italic; } } return FontStyles.Normal; } } public class FontWeightConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { FontWeight fs = (FontWeight)value; return fs == FontWeights.Bold; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null) { bool isSet = (bool)value; if (isSet) { return FontWeights.Bold; } } return FontWeights.Normal; } } }
为类别编辑器创建模板
类别编辑器将使用 XAML 数据模板创建。 这将是一个绑定到多个文本相关属性的简单用户界面。
为类别编辑器创建模板
向 CustomControlLibrary.Design 项目中添加一个名为 EditorResources 的新类。
在 EditorResources 的代码编辑器中,用下面的代码替换自动生成的代码。
namespace CustomControlLibrary.Design { using System; using System.Collections.Generic; using System.Text; using System.Windows; public partial class EditorResources : ResourceDictionary { public EditorResources() : base() { InitializeComponent(); } } }
在**“项目”菜单中,单击“添加资源字典”**。
将该文件命名为 EditorResources.xaml 并单击**“添加”**。
在 EditorResources 的 XAML 视图中,用下面的 XAML 替换自动生成的 XAML。
<ResourceDictionary xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design.Interaction" xmlns:Local="clr-namespace:CustomControlLibrary.Design" xmlns:Media="clr-namespace:System.Windows.Media;assembly=PresentationCore" xmlns:sys="clr-namespace:System;assembly=mscorlib" x:Class="CustomControlLibrary.Design.EditorResources"> <Local:FontList x:Key="FontFamilyList"/> <Local:FontSizeList x:Key="FontSizeList"/> <Local:FontStyleConverter x:Key="FontStyleConverter"/> <Local:FontWeightConverter x:Key="FontWeightConverter"/> <DataTemplate x:Key="TextCategoryEditorTemplate"> <StackPanel Margin="5"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="50"/> </Grid.ColumnDefinitions> <ComboBox Grid.Column="0" Margin="2" ItemsSource="{Binding Source={StaticResource FontFamilyList}}" SelectedItem="{Binding [FontFamily].PropertyValue.Value}"/> <ComboBox Grid.Column="1" Margin="2" ItemsSource="{Binding Source={StaticResource FontSizeList}}" SelectedItem="{Binding [FontSize].PropertyValue.Value}"/> </Grid> <StackPanel Orientation="Horizontal"> <CheckBox Margin="2" Content="Bold" IsChecked="{Binding Path=[FontWeight].PropertyValue.Value, Converter={StaticResource FontWeightConverter}}"/> <CheckBox Margin="2" Content="Italic" IsChecked="{Binding Path=[FontStyle].PropertyValue.Value, Converter={StaticResource FontStyleConverter}}"/> </StackPanel> </StackPanel> </DataTemplate> </ResourceDictionary>
生成解决方案。
封装模板并注册类别编辑器
在为类别编辑器创建了模板之后,现在必须创建一个继承自 CategoryEditor 的类以便将该模板用作自定义编辑器,而且必须注册新的类别编辑器。
封装并注册类别编辑器
向 CustomControlLibrary.Design 项目中添加一个名为 TextCategoryEditor 的新类。
在 TextCategoryEditor 的代码编辑器中,用下面的代码替换自动生成的代码。
namespace CustomControlLibrary.Design { using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using Microsoft.Windows.Design.PropertyEditing; public class TextCategoryEditor : CategoryEditor { private EditorResources res = new EditorResources(); public TextCategoryEditor() { } public override bool ConsumesProperty(PropertyEntry property) { return true; } public override DataTemplate EditorTemplate { get { return res["TextCategoryEditorTemplate"] as DataTemplate; } } public override object GetImage(Size desiredSize) { return null; } public override string TargetCategory { get { return "Text"; } } } }
向 CustomControlLibrary.Design 项目中添加一个名为 Metadata 的新类。
在 Metadata 的代码编辑器中,用下面的代码替换自动生成的代码。
using System; using System.Collections.Generic; using System.Text; using Microsoft.Windows.Design.Metadata; using System.ComponentModel; using Microsoft.Windows.Design.PropertyEditing; using System.Windows.Media; using System.Windows.Controls; using System.Windows; using CustomControlLibrary; // The ProvideMetadata assembly-level attribute indicates to designers // that this assembly contains a class that provides an attribute table. [assembly: ProvideMetadata(typeof(CustomControlLibrary.Design.Metadata))] namespace CustomControlLibrary.Design { // Container for any general design-time metadata to initialize. // Designers look for a type in the design-time assembly that // implements IProvideAttributeTable. If found, designers instantiate // this class and access its AttributeTable property automatically. internal class Metadata : IProvideAttributeTable { // Accessed by the designer to register any design-time metadata. public AttributeTable AttributeTable { get { AttributeTableBuilder builder = new AttributeTableBuilder(); builder.AddCustomAttributes (typeof(CustomControl1), new EditorAttribute( typeof(TextCategoryEditor), typeof(TextCategoryEditor))); return builder.CreateTable(); } } } }
生成解决方案。
测试类别编辑器
类别编辑器现在已经完成,可以开始使用了。 剩下的工作就是对其进行测试。 若要测试类别编辑器,需要向项目中添加一个 WPF 应用程序,向该 WPF 应用程序中添加自定义控件,并查看操作中的类别编辑器。
测试类别编辑器
使用 Visual C# 向解决方案中添加一个名为 DemoApplication 的新 WPF 应用程序项目。
MainWindow.xaml 将在 WPF 设计器中打开。
添加对 CustomControlLibrary 项目的引用。
在 MainWindow.xaml 的 XAML 视图中,用下面的 XAML 替换自动生成的 XAML。 此 XAML 将添加对 CustomControlLibrary 命名空间的引用并添加 CustomControl1 自定义控件。 该按钮出现在“设计”视图中,并显示相应文本,表明该按钮处于设计模式下。 如果该按钮未出现,则可能需要单击设计器顶部的信息栏以重新加载视图。
<Window x:Class="DemoApplication.MainWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" xmlns:my="clr-namespace:CustomControlLibrary;assembly=CustomControlLibrary"> <Grid> <my:CustomControl1 Margin="30,30,30,30" Name="customControl11"></my:CustomControl1> </Grid> </Window>
在设计视图中选择该控件。
在**“属性”窗口中,找到“文本”**类别。
您应该看到一个用于指定文本属性的用户界面,并且它不同于其他控件。 可以从下拉列表中选择字体名称和字体大小。 可通过选择复选框来指定粗体和斜体。
对此类别中表示的属性进行更改。 请注意,它们的更改反映在控件中。