Binding to Dynamic Properties with ICustomTypeProvider (Silverlight 5 Beta)

Silverlight 5 Beta introduces a new ICustomTypeProvider interface that enables data binding to objects the structure of which cannot be known until runtime. This is a common problem when you work with data in any format from databases to metadata or XML files to JSON objects. New attributes or new columns can be added over time and prior to Silverlight 5 you needed to update and recompile your source code if you wanted to show this new data through data binding in a Silverlight application.

With ICustomTypeProvider you can add properties to objects on the fly and then databind to these newly created objects. The interface is pretty simple:

 public interface ICustomTypeProvider
{
    public Type GetCustomType();
}

When you implement the ICustomTypeProvider interface you need to return your own Type. Silverlight’s data binding engine now checks whether an object implements this interface or not. If the object does implement ICustomTypeProvider, the data binding engine uses your custom type instead of the System.Type.

Implementing ICustomTypeProvider

However, implementing this interface requires some effort. Here is the list of things to consider:

  1. Create your own Type by deriving from System.Type.
  2. Your new type needs to store its properties somewhere, so you need to create your own PropertyInfo by deriving from System.Reflection.PropertyInfo.
  3. And don’t forget about INotifyPropertyChanged interface if you want your objects to work properly with the data binding.

In Silverlight 4 and earlier, you could not derive from System.Type or System.Reflection.PropertyInfo, but these APIs were changed in Silverlight 5 Beta. Here is the list of types that are now inheritable:

Creating a Helper Class

OK, implementing your own type and using reflection APIs might not be easy, but on the other hand it’s very flexible. What’s good is that you can write all this code just once and create a helper class that can be reused over and over.

I created such a helper class myself and you are free to use it in your code. This helper allows you to combine statically defined properties with dynamic ones. The Silverlight team is considering releasing this helper later as a part of the toolkit, so your feedback is really appreciated.

Just to be clear, the helper class is not a requirement for using this feature and you can handle things differently. Also, my implementation of the helper class is not the only possible implementation – you are welcome to change it according to your needs or write your own.

The structure of my helper class looks as follows:

 public class CustomTypeHelper<T> : ICustomTypeProvider, 
                                   INotifyPropertyChanged
{
    private static List<CustomPropertyInfoHelper> _properties = 
        new List<CustomPropertyInfoHelper>();
    private Dictionary<string, object> _customPropertyValues;
    private CustomType _ctype;

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String info) {}
    
    public CustomTypeHelper() {}

    public Type GetCustomType()

    public static void AddProperty(String name) {}
    public static void AddProperty(String name, Type propertyType) {}
    public static void AddProperty(
         String name, Type propertyType, List<Attribute> attributes) {}

    public void SetPropertyValue(string propertyName, object value) {}
    public object GetPropertyValue(string propertyName) {}

    public PropertyInfo[] GetProperties() {}

    private class CustomType : Type {}

    private class CustomPropertyInfoHelper : PropertyInfo {}
}

You can download the source code for CustomTypeHelper<T> class and example of its usage. In this class, the list of properties is a static list, so that if you add a new property it will be added to all instances of this class. The values of properties for each instance are stored in the _customPropertyValues dictionary. The class is generic, so you can use it for different types (for example, create Customer and Product classes with their own sets of properties).

You might notice that this helper class doesn’t allow for removing or changing properties. The feature itself doesn’t prohibit this, but it is hard to handle changes in the structure of the existing objects in a generalized helper class. You’d better figure it out for each particular application. But once again, I am looking for your feedback and if you can think of common scenarios or envision some kind of a general solution, let me know.

Using a Helper Class

Let’s see how you can use such a class. Imagine that you have a DataGrid named dataGrid1 and you want to bind it to a collection of objects that can add new properties at runtime. There are two options for using the CustomTypeHelper<T> class. First, you can simply inherit it.

 public class Customer : CustomTypeHelper<Customer>
{
    public String FirstName { get; set; }
    public String LastName { get; set; }
}

If you need to preserve your own class hierarchy, you can use the classic delegation pattern. In this case you need to implement the ICustomTypeProvider on your class and also create a property or a field of the CustomTypeHelper<T> class to which you can delegate all the calls.

 public class Customer : ICustomTypeProvider
{
    public String FirstName { get; set; }
    public String LastName { get; set; }

    private CustomTypeHelper<Customer> helper = 
        new CustomTypeHelper<Customer>();

    // Redirect all method calls to the helper like shown below
    public Type GetCustomType()
    {
        return helper.GetCustomType();
    }

    public static void AddProperty(String name)
    {
        CustomTypeHelper<Customer>.AddProperty(name);
    }

    // ... Do the same for all other methods from CustomTypeHelper<T>
}

No matter whether you create your class through inheritance or by using the delegation pattern, you can use it for adding properties and data binding as shown below.

 ObservableCollection<Customer> customers = new ObservableCollection<Customer>();

public MainPage()
{
    InitializeComponent();

    dataGrid1.AutoGenerateColumns = true;
    dataGrid1.ItemsSource = customers;

    Customer.AddProperty("Age", typeof(int));
    Customer.AddProperty("Married", typeof(bool));

    Customer customer1 = new Customer 
        { FirstName = "Mary", LastName = "Smith" };
    customer1.SetPropertyValue("Age", 40);
    customer1.SetPropertyValue("Married", true);

    Customer customer2 = new Customer 
        { FirstName = "John", LastName = "Smith" };
    customer2.SetPropertyValue("Age", 45);
    customer2.SetPropertyValue("Married", true);

    customers.Add(customer1);
    customers.Add(customer2);
}

As you can see, most of the reflection aspects can be hidden in the helper class and the public interface can be made pretty simple.

What about WPF and DLR?

Some of you might be familiar with the ICustomTypeDescriptor interface from WPF, which is solving the same problem as ICustomTypeProvider in Silverlight 5 (even the names are quite similar). So, why didn’t we simply add ICustomTypeDescriptor? The reason is that WPF’s interface requires its own hierarchy of classes (TypeDescriptor, EventDescriptor, etc.) which basically duplicates the reflection hierarchy and also increases the size of the installation package. It is more convenient to use the reflection hierarchy directly. In fact, this new reflection-based model is considered for both WPF and Silverlight. However, the next Silverlight release ships earlier than WPF, so for a while there will be some inconsistency in these APIs.

Another question that many of you might have is whether this feature has anything to do with the Dynamic Language Runtime (DLR), which is a part of the .NET 4 Framework. The answer is no, it’s an independent feature.

Since it’s already a popular question, let me explain why. The DLR objects such as ExpandoObject or DynamicObject (or any other implementation of the IDynamicMetaObjectProvider interface) do not carry any type information for their properties. The data binding engine, on the other hand, needs to get this information in order to perform type conversion for anything other than String.

For example, imagine that you have a text box bound to a property of the System.DateTime type. When you enter a value to this text box you of course enter just a string of characters. But the data binding engine checks the type of the bound property and converts the text box value from string to the necessary date format and vice versa. However, if you bind to a property of let’s say an ExpandoObject, the type of the property itself will simply change to string in this case and no data conversion will be possible. This is exactly what’s happening in WPF: you can bind DLR objects to UI elements, but no type conversion is happening, all you get from UI is strings.

So, while DLR is very convenient for interacting with other platforms and languages, it’s not really suitable for data binding and interacting with the UI of your own application.

Downloads, Links, and Feedback

The feature is available in Silverlight 5 Beta. The helper class source code and usage example are also available. Here are the links:

And of course, your feedback is appreciated here in comments, on Silverlight forums, and at UserVoice.

ICustomTypeProviderSample.zip