Click here to Skip to main content
15,867,771 members
Articles / Programming Languages / C#
Article

Leaveraging GenericType Converter for Hybrid Property Databinding

Rate me:
Please Sign up or sign in to vote.
4.73/5 (27 votes)
23 Feb 2008CPOL4 min read 22.6K   131   16   1
Leaveraging GenericType Converter for Hybrid Property Databinding
Image 1

Introduction

This article shows how I have managed to use databinding to display/edit objects with Hybrid Properties. By Hybrid Property, I mean properties with multiple modes (e.g. data or formulae or code, etc). A Hybrid Property at one time can have one or multiple modes (meaning if the user types a formulae, then at the same time have formulae like say "=G1+ 2.5" as well its converted value which evaluates to something). The user can choose to input the date as codes say "3m" when the date property switches mode to "code" and displays a valid date which is 3 months from now. Real life use cases are even complex than this but the general idea is how to effectively provide an object abstraction which can handle these complexities through a neat manageable non repetitive objective pattern.

Background

Databinding is an effective way to display objects on a grid. This is easy with objects having integral property types or if property types implement IConvertible or if they have type converters.

So far so good, but things become messy when the databound objects are user editable and we want to achieve the above requirements.

If we take the approach of properties having just string types, so that we can parse the user input, then we end up mangling our business code with UI specific code.

A better approach would be to use BO specific custom Types for the properties and have their custom type converters. But TypeConverters do not maintain state and what if we have loads of properties and the user might have a valid reason to persist both formulae as well as data for a specific property.

To tackle this situation , I have made a Generic Property Type called Attribute<T> with hybrid states.

Attribute Class

The Attribute class is a generic class which can have various modes . The modes are context specific and can be easily set to retrieve meaningful string conversion hence facilitating hybrid feature, whereas Value part will always return the implied integral value. Also depending on mode and context, specific layer (BO or UI or Presenter) can take specific action like either modify this object or trigger some external action.

This is to some extent like AOP without incorporating its messaging framework. To give a specific usecase, most of the grids that support formulae engine, require the string conversion to return a formulae string. But after the engine evaluates a value for the formulae, the grid uses reflection to invoke the typeconverter on the propertytype to set the value.

On the other hand while the attribute is in useful business mode like say Code = "atms" for strike, the BO layer can compute "ATM" from Analytics and set the value.

Secondly, this object encapsulation makes it a lot easier to handle UI, BO, Data Layers, without much code fragmentation and cyclomatics.

Thirdly, Attribute being a generic type makes it possible to dynamically associate internal integral type for the value. Meaning DateTime for a datetime column, double for some other column, etc.

C#
namespace Attributes
{
   public enum AttributeMode
   {
    Text,
    Data,
    Error,
    Formulae,
    Code
   };

   [Serializable]
   [TypeConverter(typeof(AttributeConverter))]
   public class Attribute<Type> 
   {
     //.. details of this class is in the attachment
   }
}

But the problem now becomes how to provide a TypeConverter for this class, because the Generic Type for the Attribute class is not known at design time when we try to convert "From" string to this specific Type .

AttributeConverter

C#
public override object ConvertFrom(ITypeDescriptorContext context,
       System.Globalization.CultureInfo culture, object value)
{
         Mediator mediator = new Mediator();
         mediator.Value = value.ToString();
         return mediator;
}

The trick is to return a Mediator Type in the ConvertFrom, so that subsequently the CLR will try to convert the Mediator type "To" to this specific type.

Note that the ConvertTo method of the TypeConverter has the destination type. Thus we can now use the destinationType to probe the embedded generic type.

The code below is self explanatory. The most important part here is how we use Reflection to probe the generic type associated with the Value property of the specific Attribute generic class, which has been dynamically set at some point of execution. (Note Types in generics C# are set in runtime unlike as in C++ preprocessing time.)

I can now get the associated type converter of the Target Value Type and use it to convert "From" string to this specific type and set it in the destination Type instance.

MediatorConverter

C#
public override object ConvertTo(ITypeDescriptorContext context, 
    System.Globalization.CultureInfo culture, object value, Type destinationType)
{
    object target = null;
    if (value is Mediator)
    {
        // Construct the target instance.
        target = Activator.CreateInstance(destinationType);

        //Check if the Mediator is in state of code/formulae 
        //rather than integral values
        //Set Code or Integral value
        if (((Mediator)value).IsCode)
        {
            PropertyInfo piTarget = destinationType.GetProperty("Code");
            piTarget.SetValue(target, ((Mediator)value).Value, null);
            piTarget = destinationType.GetProperty("Mode");
            piTarget.SetValue(target, AttributeMode.Code, null);
        }
        else if (((Mediator)value).IsFormulae)
        {
            PropertyInfo piTarget = destinationType.GetProperty("Formulae");
            piTarget.SetValue(target, ((Mediator)value).Value, null);
            piTarget = destinationType.GetProperty("Mode");
            piTarget.SetValue(target, AttributeMode.Formulae, null);
        }
        else
        {
            //above methodology piTarget.SetValue(target, ((Mediator)value).Value, null);
            //will not directly work here directly unless generic 
            //value type is same as Mediator Value Type
            //hence need type conversion again! from Mediator Value Type 
            //to Generic Value Type

            PropertyInfo piMediatorValue = value.GetType().GetProperty("Value");
            //Mediator value type.
            Type tMediatorValue = piMediatorValue.PropertyType;
    
            PropertyInfo piTarget = destinationType.GetProperty("Value");
    
            //Generic Value type.
            Type tTarget = piTarget.PropertyType;
        
            // Get the type converter for the target value type.
            TypeConverter tcTarget = TypeDescriptor.GetConverter(tTarget);

            if (tcTarget != null && tcTarget.CanConvertFrom(tMediatorValue))
            {
                // Get the Mediator value.
                object mediatorValue = piMediatorValue.GetValue(value, null);

                // Convert it to the target type.
                object targetValue = 
                        tcTarget.ConvertFrom(context, culture, mediatorValue);

                // Assign it to the generic instance.
                piTarget.SetValue(target, targetValue, null);
                piTarget = destinationType.GetProperty("Mode");
                piTarget.SetValue(target, AttributeMode.Data, null);
            }
        }
    }
    return target;
}
}

Conclusion

This is a useful way to provide a Hybrid Property Type with Generic Type behaviour. Credit also goes to Marc Clifton who pointed type conversion on similar lines. If you find errors or further enhancements, I would be happy to hear from you.

History

  • 23rd February, 2008: Initial post

License

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


Written By
Founder Alan&Aamy Ltd
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralExcellent Article!!! Pin
johnpaull13-Mar-08 21:41
johnpaull13-Mar-08 21:41 

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.