Click here to Skip to main content
15,879,095 members
Articles / Desktop Programming / Win32
Tip/Trick

Dynamically Bound Dictionary to Windows Grid

Rate me:
Please Sign up or sign in to vote.
5.00/5 (8 votes)
2 Oct 2012CPOL1 min read 16K   163   13   4
This article presents a way to display totally dynamic data in a windows grid using a dictionary.

I had wanted to bind a Windows form DataGridView DataSource to a 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, which 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:

C#
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:

C++
 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)


Written By
Software Developer (Senior) Clifford Nelson Consulting
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 eight years has been working primarily as a senior WPF/C# and Silverlight/C# developer. Currently working as WPF developer with BioNano Genomics in San Diego, CA redesigning their UI for their camera system. he can be reached at qck1@hotmail.com.

Comments and Discussions

 
GeneralMy vote of 5 Pin
NGErndt28-Sep-12 10:05
NGErndt28-Sep-12 10:05 
AnswerRe: My vote of 5 Pin
Clifford Nelson1-Oct-12 9:13
Clifford Nelson1-Oct-12 9:13 
AnswerRe: My vote of 5 Pin
Clifford Nelson2-Oct-12 9:20
Clifford Nelson2-Oct-12 9:20 
I have posted the code
GeneralRe: My vote of 5 Pin
NGErndt11-Jul-13 8:14
NGErndt11-Jul-13 8:14 

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

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