Как добавить пользовательский UITypeEditor для всех свойств типа с закрытым исходным кодом?
Я хочу избежать размещения EditorAttribute на каждом экземпляре определенного типа, для которого я написал пользовательский UITypeEditor.
Я не могу поместить EditorAttribute на тип, потому что я не могу изменить источник.
У меня есть ссылка на единственный экземпляр PropertyGrid, который будет использоваться.
Могу ли я сказать экземпляру PropertyGrid (или всем экземплярам) использовать пользовательский UITypeEditor всякий раз, когда он встречает определенный тип?
Вот статья MSDN, которая предоставляет отправную точку для того, как сделать это в.NET 2.0 или более поздней версии.
3 ответа
Обычно вы можете связать редакторов и т.д. во время выполнения через TypeDescriptor.AddAttributes
, Например, Bar
свойство должно отображаться с "...", которое отображает "Редактирование!"):
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() } } });
}
}
Решение Марка прямо применяет EditorAttribute к типу Bar во всем мире. Если у вас деликатное расположение, вы можете скорее аннотировать свойства конкретных экземпляров. Увы, это невозможно TypeDescriptor.AddAttributes
Мое решение было написать обертку ViewModel<T>
, который копирует свойства из T, комментируя некоторые с дополнительными атрибутами. Предположим, у нас есть переменная datum
типа Report, мы будем использовать это так
var pretty = ViewModel<Report>.DressUp(datum);
pretty.PropertyAttributeReplacements[typeof(Smiley)] = new List<Attribute>() { new EditorAttribute(typeof(SmileyEditor),typeof(UITypeEditor))};
propertyGrid1.SelectedObject = pretty;
куда ViewModel<T>
определено:
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);
}
}
Как определено выше, это заменяет свойства определенного типа, но вы можете заменить свойства по имени, если вам нужно большее разрешение.