通常使用[Editor] 属性注册一个合适的UITypeEditor 就足够了。 DataGridView 使用的编辑器是DataGridViewColumnCollectionEditor。但是在这种情况下,如果我们直接使用这个编辑器,编辑器期望该属性属于DataGridView,并尝试将ITypeDescriptorContext.Instance的值转换为DataGridVeiew,并且由于我们编辑Columns属性属于我们的用户控件我们将收到一个异常:
无法将类型为“Type of Control'”的对象转换为类型
'System.Windows.Forms.DataGridView'。
为了解决这个问题,我们需要创建一个自定义UITypeEditor 并覆盖EditValue 并编辑您的用户控件的私有DataGridView 字段的Columns 属性。
为此,我们创建一个包含DataGridView 的ITypeDescriptorContext 实例,它是Columns 属性,并将其传递给编辑器的EditValue 方法。这样编辑器将编辑我们的Columns 属性。
我们还使用[DesignerSerializationVisibility] 属性来装饰我们的属性以序列化集合内容。
这里是实现。
MyUserControl
我假设您在设计时将DataGridView 添加到用户控件,其名称将是dataGridView1。
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
[Editor(typeof(MyColumnEditor), typeof(UITypeEditor))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public DataGridViewColumnCollection Columns
{
get { return this.dataGridView1.Columns; }
}
}
编辑器
public class MyColumnEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider, object value)
{
var field = context.Instance.GetType().GetField("dataGridView1",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
var dataGridView1 = (DataGridView)field.GetValue(context.Instance);
dataGridView1.Site = ((Control)context.Instance).Site;
var columnsProperty = TypeDescriptor.GetProperties(dataGridView1)["Columns"];
var tdc = new TypeDescriptionContext(dataGridView1, columnsProperty);
var editor = (UITypeEditor)columnsProperty.GetEditor(typeof(UITypeEditor));
var result = editor.EditValue(tdc, provider, value);
dataGridView1.Site = null;
return result;
}
}
ITypeDescriptionContext 实现
public class TypeDescriptionContext : ITypeDescriptorContext
{
private Control editingObject;
private PropertyDescriptor editingProperty;
public TypeDescriptionContext(Control obj, PropertyDescriptor property)
{
editingObject = obj;
editingProperty = property;
}
public IContainer Container
{
get { return editingObject.Container; }
}
public object Instance
{
get { return editingObject; }
}
public void OnComponentChanged()
{
}
public bool OnComponentChanging()
{
return true;
}
public PropertyDescriptor PropertyDescriptor
{
get { return editingProperty; }
}
public object GetService(Type serviceType)
{
return editingObject.Site.GetService(serviceType);
}
}