Editores de propiedades de valor para los controles de Silverlight
Introducción
Esto es parte de la serie de cambios en el diseño de aplicación en tiempo de Silverlight Toolkit versión marzo 2009 . Este post trata sobre cómo mejorar la experiencia de edición de propiedades para los controles de Silverlight mediante el Editor del valor de la propiedad y el convertidor de tipos. Voy a empezar con la descripción de la arquitectura general de la edición de propiedades de WPF / Silverlight marco de extensibilidad de diseño, a continuación, utilizar ejemplos en Silverlight Toolkit versión marzo 2009 para demostrar cómo se hace, y problemas únicos / trucos en el desarrollo de Silverlight en tiempo de diseño.
Edición de la Propiedad Arquitectura
Visualmente editar las propiedades del objeto es una parte importante de los diseñadores. Los diseñadores generalmente no saben cómo hacer que las propiedades de tipo personalizado (estructura, clase o interfaz), y mucho menos para proporcionar una interfaz de edición de usuario agradable. Los desarrolladores de controles en general tienen que proporcionar TypeConverter , PropertyValueEditor , o ambos, para proporcionar la representación / serialización edición de la interfaz de usuario y XAML para las propiedades de tipos personalizados.
El marco de extensibilidad diseñador define tres tipos de editor de valor de la propiedad: editor en línea, editor extendido, y el editor de diálogo, cada uno lo implementa una clase:
Interfaz de usuario de edición de los editores se definen por DataTemplate . La propiedad que se está editando se expone al editor como DataContext de PropertyValue tipo. Editor de la interfaz de usuario por lo general se unen a la propiedad subyacente que está siendo editado a través de una de las tres propiedades de PropertyValue : Valor , StringValue , o colección .
PropertyValueEditor
PropertyValueEditor tiene un editor en línea único definido por InlineEditorTemplate propiedad. Editor en línea aparece en la ventana de propiedades. A continuación se muestra un ejemplo sencillo de InlineEditorTemplate que utiliza un cuadro de texto para mostrar y editar una propiedad:
x:Key ="TextBoxEditor" > <X DataTemplate: Key = "TextBoxEditor"> Text ="{Binding Path=Value}" /> <Texto TextBox = "{Binding Path = valor}" /> > </ DataTemplate>
ExtendedPropertyValueEditor
x:Key ="inlineEditor" > < Button Content ="..." Command ="{x:Static <DataTemplate x: Key = "inlineEditor"> Contenido <="..." botón de comando = "{x: Estático > Path = valor} "/> </ DataTemplate>
DialogPropertyValueEditor
DialogPropertyValueEditor tiene dos editores también: el editor en línea heredado de PropertyValueEditor , y un editor de diálogo adicionales definidos por DialogEditorTemplate propiedad. El editor de diálogo es por lo general apareció por el editor en línea a través de PropertyValueEditorCommands . ShowDialogEditor comando. A continuación se muestra un ejemplo sencillo:
x:Key ="inlineEditor" > < Button Content ="..." Command ="{x:Static <DataTemplate x: Key = "inlineEditor"> Contenido <="..." botón de comando = "{x: Estático ="Center" HorizontalAlignment ="Right" Margin ="0,0,4,4" /> < TextBox Text ="{Binding Nombre: "VerticalAlignment =" center "HorizontalAlignment =" right "Margin =" 0,0,4,4 "/> <texto TextBox =" {Binding
Implementar Editor de propiedades personalizadas
Para implementar un editor de propiedades personalizado para un control de Silverlight:
- implementar una clase de editor de propiedades personalizado
- heredan de PropertyValueEditor, ExtendedPropertyValueEditor o DialogPropertyValueEditor
- conjunto de su plantilla de editor (s): InlineEditorTemplate , ExtendedEditorTemplate , y / o DialogEditorTemplate ;
- Asociar el editor de propiedades personalizado con una propiedad de un control de Silverlight a través de una llamada AddCustomAttributes, algo así como
attributeTableBuilder.AddCustomAttributes ( typeof (MyControl), "MyProperty", (MyValueEditor))); PropertyValueEditor.CreateEditorAttribute nuevo (typeof (MyValueEditor)));
- Un editor de propiedades de valor aplicado correctamente debe cumplir los siguientes requisitos:
- El editor de valor de la propiedad debe ser diseñado de manera que el editor en línea y las partes extendido editor puede ser usado de forma independiente.
- Un editor de valor de la propiedad no debe almacenar el estado. Los editores de propiedades de valor son apátridas, puede tener una caché mediante una aplicación de acogida, y pueden ser reutilizados a través de valores de las propiedades múltiples.
- Un editor de valor de la propiedad no debe asumir que sólo una parte editor de valor (ver / en línea / extensión) de control está activo en un momento dado. Por ejemplo, un cuadro de diálogo podría tener la parte de la vista, parte en línea, y la parte de interfaz de usuario activo extendido, al mismo tiempo.
- Un control implementado como parte de un editor de valor de la propiedad no debe almacenar el estado. Un control implementado como parte de un editor de valores no debe asumir que sólo estará vinculado a un valor de la propiedad. Los controles pueden ser reciclados para cambiar los valores de diferentes propiedades. Cualquier información que se almacena en caché debe limpiarse si el modelo de datos se actualiza.
- Un control implementado como parte de un editor de valor de la propiedad no debe hacer ninguna suposición sobre la máquina o sus controles primarios. Los mecanismos de comunicación sólo se debe utilizar es el PropertyValue modelo de datos, a través de la DataContext , y el conjunto de comandos estándar.
- Puede leer más sobre la arquitectura edición de propiedades y marco de diseño de ampliación en MSDN.
Referencia WPF y Silverlight Asambleas
Un conjunto de diseño es un conjunto de NET / WPF cargar con Visual Studio o de fusión, pero por lo general necesita hacer referencia a las asambleas Silverlight (al menos en el conjunto de control Silverlight que proporciona características de diseño de tiempo). Esto puede crear ambigüedad de referencia para el diseño de montaje: a veces debe hacer referencia al mismo tipo completo de WPF y Silverlight, por ejemplo System.Windows.FrameworkElement tanto en PresentationFramework.dll de WPF y Silverlight de System.Windows.dll. Para evitar la confusión de Visual Studio, puede utilizar alias extern para distinguir las referencias WPF y Silverlight.
Por ejemplo, véase la siguiente imagen para el proyecto de Controls.DataVisualization.Toolkit.Design en Silverlight 3 Toolkit en marzo 2009 Publicación :
- las referencias del proyecto, tanto PresentationFramework y System.Windows, pero System.Windows está bajo el alias de Silverlight, en vez de el alias predeterminado global. La referencia System.Windows bajo el alias de Silverlight se conserva en el archivo csproj de la siguiente manera.:
Include ="System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, processorArchitecture=MSIL" > <Referencia Include = "System.Windows, Version = 2.0.5.0, Culture = neutral, PublicKeyToken = 7cec85d7bea7798e, processorArchitecture = MSIL"> > False </ SpecificVersion > <SpecificVersion> false </ SpecificVersion> > ..\Binaries\System.Windows.dll </ HintPath > <HintPath> .. \ Binaries \ System.Windows.dll </ HintPath> > False </ Private > <Privado> false </ privado> > Silverlight </ Aliases > <Alias> Silverlight </ Alias> > </ Referencia>
- en el código fuente, añadimos
alias extern Silverlight; con SSW = Silverlight:: System.Windows;
y la referencia FrameworkElement Silverlight a través de SSW:: FrameworkElement.
TextBoxEditor
Hay un editor en línea en TextBoxEditor proyecto Controls.DataVisualization.Toolkit.Design para mostrar y editar la propiedad Título del tipo de objeto para [Area | Bar | burbuja | Columna | Línea | Pie | Dispersión] y controles en serie de gráficos, como se muestra a continuación:
Texto lleno en el campo Título de la ventana Propiedades de la derecha se muestra automáticamente en XAML y puntos de vista de diseño en el centro.
La implementación de TextBoxEditor seguido los pasos descritos anteriormente:
- TextBoxEditor es una subclase de PropertyValueEditor. En él se establecen InlineEditorTemplate en su constructor por defecto. Aquí, he utilizado el código en lugar de XAML para la construcción de la plantilla de datos , porque de alguna manera no puedo xaml para construir, y todo en XAML se puede escribir en C # de todos modos.
- Se asocia con Chart.Title en ChartMetadata.cs (ver tiempo de diseño implementación de características de Silverlight Toolkit para obtener más información sobre los archivos Metadata.cs *)
TextBoxEditor.cs:
/ / (C) Copyright Microsoft Corporation. / / Esta fuente está sujeto a la licencia pública de Microsoft (Ms-PL). / / Por favor, vea http://go.microsoft.com/fwlink/?LinkID=131993 para más detalles. / / Todos los demás derechos reservados. using System; utilizando Microsoft.Windows.Design.PropertyEditing; utilizando System.Windows; utilizando System.Windows.Data; espacio de nombres System.Windows.Controls.DataVisualization.Design { / / / <summary> / / / Editor simple cuadro de texto en línea. / / / </ Summary> pública parcial TextBoxEditor clase: PropertyValueEditor { / / / <summary> / / / Mantener el prototipo constructor de PropertyValueEditor. / / / </ Summary> / / / <param Plantilla name="inlineEditorTemplate"> editor en línea. </ Param> pública TextBoxEditor (DataTemplate inlineEditorTemplate) : Base (inlineEditorTemplate) {} / / / <summary> / / / Constructor por defecto crea el cuadro de texto por defecto en línea editor de plantillas. / / / </ Summary> TextBoxEditor pública () { (TextBox)); FrameworkElementFactory textBox = new FrameworkElementFactory (typeof (TextBox)); Vinculante vinculante = new Binding (); ); binding.Path = new PropertyPath ("Valor"); binding.Mode = BindingMode.TwoWay; textBox.SetBinding (TextBox.TextProperty, vinculante); DataTemplate dt = new DataTemplate (); dt.VisualTree = caja de texto; InlineEditorTemplate = dt; } } }
CultureInfoEditor
Mi colega RJ escribió CultureInfoEditor editor en línea de la propiedad TimePicker.Culture, ya que por defecto experiencia de edición de CultureInfo en mezcla conduce a XAML no válido. A continuación se muestra la pantalla CultureInfoEditor utiliza un ComboBox para mostrar todos los CultureInfo y genera derecho XAML.
CultureInfoEditor es un ejemplo más complejo de lo que TextBoxEditor, en realidad muestra cómo la propiedad subyacente se asocia con el editor a través de la propiedad DataContext.
CultureInfoEditor.cs:
/ / (C) Copyright Microsoft Corporation. / Fuente / Esto está sujeto a la licencia pública de Microsoft (Ms-PL). / / Por favor, vea http://go.microsoft.com/fwlink/?LinkID=131993 para más detalles. / / Todos los demás derechos CultureInfoEditor : PropertyValueEditor { /// <summary> /// The ComboBox being used to edit the value. /// </summary> private ComboBox _owner; /// <summary> /// Preserve the constructor prototype from PropertyValueEditor. /// </summary> /// <param name="inlineEditorTemplate">Inline editor template.</param> public CultureInfoEditor(DataTemplate inlineEditorTemplate) : base (inlineEditorTemplate) { } /// <summary> /// Default constructor builds a ComboBox inline editor template. /// </summary> public CultureInfoEditor() { // not using databinding here because Silverlight does not support // the WPF CultureConverter that is used by Blend. FrameworkElementFactory comboBox = new FrameworkElementFactory( typeof (ComboBox)); comboBox.AddHandler( ComboBox.LoadedEvent, new RoutedEventHandler( (sender, e) => { _owner = (ComboBox) sender; _owner.SelectionChanged += EditorSelectionChanged; INotifyPropertyChanged data = _owner.DataContext as INotifyPropertyChanged; if (data != null ) { data.PropertyChanged += DatacontextPropertyChanged; } _owner.DataContextChanged += CultureDatacontextChanged; })); comboBox.SetValue(ComboBox.IsEditableProperty, false ); comboBox.SetValue(ComboBox.DisplayMemberPathProperty, "DisplayName" ); comboBox.SetValue(ComboBox.ItemsSourceProperty, CultureInfo.GetCultures(CultureTypes.SpecificCultures)); DataTemplate dt = new DataTemplate(); dt.VisualTree = comboBox; InlineEditorTemplate = dt; } /// <summary> /// Handles the SelectionChanged event of the owner control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> /// instance containing the event data.</param> private void EditorSelectionChanged( object sender, SelectionChangedEventArgs e) { // serialize with name. object DataContext = _owner.DataContext; DataContext .GetType() .GetProperty( "Value" , BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) .SetValue(DataContext, ((CultureInfo)_owner.SelectedItem).Name, new object [] { }); } /// <summary> /// Handles the PropertyChanged event of the context object. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param> private void DatacontextPropertyChanged( object sender, PropertyChangedEventArgs e) { // deserialize from name. if (e.PropertyName == "Value" ) { object value = sender .GetType() .GetProperty( "Value" , BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) .GetValue(sender, new object [] { }); if ( value != null ) { if ( value is string ) { CultureInfo setCulture = new CultureInfo( value .ToString()); _owner.SelectedItem = setCulture; } } } } /// <summary> /// Called when the context is changed. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param> private void CultureDatacontextChanged( object sender, DependencyPropertyChangedEventArgs e) { INotifyPropertyChanged old = e.OldValue as INotifyPropertyChanged; if (old != null ) { old.PropertyChanged -= DatacontextPropertyChanged; } INotifyPropertyChanged newDataContext = e.NewValue as INotifyPropertyChanged; if (newDataContext != null ) { newDataContext.PropertyChanged += DatacontextPropertyChanged; } } } } {/ / / <summary> / / / Editor de CultureInfo / / / </ summary> / / / <remarks> En la actualidad no admiten el enlace de XAML al editor </ remarks> public CultureInfoEditor clase:.. PropertyValueEditor {/ / / <summary> / / / El ComboBox se utiliza para editar el valor / / / </ summary> _owner ComboBox privado.. / / / <summary> / / / Mantener el prototipo constructor de PropertyValueEditor / / / </ summary> / / / <param plantilla name="inlineEditorTemplate"> editor en línea </ param> public CultureInfoEditor (DataTemplate inlineEditorTemplate). base (inlineEditorTemplate) {} / / / <summary> / / / Default constructor construye una plantilla ComboBox en línea editor. / / / </ summary> CultureInfoEditor pública () {/ / no usando el enlace de datos aquí porque Silverlight no admite / / la CultureConverter WPF que se utiliza mezcla FrameworkElementFactory comboBox = new FrameworkElementFactory (typeof (ComboBox));. comboBox.AddHandler ( ComboBox.LoadedEvent, nuevo RoutedEventHandler ((sender, e) => {_owner = (ComboBox) remitente; _owner.SelectionChanged + = EditorSelectionChanged; datos INotifyPropertyChanged = _owner.DataContext como INotifyPropertyChanged; if (data = null) {+ data.PropertyChanged = DatacontextPropertyChanged;} _owner.DataContextChanged + = CultureDatacontextChanged;})); CultureInfo.GetCultures comboBox.SetValue (ComboBox.ItemsSourceProperty,; comboBox.SetValue (ComboBox.IsEditableProperty, false); comboBox.SetValue (ComboBox.DisplayMemberPathProperty, "DisplayName") (CultureTypes.SpecificCultures)); DataTemplate dt = new DataTemplate (); dt.VisualTree = comboBox; InlineEditorTemplate = dt;.} / / <summary> / / / / Controla el evento SelectionChanged del control de los dueños / / / </ summary > / / / <param name="sender"> El origen del evento. </ param> / / / <param name="e"> El ltvea cref="System.Windows.Controls.SelectionChangedEventArgs"/> / / / instancia que contiene los datos del evento </ param> private void EditorSelectionChanged (object sender, SelectionChangedEventArgs e) {/ / serializar con el nombre del objeto DataContext = _owner.DataContext,... DataContext GetType () GetProperty ("Valor", BindingFlags.. .. pública | BindingFlags.Instance | BindingFlags.GetProperty) SetValue (DataContext, ((CultureInfo) _owner.SelectedItem) Nombre, new Object [] {});} / / / <summary> / / / Controla el evento PropertyChanged de la objeto de contexto. / / / </ summary> / / / <param name="sender"> El origen del evento. </ param> / / / <param name="e"> El <ver cref = "del sistema. ComponentModel.PropertyChangedEventArgs "/> ejemplo, que contiene los datos del evento. </ param> private void DatacontextPropertyChanged (object sender, PropertyChangedEventArgs e) {/ / deserializar desde el nombre. if (e.PropertyName ==" Valor ") {valor = objeto emisor. .. GetType () GetProperty ("Valor", BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) GetValue (remitente, new Object [] {}); if (valor = null) {if (valor es una cadena) { CultureInfo setCulture = new CultureInfo (valor de ToString ().) _owner.SelectedItem = setCulture;.}}}} / / / <summary> / / / Se llama cuando el contexto se modifica / / / </ summary> / / / < param name = "remitente"> El remitente. </ param> / / / <param name="e"> La instancia cref="System.Windows.DependencyPropertyChangedEventArgs"/> ltvea que contiene los datos del evento. </ param> privado vacío CultureDatacontextChanged (object sender, DependencyPropertyChangedEventArgs e) {INotifyPropertyChanged edad e.OldValue = como INotifyPropertyChanged; if (edad = null) {old.PropertyChanged -= DatacontextPropertyChanged;} INotifyPropertyChanged newDataContext = e.NewValue como INotifyPropertyChanged; if (newDataContext = null ) {newDataContext.PropertyChanged + = DatacontextPropertyChanged;}}}}
ExpandableObjectConverter
Como se mencionó al principio, además de costumbre editores valor de la propiedad, a veces se puede usar convertidor de tipos apropiadas para proporcionar una experiencia de una buena edición y la serialización de XAML. Un ejemplo es ColumnSeries.DependentRangeAxis: es de tipo IRangeAxis, mezcla de no saber cómo corregir, por lo que muestra DependentRangeAxis como de sólo lectura en el panel Propiedades. Al asociar ExpandableObjectConverter a ColumnSeries.DependentRangeAxis:
b.AddCustomAttributes ( Extensions.GetMemberName <ColumnSeries> (x => x.DependentRangeAxis), (ExpandableObjectConverter))); TypeConverterAttribute nuevo (typeof (ExpandableObjectConverter))); b.AddCustomAttributes ( Extensions.GetMemberName <ColumnSeries> (x => x.IndependentAxis), (ExpandableObjectConverter))); TypeConverterAttribute nuevo (typeof (ExpandableObjectConverter)));
Mezcla muestra un botón Nuevo junto a esta propiedad en el panel de propiedades, cuando se hace clic, se despliega el cuadro de diálogo Seleccionar objeto, se filtra con IRangeAxis tipo de la propiedad:
Conclusión
Mezcla y Silverlight en conjunto permiten a los diseñadores para crear la interfaz de usuario impresionante contra los controles reales directamente, por lo que es muy importante que los desarrolladores de control tienen la experiencia de diseño como parte del diseño general de control y ejecución. Tener un editor de propiedades personalizado que ofrece la interfaz de usuario de edición agradable y genera XAML correcto es una parte importante de la experiencia del diseñador. Esperemos que este mensaje le ayuda a entender cómo crear un editor personalizado. Gracias!








Comentarios recientes