Compartir a través de


Tutorial: Crear un editor de categorías

Actualización: noviembre 2007

El modelo de extensibilidad para Windows Presentation Foundation (WPF) Designer for Visual Studio permite crear editores personalizados para categorías de propiedades, denominados editores de categorías. Los editores de categorías ofrecen la posibilidad de proporcionar una interfaz de usuario personalizada que permite al usuario editar propiedades relacionadas pertenecientes a la misma categoría, como las propiedades relativas al texto. En este tutorial, se crea un editor de categorías que permite a los usuarios editar las propiedades relativas al texto de un control.

En este tutorial realizará las siguientes tareas:

  • Crear un proyecto de control personalizado de WPF.

  • Crear un editor de categorías que se puede usar para editar las propiedades relativas al texto de ese control.

  • Crear una clase que hereda de CategoryEditor y que representa el editor de categorías del control.

  • Crear una clase que hereda de IRegisterMetadata a fin de registrar el nuevo editor extendido.

  • Probar el editor de categorías 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

  1. 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.

  2. Agregue una referencia al siguiente ensamblado de WPF Designer.

    • Microsoft.Windows.Design
  3. 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))
            {
                Content = "I'm in design mode";
            }
        }
    }
    
  4. Establezca la ruta de acceso de salida del proyecto en "bin\".

  5. Genere la solución.

Crear una clase para encapsular la información de propiedades

El editor de categorías que se va a crear requiere información sobre fuentes y propiedades asociadas, de modo que es preciso crear una clase que encapsule dicha información. El editor de categorías utilizará esta clase como origen de datos.

Para crear una clase que encapsule la información de propiedades de fuentes

  1. 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.

  2. En el Explorador de soluciones, elimine el archivo CustomControl1 del proyecto CustomControlLibrary.Design.

  3. En el Explorador de soluciones, elimine la carpeta Themes del proyecto CustomControlLibrary.Design.

  4. Agregue una referencia al siguiente ensamblado de WPF Designer.

    • Microsoft.Windows.Design
  5. Agregue una referencia al proyecto CustomControlLibrary.

  6. 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.

  7. Agregue al proyecto CustomControlLibrary.Design una nueva clase denominada FontList.

  8. En el editor de código para FontList, 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.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;
            }
        }
    
    }
    

Crear la plantilla para el editor de categorías

El editor de categorías se crea mediante una plantilla de datos XAML. Se trata de una interfaz de usuario sencilla enlazada a varias propiedades relativas al texto.

Para crear la plantilla para el editor de categorías

  1. Agregue al proyecto CustomControlLibrary.Design una nueva clase denominada EditorResources.

  2. En el editor de código para EditorResources, reemplace el código generado automáticamente por el código siguiente.

    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. En el menú Proyecto, haga clic en Agregar diccionario de recursos.

  4. Asigne al archivo el nombre de EditorResources.xaml y haga clic en Agregar.

  5. En la vista XAML de EditorResources, 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: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}}" 
                        DisplayMemberPath="FamilyNames.Values[0]"
                        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. Genere la solución.

Encapsular la plantilla y registrar el editor de categorías

Ahora que ha creado la plantilla del editor de categorías, debe crear una clase que hereda de CategoryEditor para utilizar la plantilla como un editor personalizado y debe registrar el nuevo editor de categorías.

Para encapsular y registrar el editor de categorías

  1. Agregue al proyecto CustomControlLibrary.Design una nueva clase denominada TextCategoryEditor.

  2. En el editor de código para TextCategoryEditor, reemplace el código generado automáticamente por el código siguiente.

    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. Agregue al proyecto CustomControlLibrary.Design una nueva clase denominada Metadata.

  4. En el editor de código para Metadata, reemplace el código generado automáticamente por el código siguiente.

    namespace CustomControlLibrary.Design
    {
        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 the WPF Designer to register any design-time metadata
            public void Register()
            {
                AttributeTableBuilder builder = new AttributeTableBuilder();
                builder.AddCustomAttributes
                    (typeof( CustomControl1), 
                    "Enter text",
                    PropertyValueEditor.CreateEditorAttribute(
                        typeof(TextCategoryEditor)));
                MetadataStore.AddAttributeTable(builder.CreateTable());
            }
        }
    }
    
  5. Genere la solución.

Probar el editor de categorías

El editor de categorías ya está completado y listo para su uso. Sólo queda probarlo. Para probar el editor de categorías, agregará al proyecto una aplicación de WPF, agregará el control personalizado a la aplicación de WPF y verá el editor de categorías en acción.

Para probar el editor de categorías

  1. 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.

  2. Agregue una referencia al proyecto CustomControlLibrary.

  3. 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 texto que indica que 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"></my:CustomControl1>
        </Grid>
    </Window>
    
  4. Seleccione el control en la vista Diseño.

  5. En la ventana Propiedades, busque la categoría Text.

    Debe aparecer una interfaz de usuario que permita especificar las propiedades de texto, distinta de los demás controles. Puede seleccionar un nombre y un tamaño de fuente en las listas desplegables. Puede especificar la negrita y la cursiva activando las casillas correspondientes.

  6. Modifique las propiedades representadas en esta categoría. Observe que los cambios se reflejan en el control.

Vea también

Tareas

Tutorial: Implementar un editor de colores

Cómo: Crear un editor de valores

Otros recursos

Crear editores personalizados

Extensibilidad de WPF Designer