共用方式為


逐步解說:建立分類編輯器

WPF Designer for Visual Studio 的擴充性模型可讓您為屬性分類建立自訂編輯器,稱為分類編輯器。 分類編輯器可讓您提供自訂使用者介面。以便使用者編輯屬於單一分類的相關屬性,例如與文字相關的屬性。 在本逐步解說中,您將建置分類編輯器,以便使用者編輯控制項的文字相關屬性。

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

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

  • 建立分類編輯器,可用來編輯該控制項的文字相關屬性。

  • 建立繼承自 CategoryEditor 的類別,以代表控制項的分類編輯器。

  • 建立實作 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))
                {
                    Content = "In design mode";
                }
            }
        }
    }
    
  3. 將專案的輸出路徑設定為 "bin\"。

  4. 建置方案。

建立類別來封裝屬性資訊

您將建立的分類編輯器需要一些字型和相關屬性的資訊,因此,您會建立類別來封裝這些資訊。 此類別將當做分類編輯器的資料來源。

若要建立封裝字型屬性資訊的類別

  1. 將 Visual C# 中名為 CustomControlLibrary.Design 的新 WPF 自訂控制項程式庫專案加入到方案中。

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

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

  3. 在 [方案總管] 中,從 CustomControlLibrary.Design 專案刪除 Themes 資料夾。

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

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  5. 加入 CustomControlLibrary 專案的參考。

  6. 將專案的輸出路徑設定為 ".. \CustomControlLibrary\bin\"。 這麼做會將控制項的組件和中繼資料組件保留在同一個資料夾中,讓設計工具可進行中繼資料探索。

  7. 將名為 FontList 的新類別加入到 CustomControlLibrary.Design 專案。

  8. 在 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 資料範本建立。 這會是繫結至數個文字相關屬性的簡單使用者介面。

若要建立分類編輯器的樣板

  1. 將名為 EditorResources 的新類別加入到 CustomControlLibrary.Design 專案。

  2. 在 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();
            }
        }
    }
    
  3. 按一下 [專案] 功能表上的 [加入資源字典]。

  4. 將檔案命名為 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">
        <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>
    
  6. 建置方案。

封裝樣板和註冊分類編輯器

現在您已為分類編輯器建立了樣板,接下來就必須建立繼承自 CategoryEditor 的類別,以便使用樣板做為自訂編輯器,而且必須註冊新的分類編輯器。

若要封裝和註冊分類編輯器

  1. 將名為 TextCategoryEditor 的新類別加入到 CustomControlLibrary.Design 專案。

  2. 在 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"; }
            }
        }
    }
    
  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),
                        new EditorAttribute(
                            typeof(TextCategoryEditor), 
                            typeof(TextCategoryEditor)));
                    return builder.CreateTable();
                }
            }
        }
    }
    
  5. 建置方案。

測試分類編輯器

分類編輯器現在已經完成並可以使用。 接著就要進行最後測試。 為測試分類編輯器,您會將 WPF 應用程式加入到專案、將自訂控制項加入到 WPF 應用程式,然後檢視分類編輯器的實際運作。

若要測試分類編輯器

  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. 在 [屬性] 視窗中,找到 [Text] 分類。

    您應會看到指定 Text 屬性的使用者介面,這與其他控制項都不同。 您可以從下拉式清單選取字型名稱和字型大小。 您可以選取核取方塊來指定粗體和斜體。

  6. 變更出現在此分類中的屬性。 請注意,它們的變更會反映在控制項中。

請參閱

工作

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

HOW TO:建立值編輯器

其他資源

建立自訂編輯器

WPF 設計工具擴充性