Пошаговое руководство. Реализация редактора цвета
Обновлен: Ноябрь 2007
Модель расширяемости Windows Presentation Foundation (WPF) для Visual Studio (конструктор) позволяет создавать специальные редакторы значений для свойств в окне «Свойства» во время разработки. Это могут быть встроенные редакторы, которые позволяют изменять значения непосредственно в окне «Свойства», или расширенными редакторами, которые позволяют предоставлять дополнительный пользовательский интерфейс для редактирования свойств вне окна «Свойства». Для демонстрации создания расширенного редактора в данном пошаговом руководстве представлены пошаговые инструкции по созданию редактора цвета для свойства Background элемента управления. Этот расширенный редактор открывается из встроенного редактора окна «Свойства».
В данном пошаговом руководстве нужно выполнить следующие задачи:
создать проект пользовательского элемента управления WPF;
создать пользовательский элемент управления, который будет работать как расширенный редактор;
создать встроенный редактор, который может использоваться для редактирования значения свойства в окне «Свойства» и открытия расширенного редактора;
Создание класса, производного от интерфейса ExtendedPropertyValueEditor, который используется для подключения редакторов к классу, для которого нужно предоставить функции редактирования;
создать класс, наследуемый от IRegisterMetadata, для регистрации нового расширенного редактора;
протестировать расширенный редактор во время разработки.
Обязательные компоненты
Для прохождения этого пошагового руководства необходимы следующие компоненты:
- Visual Studio 2008.
Создание пользовательского элемента управления
Первым этапом является создание проекта для пользовательского элемента управления. Элементом управления является простая кнопка с небольшим объемом кода времени разработки, в котором для реализации поведения времени разработки используется метод GetIsInDesignMode.
Чтобы создать пользовательский элемент управления
Создайте новый проект библиотеки пользовательских элементов управления WPF в Visual C# с именем CustomControlLibrary.
Код для CustomControl1 откроется в редакторе кода.
Добавьте ссылку на следующую сборку WPF (конструктор):
- Microsoft.Windows.Design.
В редакторе кода для CustomControl1 замените код в пространстве имен CustomControlLibrary следующим кодом:
public class CustomControl1 : Button { public CustomControl1() { if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) { Background = Brushes.Red; } } }
Задайте выходной путь проекта как «bin\».
Выполните построение решения.
Создание пользовательского элемента управления для расширенного редактора
Элемент управления, созданный в предыдущей процедуре, является элементом управления, к которому будет присоединен настраиваемый редактор цвета. В этой процедуре предстоит создать другой пользовательский элемент управления, который будет работать как расширенный редактор.
Чтобы создать пользовательский элемент управления, который будет работать как расширенный редактор
Добавьте к решению новый проект библиотеки пользовательских элементов управления WPF в Visual C# с именем CustomControlLibrary.Design.
Код для CustomControl1 откроется в редакторе кода.
В обозревателе решений удалите файл CustomControl1 из проекта CustomControlLibrary.Design.
Добавьте ссылку на следующую сборку WPF (конструктор):
- Microsoft.Windows.Design.
Добавьте ссылку на проект CustomControlLibrary.
Задайте выходной путь проекта как «..\CustomControlLibrary\bin\». При этом сборка элемента управления сохраняется в одной папке со сборкой метаданных, что позволяет разработчикам выполнять обнаружение метаданных.
Добавьте новый класс с именем ColorsList в проект CustomControlLibrary.Design.
В редакторе кода для 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 ColorsListNamespace { 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)); } } } } }
Добавьте новый пользовательский элемент управления (WPF) с именем ColorsListControl в проект CustomControlLibrary.Design.
Код для файла ColorsListControl.xaml откроется в конструкторе.
В представлении XAML для ColorsListControl.xaml замените автоматически созданный XAML-код на следующий XAML-код.
<UserControl x:Class="ColorsListNamespace.ColorsListControl" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:Local="clr-namespace:ColorsListNamespace" xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design" 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>
В обозревателе решений разверните ColorsListControl.xaml и откройте файл ColorsListControl.xaml.cs.
В редакторе кода для 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 ColorsListNamespace { public partial class ColorsListControl : System.Windows.Controls.UserControl { public static readonly RoutedEvent ClosePopupEvent = EventManager.RegisterRoutedEvent("ClosePopupEvent", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(ColorsListControl)); 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); } } public event RoutedEventHandler ClosePopup { add { AddHandler(ClosePopupEvent, value); } remove { RemoveHandler(ClosePopupEvent, value); } } protected void RaiseClosePopupEvent() { RoutedEventArgs newEventArgs = new RoutedEventArgs(ColorsListControl.ClosePopupEvent); RaiseEvent(newEventArgs); } private void ItemsControl_Click(object sender, RoutedEventArgs e) { SelectedColor = (Color)((Button)sender).Tag; SelectedBrush = new SolidColorBrush(SelectedColor); RaiseClosePopupEvent(); } } }
Выполните построение решения.
Перезагрузите ColorsListControl.xaml в конструкторе, в окне должен отобразиться пользовательский интерфейс расширенного редактора.
Создание шаблонов для редактора цвета
Встроенный редактор для редактора цвета является менее сложным, чем расширенный редактор, и может создаваться с помощью шаблона данных XAML. Шаблон данных также создается для расширенного редактора, задающего использование пользовательского элемента управления, созданный в предыдущей процедуре.
Чтобы создать шаблон для редактора цвета
Добавьте новый класс с именем EditorResources в проект CustomControlLibrary.Design.
В редакторе кода для EditorResources замените автоматически создаваемый код на следующий код.
namespace ExtendedEditorNamespace { 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 для 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" xmlns:Local="clr-namespace:ColorsListNamespace" xmlns:Media="clr-namespace:System.Windows.Media;assembly=PresentationCore" xmlns:sys="clr-namespace:System;assembly=mscorlib" x:Class="ExtendedEditorNamespace.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>
Выполните построение решения.
Инкапсуляция шаблонов и регистрация редакторов
Наиболее сложные этапы завершены. Теперь, создав шаблоны расширенного и встроенного редакторов для редактора цвета, можно создать класс, инкапсулирующий их и затем регистрирующий их в пользовательском элементе управления.
Чтобы осуществить инкапсуляцию и регистрацию редакторов
Добавьте новый класс с именем BrushExtendedEditor в проект CustomControlLibrary.Design.
В редакторе кода для BrushExtendedEditor замените автоматически создаваемый код на следующий код.
namespace ExtendedEditorNamespace { using System; using System.Collections.Generic; using System.Text; using Microsoft.Windows.Design.PropertyEditing; using System.Windows; using ExtendedEditorNamespace; public class BrushExtendedEditor : ExtendedPropertyValueEditor { private EditorResources res = new EditorResources(); public BrushExtendedEditor() { this.ExtendedEditorTemplate = res["BrushExtendedEditorTemplate"] as DataTemplate; this.InlineEditorTemplate = res["BrushInlineEditorTemplate"] as DataTemplate; } } }
Добавьте новый класс с именем Metadata в проект CustomControlLibrary.Design.
В редакторе кода для Metadata замените автоматически создаваемый код на следующий код.
namespace ExtendedEditorNamespace { 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; // Container for any general design-time metadata that we want to initialize. // Designers will look for a type in the design-time assembly that implements IRegisterMetadata. // If found, they will instantiate it and call its Register() method automatically. internal class Metadata : IRegisterMetadata { // Called by Cider to register any design-time metadata public void Register() { AttributeTableBuilder builder = new AttributeTableBuilder(); builder.AddCustomAttributes (typeof(CustomControl1), Control.BackgroundProperty, PropertyValueEditor.CreateEditorAttribute( typeof(BrushExtendedEditor))); MetadataStore.AddAttributeTable(builder.CreateTable()); } } }
Выполните построение решения.
Тестирование редактора цвета
Создание редактора цвета завершено. Следующий этап — тестирование редактора. Чтобы проверить редактор, следует добавить в решение проект приложения WPF и добавить созданный пользовательский элемент управления. Затем нужно будет изменить свойство Background в окне «Свойства» и посмотреть новый редактор в действии.
Чтобы протестировать редактор цвета
Добавьте в решение новый проект приложения WPF в Visual C# с именем DemoApplication.
Файл Window1.xaml откроется в конструкторе WPF (конструктор).
Добавьте ссылку на проект CustomControlLibrary.
В представлении XAML для Window1.xaml замените автоматически созданный XAML-код на следующий XAML-код. В этом коде XAML добавляется ссылка на пространство имен CustomControlLibrary и добавляется пользовательский элемент управления CustomControl1. Кнопка появляется в представлении «Конструктор» с красным фоном, обозначающим, что элемент управления находится в режиме разработки. Если кнопка не отображается, щелкните панель информации в верхней части конструктора для перезагрузки представления.
<Window x:Class="DemoApplication.Window1" 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">Button</my:CustomControl1> </Grid> </Window>
В представлении «Конструктор» выделите элемент управления.
В окне Свойства нажмите кнопку раскрывающегося списка свойства Background. Отобразится визуальный редактор цвета вместо списка цветов по умолчанию.
Выберите цвет из редактора. Фон пользовательского элемента управления изменится на этот цвет.
См. также
Задачи
Пошаговое руководство. Реализация встроенного редактора значений
Практическое руководство. Создание редактора значений