逐步解說:實作色彩編輯器

WPF Designer for Visual Studio 的擴充性模型可讓您在設計階段為 [屬性] 視窗中的屬性建立自訂值編輯器。 編輯器可以是內嵌編輯器,以便直接在 [屬性] 視窗中編輯值,也可以是擴充編輯器,能讓您提供額外的 UI,在 [屬性] 視窗以外編輯屬性。 為了示範如何建立擴充編輯器,本逐步解說提供如何為控制項的 Background 屬性建立色彩編輯器的逐步程序。此擴充編輯器是從 [屬性] 視窗中的內嵌編輯器開啟。

在這個逐步解說中,您會執行下列工作:

  • 建立 WPF 自訂控制項專案。

  • 建立要當做擴充編輯器的使用者控制項。

  • 建立內嵌編輯器,這可用來在 [屬性] 視窗中編輯屬性值,以及開啟擴充編輯器。

  • 建立繼承自 ExtendedPropertyValueEditor 的類別,用來將編輯器連接至要為其提供自訂編輯的類別。

  • 建立實作 IProvideAttributeTable 介面的類別,以註冊新的擴充編輯器。

  • 在設計階段測試擴充編輯器。

必要條件

您需要下列元件才能完成此逐步解說:

  • Visual Studio 2010。

建立自訂控制項

第一個步驟是為自訂控制項建立專案。 這個控制項是一個具有少量設計階段程式碼的簡易按鈕,這個程式碼使用 GetIsInDesignMode 方法來實作設計階段行為。

建立自訂控制項

  1. 在 Visual C# 中建立名為 CustomControlLibrary 的新 WPF 自訂控制項程式庫。

    CustomControl1 的程式碼隨即在 [程式碼編輯器] 中開啟。

  2. 在 CustomControl1 的 [程式碼編輯器] 中,將 CustomControlLibrary 命名空間 (Namespace) 中的程式碼替換成下列程式碼:

    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. 將 Visual C# 中名為 CustomControlLibrary.Design 的新 WPF 自訂控制項程式庫專案加入到方案中。

    CustomControl1 的程式碼隨即在 [程式碼編輯器] 中開啟。

  2. 在 [方案總管] 中,從 CustomControlLibrary.Design 專案刪除 CustomControl1 檔案。

  3. 加入下列 WPF 設計工具組件的參考。

    • 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. 將名為 ColorsListControl 的新使用者控制項 (WPF) 加入到 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,然後按一下 [加入]。

    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. 將 Visual C# 中名為 DemoApplication 的新 WPF 應用程式專案加入至方案。

    MainWindow.xaml 隨即在 WPF 設計工具中開啟。

  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. 在 [屬性] 視窗中,按一下 [Background] 屬性旁的下拉按鈕。 這時會顯示視覺色彩編輯器,而非預設色彩清單。

  6. 從編輯器選取色彩。 自訂控制項的背景就會變更為該色彩。

請參閱

工作

逐步解說:實作內嵌值編輯器

HOW TO:建立值編輯器

其他資源

建立自訂編輯器

WPF 設計工具擴充性