Tutorial: Implementar un editor de colores
Actualización: noviembre 2007
El modelo de extensibilidad de Windows Presentation Foundation (WPF) Designer for Visual Studio le permite crear editores de valores personalizados para propiedades en la ventana Propiedades en tiempo de diseño. Los editores pueden ser editores insertados, que permiten modificar valores directamente en la ventana Propiedades o editores extendidos, que permiten proporcionar una interfaz de usuario adicional para modificar una propiedad fuera de la ventana Propiedades. Para mostrar cómo se crea un editor extendido, en este tutorial se ofrecen los procedimientos paso a paso para crear un editor de colores para la propiedad Background de un control. Este editor extendido se abre desde un editor insertado en la ventana Propiedades.
En este tutorial realizará las siguientes tareas:
Crear un proyecto de control personalizado de WPF.
Cree un control de usuario que actuará como el editor extendido.
Cree un editor insertado que se pueda utilizar para modificar el valor de la propiedad en la ventana Propiedades y abrir el editor extendido.
Cree una clase que herede de ExtendedPropertyValueEditor que se utiliza para conectar los editores con la clase para la que desea proporcionar la edición personalizada.
Cree una clase que herede de IRegisterMetadata para registrar el nuevo editor extendido.
Pruebe el editor extendido en tiempo de diseño.
Requisitos previos
Necesita los componentes siguientes para completar este tutorial:
- Visual Studio 2008.
Crear el control personalizado
El primer paso consiste en crear el proyecto para el control personalizado. El control es un botón simple con poco código en tiempo de diseño, que utiliza el método GetIsInDesignMode para implementar un comportamiento en tiempo de diseño.
Para crear el control personalizado
Cree un nuevo proyecto de biblioteca de controles personalizados de WPF en Visual C# denominado CustomControlLibrary.
El código de CustomControl1 se abre en el editor de código.
Agregue una referencia al siguiente ensamblado de WPF Designer.
- Microsoft.Windows.Design
En el editor de código para CustomControl1, reemplace el código del espacio de nombres CustomControlLibrary por el siguiente código:
public class CustomControl1 : Button { public CustomControl1() { if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) { Background = Brushes.Red; } } }
Establezca la ruta de acceso de los resultados del proyecto en "bin\".
Genere la solución.
Crear el control de usuario para el editor extendido
El control que creó en el procedimiento anterior es el control al que va a asociar el editor de colores personalizado. En este procedimiento creará otro control de usuario que actuará como el editor extendido.
Para crear un control de usuario que actuará como el editor extendido
Agregue a la solución un nuevo proyecto de biblioteca de controles personalizados de WPF en Visual C# denominado CustomControlLibrary.Design.
El código de CustomControl1 se abre en el editor de código.
En el Explorador de soluciones, elimine el archivo CustomControl1 del proyecto CustomControlLibrary.Design.
Agregue una referencia al siguiente ensamblado de WPF Designer.
- Microsoft.Windows.Design
Agregue una referencia al proyecto CustomControlLibrary.
Establezca la ruta de acceso de los resultados del proyecto en ".. \CustomControlLibrary\bin\". De este modo, el ensamblado del control y el ensamblado de metadatos permanecen en la misma carpeta, lo que permite que los diseñadores detecten los metadatos.
Agregue al proyecto CustomControlLibrary.Design una nueva clase denominada ColorsList.
En el editor de código para ColorsList, reemplace el código generado automáticamente por el código siguiente.
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)); } } } } }
Agregue un nuevo elemento de control de usuario (WPF) denominado ColorsListControl al proyecto CustomControlLibrary.Design.
El código para ColorsListControl.xaml se abre en el diseñador.
En la vista XAML de ColorsListControl.xaml, reemplace el XAML generado automáticamente por el XAML siguiente.
<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>
En el Explorador de soluciones, expanda ColorsListControl.xaml y abra ColorsListControl.xaml.cs.
En el editor de código para ColorsListControl, reemplace el código generado automáticamente por el código siguiente.
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(); } } }
Genere la solución.
Vuelva a cargar ColorsListControl.xaml en el diseñador y deberá ver aparecer la interfaz de usuario del editor extendido en la vista Diseño.
Crear las plantillas para el editor de colores
El editor insertado del editor de colores es menos complejo que el editor extendido y se puede crear con una plantilla de datos XAML. También creará una plantilla de datos para el editor extendido que especifica que se use el control de usuario que creó en el procedimiento anterior.
Para crear la plantilla para el editor de colores
Agregue al proyecto CustomControlLibrary.Design una nueva clase denominada EditorResources.
En el editor de código para EditorResources, reemplace el código generado automáticamente por el código siguiente.
namespace ExtendedEditorNamespace { using System; using System.Collections.Generic; using System.Text; using System.Windows; public partial class EditorResources : ResourceDictionary { public EditorResources() : base() { InitializeComponent(); } } }
En el menú Proyecto, haga clic en Agregar diccionario de recursos.
Asigne al archivo el nombre de EditorResources.xaml y haga clic en Agregar.
El código para EditorResources.xaml se abre en el diseñador.
En la vista XAML de EditorResources.xaml, reemplace el XAML generado automáticamente por el XAML siguiente.
<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>
Genere la solución.
Encapsular las plantillas y registrar los editores
El trabajo más difícil ya ha terminado. Ahora que ha creado las plantillas del editor extendido y del editor insertado para el editor de colores, puede crear una clase que los encapsula y después los registra con el control personalizado.
Para encapsular y registrar los editores
Agregue al proyecto CustomControlLibrary.Design una nueva clase denominada BrushExtendedEditor.
En el editor de código para BrushExtendedEditor, reemplace el código generado automáticamente por el código siguiente.
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; } } }
Agregue al proyecto CustomControlLibrary.Design una nueva clase denominada Metadata.
En el editor de código para Metadata, reemplace el código generado automáticamente por el código siguiente.
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()); } } }
Genere la solución.
Probar el editor de colores
Acaba de terminar de crear el editor de colores. Lo único que queda ahora es probarlo. Para probar el editor agregará a la solución un proyecto de aplicación de WPF y agregará el control personalizado. A continuación cambiará el fondo en la ventana Propiedades y verá el nuevo editor en acción.
Para probar el editor de colores
Agregue a la solución un nuevo proyecto de aplicación de WPF en Visual C# denominado DemoApplication.
Window1.xaml se abrirá en el WPF Designer.
Agregue una referencia al proyecto CustomControlLibrary.
En la vista XAML de Window1.xaml, reemplace el XAML generado automáticamente por el XAML siguiente. Este XAML agrega una referencia al espacio de nombres CustomControlLibrary y agrega el control personalizado CustomControl1. El botón aparece en la vista Diseño con un fondo rojo, que indica que el control se encuentra en modo de diseño. Si el botón no aparece, es posible que tenga que hacer clic en la barra de información situada en la parte superior del diseñador para volver a cargar la vista.
<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>
Seleccione el control en la vista Diseño.
En la ventana Propiedades, haga clic en el botón de lista desplegable situado junto a la propiedad Background. Se mostrará un editor de colores visual en lugar de la lista predeterminada de colores.
Seleccione un color del editor. El color de fondo del control personalizado cambiará a ese color.
Vea también
Tareas
Tutorial: Implementar un editor de valores insertados
Cómo: Crear un editor de valores