6

Short description:

I have a UserControl with a DataGridView on it. I want to expose the DataGridView Columns collection to the designer, so I can change the columns on my User Control at design time.

Question: Which designer attributes do I need for this?

For those interested in the longer version:

I have a UserControl with the following features:

  • a DataGridView that shows "pages" of items from a collection.
  • a NumericUpdown control to select which page to show.
  • page up / page down buttons that will disable when the first / last page is shown
  • Changes to the displayed items are visually marked
  • Buttons to save / discard the changes.

This user control can work autonomic. It has one function to be used by the parent control:

  • Show page (collection of items to show)

The UserControl raises two events:

  • Event Page changed (with a page number). Should result in loading a new page
  • Event Save items (with the collection of changed items)

I have to show this user control on several forms. The only difference is that the collection of DataGridViewColumn differs per form.

I could add the columns programmatically, but it would be easier to create them using the designer.

1 Answer 1

8

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);
    }
}
Sign up to request clarification or add additional context in comments.

13 Comments

Checked it, and it works. Be aware though that the columns that you add during design are added as members to the form, not to the user control. Luckily I don't need them in this situation. So I can set GenerateMember to false
Thank you for feedback :) I believe this is an standard behavior because the columns belong to the control. It works like other controls, when you add an item to a collection, collection items will be generated at form level.
@RezaAghaei I have followed your steps, but I have a problem. I have created an user control that contains a DataGridView. The user control has a Columns property as you specified. The project compiles succesfully, but when I enter in design mode in a Form that contains my custom user control and I click on Columns property for edit the content it shows a messagebox that says No parameterless constructor defined for this object. I have put a public constructor without params in my user control, also into CustomColumnEditor and TypeDescriptionContext, but it stills showing the same message.
@stivex I checked it again and it works properly. Check your Columns property definition and attribute and compare it with the property that I have defined in the class. I first put a dataGridView1 on the user control design surface and then went to code and added such property decorated with suitable editor attribute.
@stivex (3) You may find this post and my answer helpful. It describes an unexpected behavior in a custom grid.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.