Databinding SqlTypes

Page 2 of 2
  1. Introduction
  2. The Solution

The Solution

Property descriptors allow us to expose the SqlTypes underlying type ONLY through data binding, and leave everything else the same for normal use of the object. One problem with property descriptors is that we need to implement ITypedList for it to be any use. ITypedList contains the method signature GetItemProperties() , which we can return our own property descriptors with. We could write one property descriptor for each of the SqlTypes, but here's an easier way.

public class SqlPropertyDescriptor : PropertyDescriptor
{
    public static SqlPropertyDescriptor GetProperty(string name, Type sqlType)
    {
        Type baseType = sqlType.GetProperty("Value").PropertyType;
        ArrayList attribs = new ArrayList(TypeDescriptor.GetAttributes(baseType));
        Attribute[] attrs = (Attribute[])attribs.ToArray(typeof(Attribute));
        return new SqlPropertyDescriptor(name,attrs,sqlType,baseType);
    }
    private Type SqlType;
    private Type BaseType;
    protected SqlPropertyDescriptor( string name,Attribute[] attrs, Type sqlType, Type baseType ) : base(name,attrs)
    {
        SqlType = sqlType;
        BaseType = baseType;
    }
    ...
    public override void SetValue(object component,object value)
    {
        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);
    }
    public override object GetValue(object component)
    {
        object Property = component.GetType().GetProperty(this.Name).GetValue(component,null);
        if ( (bool)Property.GetType().GetProperty("IsNull").GetValue(Property,null) )
            return DBNull.Value;
        return Property.GetType().GetProperty("Value").GetValue(Property,null);
    }
}

Here we can see that I have overridden the SetValue() and GetValue() , and since they pass around the data type object , they can handle nulls. I use some reflection to achieve the desired result. SetValue() can put null into the property, and GetValue() can return a null if need be. To use the property descriptors, we must implement ITypedList in our collection, and return our custom property descriptor for all the properties where they are SqlTypes . In my code, I call the following method to replace the property descriptors.

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)));
}

So, now we have a class with properties that are database and null friendly, we can show it in a grid and edit it, and the methods written are generic enough that we can use then on all the SqlTypes.

You might also like...

Comments

Dan Glass

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“It is practically impossible to teach good programming style to students that have had prior exposure to BASIC. As potential programmers, they are mentally mutilated beyond hope of regeneration.” - E. W. Dijkstra