Click here to Skip to main content
11,646,594 members (74,540 online)
Click here to Skip to main content

Complex Data Binding a collection implementing IBindingList and ITypedList

, 31 Mar 2003 150.4K 3.3K 79
Rate this:
Please Sign up or sign in to vote.
Complex Data Binding a collection implementing IBindingList and ITypedList

Sample Image - ComplexDataBinding.jpg

Introduction

Data binding can be nasty - especially when you cant use the System.Data objects. I have tried to use all the features of data binding to show them to you. It is pretty small, but takes a hell of a long way to get there.

The sample shows a custom collection with objects in it having properties, some of those properties are collections again, with objects in them - i.e. hierarchical data. Maybe some of the properties can't be edited directly because the grid is not smart enough - like SqlTypes.

The Problem

We have a collection of objects that need to go into a Windows DataGrid. They may or may not have properties that are collections too.

The Solution

We need to create the following objects:

  • A class implementing ITypedList and IBindingList (your collection)
  • A class that is your data (lots of properties and stuff)
  • A class implementing IComparer (for sorting)
  • A class implementing PropertyDescriptor (for using non grid compatible types, like SqlTypes)
  • A class implementing Attribute (so we know what's in the collection)

For those of you that have tried this and it didn't work, a couple of issues came up that I will discuss.

ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) 

This was the nastiest method interface in the project. The problem had to do with the listAccessors. If the parameter is not null, then the only one that should be processed is the last one. I had to decompile System.Data.DataView.ITypedList.GetItemProperties to find that out. Then I needed to detect our custom collections and return the properties for the underlying data.

SqlPropertyDescriptor : PropertyDescriptor

This one, although straight forward to implement, is a bit tricky in that when calling GetItemProperties and we want to use this PropertyDesciptor instead of the default, we need to replace it in the collection. I wrote this method to do it:

protected PropertyDescriptorCollection 
    GetPropertyDescriptorCollection( ArrayList properties )
{
    if ( properties == null || properties.Count == 0 )
        return new PropertyDescriptorCollection(null);

    ArrayList output = new ArrayList();

    foreach ( PropertyDescriptor p in properties )
    {
        if ( p.Attributes.Matches(new Attribute[]
            {new BindableAttribute(false)}) ) continue;

        if ( p.PropertyType.Namespace == "System.Data.SqlTypes" )
        {
            // create the base type property descriptor
            output.Add(SqlPropertyDescriptor.
                GetProperty( p.Name, p.PropertyType ) );
        }
        else
        {
            output.Add(p);
        }
    }
    return new PropertyDescriptorCollection((PropertyDescriptor[])
        output.ToArray(typeof(PropertyDescriptor)));
}

After that, it was all straight forward.

The SetValue and GetValue of the PropertyDescriptor provide the means to edit SqlTypes like SqlDateTime. After detecting the namespace of the data type, I use SqlPropertDescriptor which implements GetValue() and SetValue(). These methods try to figure everything out for themselves:

public override void SetValue(object component,object value)
{
    try
    {
        PropertyInfo pi = component.GetType().GetProperty(this.Name);
        Object o;
        if ( value == DBNull.Value )
        {
            o = component.GetType().GetField("Null", 
                BindingFlags.Static | BindingFlags.Public | 
                BindingFlags.GetField).GetValue(component);
                
        }
        else
        {
            o = pi.PropertyType.GetConstructor(new Type[]
                {BaseType}).Invoke(new Object[]{value});
        }
        pi.SetValue(component,o, null);
    }
    catch(Exception ex)
    {
        Debug.WriteLine(ex);
    }
}

public override object GetValue(object component)
{
    try
    {
        object Property = component.GetType().GetProperty
            (this.Name).GetValue(component,null);

        // handle nulls
        if ( (bool)Property.GetType().GetProperty
            ("IsNull").GetValue(Property,null) ) 
            return DBNull.Value;

        object Value = Property.GetType().GetProperty
            ("Value").GetValue(Property,null);
        return Value;
    }
    catch(Exception ex)
    {
        Debug.WriteLine(ex);
    }
    return null;
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Dan Glass
Architect support.com
Australia Australia

You may also be interested in...

Comments and Discussions

 
GeneralAdditional code needed for previous message. Pin
gffajardo14-Oct-06 5:38
membergffajardo14-Oct-06 5:38 
QuestionRe: Additional code needed for previous message. Pin
kavano25-Oct-06 8:33
memberkavano25-Oct-06 8:33 
Question.Net 2.0 makes this unnecessary Pin
gffajardo13-Oct-06 12:15
membergffajardo13-Oct-06 12:15 
GeneralExplaination of The Tricky ITypedList.GetItemProperties Pin
Weifen Luo8-May-06 18:00
memberWeifen Luo8-May-06 18:00 
GeneralUsage Patterns Pin
Steve Hawkes19-Mar-06 20:23
memberSteve Hawkes19-Mar-06 20:23 
QuestionXML data binding? Pin
hellamasta14-Nov-05 0:18
memberhellamasta14-Nov-05 0:18 
QuestionHow: addnew row in datagrid? Pin
artem12321-May-05 5:45
memberartem12321-May-05 5:45 
AnswerRe: How: addnew row in datagrid? Pin
Jim37373737321-Jun-06 16:59
memberJim37373737321-Jun-06 16:59 
QuestionRe: How: addnew row in datagrid? Pin
yfessler22-Jun-06 22:32
memberyfessler22-Jun-06 22:32 
AnswerRe: How: addnew row in datagrid? Pin
Jim37373737323-Jun-06 6:21
memberJim37373737323-Jun-06 6:21 
Generalhiding properties/strong typing/inheriting Pin
Rob STS15-Nov-04 19:06
memberRob STS15-Nov-04 19:06 
GeneralRe: hiding properties/strong typing/inheriting Pin
lemonia22-Nov-04 2:49
memberlemonia22-Nov-04 2:49 
GeneralRe: hiding properties/strong typing/inheriting Pin
Rob STS10-Dec-04 13:58
memberRob STS10-Dec-04 13:58 
GeneralRe: hiding properties/strong typing/inheriting Pin
Anonymous14-Dec-04 4:03
sussAnonymous14-Dec-04 4:03 
GeneralVery nice work, still a question on IBindingList.Find() Pin
northernlights8-Dec-03 23:20
membernorthernlights8-Dec-03 23:20 
QuestionDo you know.....? Pin
ggaruda13-Sep-03 16:45
memberggaruda13-Sep-03 16:45 
AnswerRe: Do you know.....? Pin
Dan Glass15-Sep-03 7:21
memberDan Glass15-Sep-03 7:21 
Generalgreat work ! Pin
dirkus7-Sep-03 12:54
memberdirkus7-Sep-03 12:54 
GeneralRe: great work ! Pin
Crispin Horsfield27-Feb-04 9:35
memberCrispin Horsfield27-Feb-04 9:35 
GeneralThank you! Pin
sharkfish18-Aug-03 11:05
membersharkfish18-Aug-03 11:05 
GeneralThanks Pin
pthomson4-Aug-03 15:25
memberpthomson4-Aug-03 15:25 
QuestionModify to support use by the Databinding picker? Pin
Bill Foust23-Jun-03 5:46
sussBill Foust23-Jun-03 5:46 
GeneralSupportsChangeNotification Pin
anonim2-Apr-03 21:04
sussanonim2-Apr-03 21:04 
GeneralGreat! Pin
sonemaf1-Apr-03 8:18
membersonemaf1-Apr-03 8:18 
GeneralRe: Great! Pin
mordejai1-Apr-03 9:31
membermordejai1-Apr-03 9:31 

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 | Terms of Use | Mobile
Web01 | 2.8.150731.1 | Last Updated 1 Apr 2003
Article Copyright 2003 by Dan Glass
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid