Click here to Skip to main content
6,596,602 members and growing! (23,001 online)
Email Password   helpLost your password?
Languages » C# » General     Advanced

Complex Data Binding a collection implementing IBindingList and ITypedList

By Dan Glass

Complex Data Binding a collection implementing IBindingList and ITypedList
C#.NET 1.0, Win2K, WinXP, Dev
Posted:26 Mar 2003
Updated:31 Mar 2003
Views:108,995
Bookmarked:63 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
22 votes for this article.
Popularity: 5.33 Rating: 3.97 out of 5
2 votes, 9.1%
1

2
2 votes, 9.1%
3
3 votes, 13.6%
4
15 votes, 68.2%
5

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

About the Author

Dan Glass


Member
Tech Support
Occupation: Architect
Company: support.com
Location: Australia Australia

Other popular C# articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 25 (Total in Forum: 25) (Refresh)FirstPrevNext
GeneralAdditional code needed for previous message. Pinmembergffajardo6:38 14 Oct '06  
QuestionRe: Additional code needed for previous message. Pinmemberkavano9:33 25 Oct '06  
Question.Net 2.0 makes this unnecessary Pinmembergffajardo13:15 13 Oct '06  
GeneralExplaination of The Tricky ITypedList.GetItemProperties PinmemberWeifen Luo19:00 8 May '06  
GeneralUsage Patterns PinmemberSteve Hawkes21:23 19 Mar '06  
GeneralXML data binding? Pinmemberhellamasta1:18 14 Nov '05  
GeneralHow: addnew row in datagrid? Pinmemberartem1236:45 21 May '05  
GeneralRe: How: addnew row in datagrid? PinmemberJim37373737317:59 21 Jun '06  
QuestionRe: How: addnew row in datagrid? Pinmemberyfessler23:32 22 Jun '06  
AnswerRe: How: addnew row in datagrid? PinmemberJim3737373737:21 23 Jun '06  
Generalhiding properties/strong typing/inheriting PinmemberRob STS20:06 15 Nov '04  
GeneralRe: hiding properties/strong typing/inheriting Pinmemberlemonia3:49 22 Nov '04  
GeneralRe: hiding properties/strong typing/inheriting PinmemberRob STS14:58 10 Dec '04  
GeneralRe: hiding properties/strong typing/inheriting PinsussAnonymous5:03 14 Dec '04  
GeneralVery nice work, still a question on IBindingList.Find() Pinmembernorthernlights0:20 9 Dec '03  
GeneralDo you know.....? Pinmemberggaruda17:45 13 Sep '03  
GeneralRe: Do you know.....? PinmemberDan Glass8:21 15 Sep '03  
Generalgreat work ! Pinmemberdirkus13:54 7 Sep '03  
GeneralRe: great work ! PinmemberCrispin Horsfield10:35 27 Feb '04  
GeneralThank you! Pinmembersharkfish12:05 18 Aug '03  
GeneralThanks Pinmemberpthomson16:25 4 Aug '03  
GeneralModify to support use by the Databinding picker? PinsussBill Foust6:46 23 Jun '03  
GeneralSupportsChangeNotification Pinsussanonim22:04 2 Apr '03  
GeneralGreat! Pinmembersonemaf9:18 1 Apr '03  
GeneralRe: Great! Pinmembermordejai10:31 1 Apr '03  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 31 Mar 2003
Editor: Smitha Vijayan
Copyright 2003 by Dan Glass
Everything else Copyright © CodeProject, 1999-2009
Web16 | Advertise on the Code Project