演练:实现颜色编辑器

[本文档仅供预览,在以后的发行版中可能会发生更改。包含的空白主题用作占位符。]

适用于 Visual Studio 的 WPF 设计器 的扩展性模型在 " 属性 " 窗口允许您创建属性的自定义值编辑器在设计时。 编辑器可以是内联编辑器,可以直接编辑值在 " 属性 " 窗口或扩展编辑器,使您能够编辑属性提供其他用户在 " 属性 " 窗口外部。 为了演示如何创建扩展编辑器,本演练提供了为控件的 background 属性创建一个颜色编辑器的分步过程。 此扩展编辑器在 " 属性 " 窗口的内联编辑器中打开。

在本演练中,您将执行下列任务:

  • 创建 WPF 自定义控件项目。

  • 创建充当扩展编辑器的用户控件。

  • 创建可用来在 " 属性 " 窗口中编辑属性值并打开扩展编辑器的内联编辑器。

  • 创建从继承 ExtendedPropertyValueEditor 用于连接编辑到类希望提供自定义编辑的类。

  • 创建实现接口 IProvideAttributeTable 以注册新的扩展编辑器的类。

  • 测试扩展编辑器在设计时。

系统必备

您需要以下组件来完成本演练:

  • Visual Studio 2012 RC.

创建自定义控件

第一步是为自定义控件创建项目。 该控件是带有少量设计时代码的一个简单的按钮,使用 GetIsInDesignMode 方法实现设计时行为。

创建自定义控件

  1. 创建新 WPF 自定义控件库项目。 CustomControlLibrary名为的 Visual C#。

    CustomControl1 的代码在代码编辑器中打开。

  2. 在 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))
                {
                    Background = Brushes.Red;
                }
            }
        }
    }
    
  3. 将项目的输出路径设置为 “bin \”。

  4. 生成解决方案。

创建扩展编辑器的用户控件

在前面过程中创建的控件是控件将要附加到的自定义颜色编辑器。 在此过程中,您将创建将充当扩展编辑器的另一个用户控件。

创建将充当扩展编辑器的用户控件

  1. 添加一个名为 CustomControlLibrary.Design 的 Visual C# 的新 WPF 自定义控件库项目添加到解决方案。

    CustomControl1 的代码在代码编辑器中打开。

  2. 解决方案资源管理器,从 CustomControlLibrary.Design 项目中删除 CustomControl1 文件。

  3. 添加对以下程 WPF Designer 程序集。

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  4. 添加对 CustomControlLibrary 项目。

  5. 将项目的输出路径设置为 “ \ CustomControlLibrary \ bin \”。 这在同一文件夹使控件的程序集和元数据程序集,使设计器的元数据发现。

  6. 将名为 ColorsList 的新类向 CustomControlLibrary.Design 项目。

  7. 在 ColorsList的代码编辑器中,用以下代码替换自动生成的代码。

    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Media;
    using System.Reflection;
    using System.Collections.ObjectModel;
    
    namespace CustomControlLibrary.Design
    {
        public class ColorsList : ObservableCollection<Color>
        {
            public ColorsList()
            {
                Type type = typeof(Colors);
                foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.Static))
                {
                    if (propertyInfo.PropertyType == typeof(Color))
                    {
                        Add((Color)propertyInfo.GetValue(null, null));
                    }
                }
            }
        }
    }
    
  8. 添加新用户控件 (wpf) 名为 ColorsListControl 向 CustomControlLibrary.Design 项目。

    ColorsListControl.xaml 的代码将在设计器中打开。

  9. 在 ColorsListControl.xaml 的 XAML 视图中,用以下 XAML 替换自动生成的 XAML。

        <UserControl x:Class="CustomControlLibrary.Design.ColorsListControl"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Local="clr-namespace:CustomControlLibrary.Design" 
        xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design.Interaction"
        Height="184" Width="260" Background="White">
        <UserControl.Resources>
            <Local:ColorsList x:Key="colors"/>
            <Style TargetType="{x:Type Button}">
                <EventSetter Event="Click" Handler="ItemsControl_Click"/>
            </Style>
        </UserControl.Resources>
    
        <ItemsControl 
            ItemsSource="{Binding Source={StaticResource colors}}" 
            HorizontalContentAlignment="Stretch" 
            VerticalContentAlignment="Stretch" 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch">
            <ItemsControl.Template>
                <ControlTemplate TargetType="ItemsControl">
                    <Border CornerRadius="5" >
                        <WrapPanel Orientation="Horizontal"
                                   VerticalAlignment="Center"
                                   HorizontalAlignment="Center">
                            <ScrollViewer>
                                <ItemsPresenter/>
                            </ScrollViewer>
                        </WrapPanel>
                    </Border>
                </ControlTemplate>
            </ItemsControl.Template>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Tag="{Binding}" Command="{x:Static PropertyEditing:PropertyValueEditorCommands.ShowInlineEditor}">
                        <Button.Template>
                            <ControlTemplate>
                                <Border Width="30" Height="30" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                                    <Rectangle Width="22" Height="22" ToolTip="{Binding}">
                                        <Rectangle.Fill>
                                            <SolidColorBrush Color="{Binding}"/>
                                        </Rectangle.Fill>
                                    </Rectangle>
                                </Border>
                            </ControlTemplate>
                        </Button.Template>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </UserControl>
    
  10. 解决方案资源管理器,展开 ColorsListControl.xaml 并打开 ColorsListControl.xaml.cs。

  11. 在 ColorsListControl的代码编辑器中,用以下代码替换自动生成的代码。

    using System;
    using System.Linq;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    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.Design
    {
        public partial class ColorsListControl : System.Windows.Controls.UserControl
        {
            public ColorsListControl()
            {
                InitializeComponent();
            }
    
            public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register("SelectedColor", typeof(Color), typeof(ColorsListControl), new FrameworkPropertyMetadata(null));
            public Color SelectedColor
            {
                get { return (Color)base.GetValue(SelectedColorProperty); }
                set { base.SetValue(SelectedColorProperty, value); }
            }
    
            public static readonly DependencyProperty SelectedBrushProperty = DependencyProperty.Register("SelectedBrush", typeof(SolidColorBrush), typeof(ColorsListControl), new FrameworkPropertyMetadata(null));
            public SolidColorBrush SelectedBrush
            {
                get { return (SolidColorBrush)base.GetValue(SelectedBrushProperty); }
                set { base.SetValue(SelectedBrushProperty, value); }
            }
    
            private void ItemsControl_Click(object sender, RoutedEventArgs e)
            {
                SelectedColor = (Color)((Button)sender).Tag;
                SelectedBrush = new SolidColorBrush(SelectedColor);
            }
        }
    }
    
  12. 生成解决方案。

  13. 在设计器中重新加载 ColorsListControl.xaml,您应当看到扩展编辑器 UI 显示在 " 设计 " 视图。

为颜色编辑器创建模板

您的颜色编辑器的内联编辑器不如扩展编辑器复杂的,可以用 XAML 数据模板创建。 还将创建指定使用用户控件上一过程中创建的扩展编辑器的数据模板。

为颜色编辑器创建模板

  1. 将名为 EditorResources 的新类向 CustomControlLibrary.Design 项目。

  2. 在 EditorResources的代码编辑器中,用以下代码替换自动生成的代码。

    namespace ExtendedEditorNamespace
    {
        using System;
        using System.Collections.Generic;
        using System.Text;
        using System.Windows;
        public partial class EditorResources : ResourceDictionary {
            public EditorResources()
                : base()
            {
                InitializeComponent();
            }
        }
    }
    
  3. 项目 菜单上,单击 添加资源字典

  4. 将该文件命名为 EditorResources.xaml 并单击 add

    EditorResources.xaml 的代码将在设计器中打开。

  5. 在 EditorResources.xaml 的 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">
    
        <DataTemplate x:Key="BrushExtendedEditorTemplate">
            <Local:ColorsListControl SelectedBrush="{Binding Value, Mode=TwoWay}"/>
        </DataTemplate>
    
    
        <DataTemplate x:Key="BrushInlineEditorTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <TextBox Grid.Column="0" Text="{Binding StringValue}"/>
                <PropertyEditing:EditModeSwitchButton Grid.Column="1"/>
            </Grid>
        </DataTemplate>
    
    </ResourceDictionary>
    
  6. 生成解决方案。

封装模板并注册编辑器

可以在完成。 您已经创建了颜色编辑器的扩展和内联编辑器,可以创建封装它们并注册它们与您的自定义控件的类。

封装并注册编辑器

  1. 将名为 BrushExtendedEditor 的新类向 CustomControlLibrary.Design 项目。

  2. 在 BrushExtendedEditor的代码编辑器中,用以下代码替换自动生成的代码。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Windows.Design.PropertyEditing;
    using System.Windows;
    
    namespace CustomControlLibrary.Design
    {
        public class BrushExtendedEditor : ExtendedPropertyValueEditor
        {
            private EditorResources res = new EditorResources();
    
            public BrushExtendedEditor()
            {
                this.ExtendedEditorTemplate = res["BrushExtendedEditorTemplate"] as DataTemplate;
                this.InlineEditorTemplate = res["BrushInlineEditorTemplate"] as DataTemplate;
            }
        }
    }
    
  3. 将名为 Metadata 的新类向 CustomControlLibrary.Design 项目。

  4. 在 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),
                        "Background",
                        PropertyValueEditor.CreateEditorAttribute(
                            typeof(BrushExtendedEditor)));
    
                    return builder.CreateTable();
                }
            }
        }
    }
    
  5. 生成解决方案。

测试颜色编辑器

您完成创建自己的颜色编辑器。 现在剩下的工作就是对其进行测试。 若要测试您的编辑将添加 WPF 应用程序项目添加到解决方案并添加您的自定义控件。 然后在 " 属性 " 窗口中更改 background 您将在操作中看到新编辑器。

测试颜色编辑器

  1. 添加一个名为 DemoApplication 的 Visual C# 的新 WPF 应用程序项目添加到解决方案。

    在 MainWindow.xaml WPF Designer打开。

  2. 添加对 CustomControlLibrary 项目。

  3. 在 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>
    
  4. 在设计器视图中,选择控件。

  5. 属性 窗口,请在 背景 单击属性旁边的下拉按钮。 将显示一个可视化颜色编辑器 (而不是默认的颜色。

  6. 选择一种颜色从编辑器。 您的自定义控件背景变成该颜色。

请参见

任务

演练:实现内联值编辑器

如何:创建值编辑器

其他资源

创建自定义编辑器

WPF 设计器扩展性