Usually it's enough to register a suitable UITypeEditor
using [Editor]
attribute. The editor which is used by the DataGridView
is DataGridViewColumnCollectionEditor
. But in this case, if we use this editor directly, the editor expect the the property belong to a DataGridView
and tries to convert value of ITypeDescriptorContext.Instance
to DataGridVeiew
and since our editing Columns
property belongs to our user control we will receive an exception:
Unable to cast object of type 'Type of Control'
to type
'System.Windows.Forms.DataGridView
'.
To solve the problem, we need to create a custom UITypeEditor
and override EditValue
and edit Columns
property of the private DataGridView
field of your user control.
To do so, we create an instance of ITypeDescriptorContext
containing the DataGridView
and it's Columns
property and pass it to EditValue
method of the editor. This way the editor will edit our Columns
property.
We also decorate our property using [DesignerSerializationVisibility]
attribute to serialize the collection contents.
Here is the implementations.
MyUserControl
I suppose you add a DataGridView
at design-time to the user control and its name would be 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; }
}
}
Editor
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 Implementation
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);
}
}