Click here to Skip to main content
Click here to Skip to main content

Dynamically Bound Dictionary to Windows Grid

, 2 Oct 2012
Rate this:
Please Sign up or sign in to vote.
This article presents a way to display totally dynamic data in a windoes grid using a dictionary.

I had wanted to bind a Windows form DataGridView DataSource to an list of Dictionary types, and initially attempted to use a DynamicObject as an adapter. This would have been nice because then I would just need to write the DynamicObject code to look up in the dictionary. Never did get this to work. Think it is a serious oversight the Microsoft has not supported binding to DynamicObject instances, but we have to live with it. I did implement the interface with a Table, but this required conversion of the dictionary to fields in a row. Somebody pointed me to another solution, and it does have certain advantages, and probably a whole lot less overhead than using a table. It uses the ICustomTypeDescriptor. The ICustomTypeDescriptor provides an interface that supplies dynamic custom type information for an object.

All that is needed is to create a class that inherits from ICustomTypeDescriptor, that provides a variable for the Dictionary, and returns a customized PropertyDescriptor that will look up the value in the dictionary of the class inheriting from ICustomTypeDescriptor. The PropertyDescriptor does pretty much all the work:

  public class DictionaryTypeDescriptor : ICustomTypeDescriptor
  {
    private readonly Dictionary<string, object> _properties = 
            new Dictionary<string, object>();
    public object this[string name]
    {
      get { return _properties.ContainsKey(name) ? _properties[name] : null; }
      set { _properties[name] = value; }
    }
    #region ICustomTypeDescriptor Members
    public AttributeCollection GetAttributes()
    {
      return AttributeCollection.Empty;
    }
    public string GetClassName()
    {
      return TypeDescriptor.GetClassName(this, true);
    }
    public string GetComponentName()
    {
      return TypeDescriptor.GetComponentName(this, true);
    }
    public TypeConverter GetConverter()
    {
      return null;
    }
    public EventDescriptor GetDefaultEvent()
    {
      return null;
    }
    public PropertyDescriptor GetDefaultProperty()
    {
      return null;
    }
    public object GetEditor(Type editorBaseType)
    {
      return null;
    }
    public EventDescriptorCollection GetEvents(Attribute[] attributes)
    {
      return EventDescriptorCollection.Empty;
    }
    public EventDescriptorCollection GetEvents()
    {
      return EventDescriptorCollection.Empty;
    }
    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
      return new PropertyDescriptorCollection(
        _properties.Keys.Select(key => new DictionaryDescriptor(key)).ToArray());
    }
    public PropertyDescriptorCollection GetProperties()
    {
      return GetProperties(null);
    }
    public object GetPropertyOwner(PropertyDescriptor pd)
    {
      return this;
    }
    #endregion
 
    class DictionaryDescriptor : PropertyDescriptor
    {
      public DictionaryDescriptor(string name) : base(name, null) { }
      public override bool CanResetValue(object component)
      {
        return true;
      }
      public override Type ComponentType
      {
        get { return typeof(DictionaryTypeDescriptor); }
      }
      public override object GetValue(object component)
      {
        return ((DictionaryTypeDescriptor)component)[Name];
      }
      public override void SetValue(object component, object value)
      {
        ((DictionaryTypeDescriptor)component)[Name] = value;
      }
      public override bool IsReadOnly
      {
        get { return false; }
      }
      public override Type PropertyType
      {
        get { return typeof(object); }
      }
      public override void ResetValue(object component)
      {
        ((DictionaryTypeDescriptor)component)._properties.Remove(Name);
      }
      public override bool ShouldSerializeValue(object component)
      {
        return ((DictionaryTypeDescriptor)component)._properties.ContainsKey(Name);
      }
    }
  }

Using this code is very simple. In the code behind the form I have the following:

   public partial class DynamicallyBoundForm : Form
  {
    public DynamicallyBoundForm()
    {
      InitializeComponent();
 
      var obj1 = new DictionaryTypeDescriptor();
      obj1["test1"] = 100;
      obj1["test2"] = 200;
      obj1["test3"] = 300;
      var objects = new List<DictionaryTypeDescriptor>() { obj1 };
      dataGrid.DataSource = objects;
    }
  }

I made a few changes for this example from what I implemented: I made class completely dynamic so that fields could be added as needed. Also,in my code I provide a dictionary of Dictionary<string, string>.

History

10/02/12: Added source code.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Clifford Nelson
Software Developer (Senior) ETeam/Delloitte
United States United States
Has been working as a C# developer on contract for the last several years, including 3 years at Microsoft. Previously worked with Visual Basic and Microsoft Access VBA, and have developed code for Word, Excel and Outlook. Started working with WPF in 2007 when part of the Microsoft WPF team. For the last three years has been working primarily as a senior WPF/C# and Silverlight/C# developer. Currently working as WPF developer with NBC Universal in Universal City, CA

Comments and Discussions

 
GeneralMy vote of 5 PinmemberNGErndt28-Sep-12 10:05 
AnswerRe: My vote of 5 PinmemberClifford Nelson1-Oct-12 9:13 
AnswerRe: My vote of 5 PinmemberClifford Nelson2-Oct-12 9:20 
GeneralRe: My vote of 5 PinmemberNGErndt11-Jul-13 8:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 2 Oct 2012
Article Copyright 2012 by Clifford Nelson
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid