ObservableCollection Base Class With Expression Blend Designer Support

by Dean 18. January 2009 23:54

One of the big issues for me with using Expression Blend for design in conjunction with VS2008 for the hard coding, is that you need to create at least test data loading stubs in the middle tier, delivered over WCF/WS in order visualize databound controls in the Silverlight app.

This means that you often need to have everything ‘working’ on the data delivery backend before you can effectively design the visual elements, otherwise you’ll be trying to work with empty ListBoxes and DataGrids etc.

In order to solve this problem, I have designed a base collection class that automatically generates test data in debug builds, but loses all of that redundant functionality for efficiency and security in release builds.

Without further ado – here is the code for the base class I am using for my data collections
(explanations follow)

 

    public class CollectionBase<T> : ObservableCollection<T>
    {
        private static readonly Random rand = new Random(DateTime.Now.Second);
        public CollectionBase() : base()
        {
            BuildTestData();
        }
 
        [Conditional("DEBUG")]
        public virtual void BuildTestData()
        {
            var props = typeof (T).GetProperties();
            for (var i=0; i < rand.Next(5,30); i++)
            {
                var item = (T)Activator.CreateInstance(typeof(T));
                foreach (var prop in props)
                {
                    switch (prop.PropertyType.Name)
                    {
                        case "String":
                            prop.SetValue(item,GetTestString(),null);
                            break;
                        case "DateTime":
                            prop.SetValue(item, GetTestDateTime(),null);
                            break;
                        case "Double":
                            prop.SetValue(item, (double)rand.Next(10000), null);
                            break;
                        case "Int32":
                            prop.SetValue(item, rand.Next(10000), null);
                            break;
                        case "Decimal":
                            prop.SetValue(item, (decimal)rand.Next(10000), null);
                            break;
                        case "Boolean":
                            prop.SetValue(item, rand.Next(0,1) == 0, null);
                            break;
                    }
                }
                Add(item);
            }
        }
 
        private static DateTime GetTestDateTime()
        {
            return DateTime.Now.AddSeconds(rand.Next(-2500000, 0));
        }
 
        private static string GetTestString()
        {
            var count = rand.Next(5,10);
            var chars = new char[count];
            for (var i = 0; i < count ; i++ )
                chars[i] = (char)rand.Next('A', 'Z');
            return new string(chars);
        }
    }


And the code for an example collection class that inherits from this base class is below

    public class PersonCollection : CollectionBase<Person>
    {
 
    }

As you can see, once you have the base class you just create an inheritor with the appropriate data object type in the class declaration.

Once armed with collection classes for all of your required types, you can easily use drag and drop in Blend to create data sources form the collection classes.

Once these data sources are then dragged onto a data-bound control in Blend, you will automatically see data appear in the control – thus enabling you to effectively apply your design skills to the control.

Now let me explain certain aspects of the code above

  1. the use of the [Conditional(“DEBUG”)] attribute -
    This is required in order for the code not to appear in the compiled MSIL in release (production) builds. Having the test data code in release builds may represent a security risk and/or an impediment to performance.
  2. Making the BuildTestData() method ‘virtual’ will allow the implementer to create their own test data building logic. I know your not supposed to call virtual members in a class constructor, but I think the pro’s outweigh the cons.
  3. There are some private static methods for creating test strings and dates etc. These are static on order to increase efficiency in the CLR.

I hope you find the above class useful. Im using it in current projects, and its working well. Once I have my services up and running, I can simply change the bindings in order to get the real data flowing:

PersonGrid.ItemsSource = MainService.GetEmployees();

If anyone has any improvements that can be made to this idea, please let me know.

Dean Chalk

Addendum – For a good example of how to use this technique – go to my next blog post here

Tags: ,

Silverlight

blog comments powered by Disqus
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010 Dean Chalk's Blog