I want to avoid placing an EditorAttribute on every instance of a certain type that I've written a custom UITypeEditor for.
我想避免在我编写自定义UITypeEditor的某个类型的每个实例上放置EditorAttribute。
I can't place an EditorAttribute on the type because I can't modify the source.
我不能在类型上放置EditorAttribute,因为我无法修改源代码。
I have a reference to the only PropertyGrid instance that will be used.
我引用了将要使用的唯一PropertyGrid实例。
Can I tell a PropertyGrid instance (or all instances) to use a custom UITypeEditor whenever it encounters a specific type?
我是否可以告诉PropertyGrid实例(或所有实例)在遇到特定类型时使用自定义UITypeEditor?
Here is an MSDN article that provides are starting point on how to do this in .NET 2.0 or greater.
这是一篇MSDN文章,它提供了如何在.NET 2.0或更高版本中执行此操作的起点。
3 个解决方案
#1
You can usually associate editors etc at runtime via TypeDescriptor.AddAttributes
. For example (the Bar
property should show with a "..." that displays "Editing!"):
您通常可以通过TypeDescriptor.AddAttributes在运行时关联编辑器等。例如(Bar属性应显示“......”,显示“Editing!”):
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() } } });
}
}
#2
Marc's solution bluntly applies the EditorAttribute to the Bar type globally. If you have a delicate disposition, you might rather annotate properties of a specific instances. Alas, that isn't possible with TypeDescriptor.AddAttributes
Marc的解决方案直接将EditorAttribute全局应用于Bar类型。如果你有一个微妙的处置,你可能宁愿注释特定实例的属性。唉,使用TypeDescriptor.AddAttributes是不可能的
My solution was to write a wrapper ViewModel<T>
, which copies properties from T, annotating some with extra attributes. Suppose we have a variable datum
of type Report, we'd use it like this
我的解决方案是编写一个包装器ViewModel
var pretty = ViewModel<Report>.DressUp(datum);
pretty.PropertyAttributeReplacements[typeof(Smiley)] = new List<Attribute>() { new EditorAttribute(typeof(SmileyEditor),typeof(UITypeEditor))};
propertyGrid1.SelectedObject = pretty;
Where ViewModel<T>
is defined:
定义ViewModel
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);
}
}
As defined above, this substitutes properties of a specific type, but you can substitute properties by name if you need the greater resolution.
如上所述,这会替换特定类型的属性,但如果需要更高的分辨率,则可以按名称替换属性。
#1
You can usually associate editors etc at runtime via TypeDescriptor.AddAttributes
. For example (the Bar
property should show with a "..." that displays "Editing!"):
您通常可以通过TypeDescriptor.AddAttributes在运行时关联编辑器等。例如(Bar属性应显示“......”,显示“Editing!”):
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() } } });
}
}
#2
Marc's solution bluntly applies the EditorAttribute to the Bar type globally. If you have a delicate disposition, you might rather annotate properties of a specific instances. Alas, that isn't possible with TypeDescriptor.AddAttributes
Marc的解决方案直接将EditorAttribute全局应用于Bar类型。如果你有一个微妙的处置,你可能宁愿注释特定实例的属性。唉,使用TypeDescriptor.AddAttributes是不可能的
My solution was to write a wrapper ViewModel<T>
, which copies properties from T, annotating some with extra attributes. Suppose we have a variable datum
of type Report, we'd use it like this
我的解决方案是编写一个包装器ViewModel
var pretty = ViewModel<Report>.DressUp(datum);
pretty.PropertyAttributeReplacements[typeof(Smiley)] = new List<Attribute>() { new EditorAttribute(typeof(SmileyEditor),typeof(UITypeEditor))};
propertyGrid1.SelectedObject = pretty;
Where ViewModel<T>
is defined:
定义ViewModel
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);
}
}
As defined above, this substitutes properties of a specific type, but you can substitute properties by name if you need the greater resolution.
如上所述,这会替换特定类型的属性,但如果需要更高的分辨率,则可以按名称替换属性。
#3
Just add an Editor attribute to your class.
只需在您的类中添加Editor属性即可。