¿Cómo me inyecto una UITypeEditor personalizado para todas las propiedades de un tipo de código cerrado?
-
21-08-2019 - |
Pregunta
Quiero evitar la colocación de un EditorAttribute en cada instancia de un determinado tipo que he escrito un UITypeEditor personalizado para.
No puedo colocar un EditorAttribute del tipo porque no puedo modificar el código fuente.
I tiene una referencia a la única instancia PropertyGrid que será utilizado.
¿Puedo contar una instancia PropertyGrid (o todas las instancias) para utilizar un UITypeEditor costumbre cada vez que se encuentra con un tipo específico?
Aquí es un artículo de MSDN que proporciona son punto de partida en cómo hacer esto en .NET 2.0 o superior.
Solución
Normalmente se puede asociar editores, etc. en tiempo de ejecución a través de TypeDescriptor.AddAttributes
. Por ejemplo (la Bar
propiedad debe mostrar con un "..." que muestra 'Edición'):
using System;
using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms;
class Foo
{
public Foo() { Bar = new Bar(); }
public Bar Bar { get; set; }
}
class Bar
{
public string Value { get; set; }
}
class BarEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
MessageBox.Show("Editing!");
return base.EditValue(context, provider, value);
}
}
static class Program
{
[STAThread]
static void Main()
{
TypeDescriptor.AddAttributes(typeof(Bar),
new EditorAttribute(typeof(BarEditor), typeof(UITypeEditor)));
Application.EnableVisualStyles();
Application.Run(new Form { Controls = { new PropertyGrid { SelectedObject = new Foo() } } });
}
}
Otros consejos
La solución de Marc aplica sin rodeos la EditorAttribute a la barra de tipo a nivel mundial. Si usted tiene una disposición delicada, es posible que en lugar de anotar propiedades a casos específicos. Por desgracia, eso no es posible con TypeDescriptor.AddAttributes
Mi solución fue escribir un envoltorio ViewModel<T>
, que copia las propiedades de T, anotando algunos con atributos adicionales. Supongamos que tenemos una variable datum
del tipo de informe, nos gustaría utilizar de esta manera
var pretty = ViewModel<Report>.DressUp(datum);
pretty.PropertyAttributeReplacements[typeof(Smiley)] = new List<Attribute>() { new EditorAttribute(typeof(SmileyEditor),typeof(UITypeEditor))};
propertyGrid1.SelectedObject = pretty;
Donde <=> se define:
public class ViewModel<T> : CustomTypeDescriptor
{
private T _instance;
private ICustomTypeDescriptor _originalDescriptor;
public ViewModel(T instance, ICustomTypeDescriptor originalDescriptor) : base(originalDescriptor)
{
_instance = instance;
_originalDescriptor = originalDescriptor;
PropertyAttributeReplacements = new Dictionary<Type,IList<Attribute>>();
}
public static ViewModel<T> DressUp(T instance)
{
return new ViewModel<T>(instance, TypeDescriptor.GetProvider(instance).GetTypeDescriptor(instance));
}
/// <summary>
/// Most useful for changing EditorAttribute and TypeConvertorAttribute
/// </summary>
public IDictionary<Type,IList<Attribute>> PropertyAttributeReplacements {get; set; }
public override PropertyDescriptorCollection GetProperties (Attribute[] attributes)
{
var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>();
var bettered = properties.Select(pd =>
{
if (PropertyAttributeReplacements.ContainsKey(pd.PropertyType))
{
return TypeDescriptor.CreateProperty(typeof(T), pd, PropertyAttributeReplacements[pd.PropertyType].ToArray());
}
else
{
return pd;
}
});
return new PropertyDescriptorCollection(bettered.ToArray());
}
public override PropertyDescriptorCollection GetProperties()
{
return GetProperties(null);
}
}
Como se definió anteriormente, este sustituye propiedades de un tipo específico, pero se puede sustituir propiedades por su nombre si necesita mayor resolución.
Editor de atributos a su clase.