We're working on a series of classes here at work which form a domain model which will some day be accessed from both a PC client (using Windows Presentation Foundation) and a mobile client (using the .NET Compact Framework).

Targeting two different frameworks from the same set of classes is usually not too big a challenge, but we recently found one case that stumped us.

Imagine, if you will, that you have a class called "Order" which stores a collection of "OrderItem" objects. So the order itself has the customer, the date etc, and each item within the order has a product, quantity etc. We define our order's items property thusly:

private IList<OrderItem> _items = new List<OrderItem>();
public IList<OrderItem> Items { get { return _items; } }

Pretty straight forward, really. However, we decided that we wanted to bind directly to the Items property of our order from within our WPF client, and we therefore wanted to make use of .NET 3.0's ObservableCollection<T> property. So our first instinct was to simply do this:

private IList<OrderItem> _items = new ObservableCollection<OrderItem>();
public IList<OrderItem> Items { get { return _items; } }

Sounds reasonable, right? And it is, until you realise that ObservableCollection<T> is not available on the compact framework. Now our class won't compile to a mobile version of the assembly. To get nice collection data-binding on the compact framework you pretty much have to use BindingList<T>.

We tossed around a few solutions. One idea was to make a "CollectionFactory" class which would have a different implementation in the "desktop" version of the assembly and the "mobile" version. The code would then morph into something like this:

private IList<OrderItem> _items = CollectionFactory.New<OrderItem>();
public IList<OrderItem> Items { get { return _items; } }

I still believe that this idea would work, but now I'm considering another approach. We've learned a lot recently about dependency injection, and have been structuring our classes in such a way that each class accepts its dependencies as constructor parameters. I'm starting to wonder now whether the implementation of a collection should be a dependency too. So now instead of constructing the _items list in its declaration, we would accept it as a parameter to the class itself, like this:

class Order
{
    public Order(IList<OrderItem> items)
    {
        _items = items;
    }

    public Order() : this(new List<OrderItem>())
    {
    }

 

There are drawbacks to this approach. The calling code could pass in a non-empty list. I guess we could call Clear() on the list first, but it still seems hackish. The calling code could also construct more than one Order instance with the same list of OrderItems, which is a bit ugly too.

Another approach would be generics:

class Order<T> where T : IList<OrderItem>, new()
{
    public Order()
    {
        _items = new T();
    }

And this works nicely but makes the code to instantiate a new order look pretty messy. Or we could use lambdas and just ask for how to make a new list:

class Order
{
    public Order(Func<IList<OrderItem>> itemsGenerator)
    {
        _items = itemsGenerator();
    }

This is kinda cool too, but has similar problems to simply passing the list in as an object.

One last approach would be to define our own ObservableCollection<T> class in the mobile version of the assembly, by simply deriving it from BindingList<T>. If we never explicitly used any of ObservableCollection<T>'s unique methods or properties from within our assembly then that could work.

Have you solved this particular problem? Hey Microsoft! When can we have ObservableCollection<T> and INotifyCollectionChanged in the compact framework?