Ron Jacobs

Windows Workflow Foundation

How to make a library portable and data binding friendly at the same time?

How to make a library portable and data binding friendly at the same time?

Rate This
  • Comments 2

Here is the challenge. 

  1. Create a portable library that could be used by almost anything including Console Apps, Windows Phone, ASP.NET, Xbox 360
  2. Make it data binding friendly for targets like WPF, Silverlight and Windows 8 XAML Metro Apps by supporting property and collection changed notifications.
  3. Make it efficient so that users who don’t need data binding are not penalized with a performance hit and having to reference libraries they don’t need.
  4. Write Unit Tests to demonstrate that the solution works for both data binding and non-data binding users.

I was a little stumped so I decided to ask about this on StackOverflow see C# Class library collections ObservableCollection T vs Collection T and based on what the community came up with, here is my solution – can you do better?

Download Sample Code

The Base Class: Foo

If you don’t want data binding, Foo is for you.  It is a simple class.  It has a property “Num” and a collection “Strings” with a method called Populate().  You’ll notice that I created some virtual members to allow the derived class to do what it needs to do.

public class Foo
{
private readonly Collection<string> strings = new Collection<string>();

/// <summary>
/// Gets the Num value
/// </summary>
/// <remarks>
/// This property is virtual so that the derived Observable class can provide property changed notifications
/// </remarks>
public virtual int Num { get; set; }

/// <summary>
/// Gets the collection of strings
/// </summary>
public ReadOnlyCollection<string> Strings
{
get
{
return new ReadOnlyCollection<string>(this.strings);
}
}

/// <summary>
/// The collection of strings
/// </summary>
/// <remarks>
/// This property is protected virtual so that the Observable class can substitue an
/// ObservableCollection
/// </remarks>
protected virtual ICollection<string> StringsCollection
{
get
{
return this.strings;
}
}

/// <summary>
/// Populates the string collection
/// </summary>
/// <param name="max">The maximum size for the collection</param>
public void Populate(int max = 1000)
{
// If no num was specified, create a random value
if (Num == 0)
{
var r = new Random();
this.Num = r.Next(1, max);
}

if (Num > max)
{
throw new InvalidOperationException("Num is greater than max");
}

for (var i = 0; i < this.Num; i++)
{
this.StringsCollection.Add(string.Format("string {0}", i));
}
}
}

The Derived Class: ObservableFoo

ObservableFoo is just like Foo except that it is data binding ready because it supports INotifyPropertyChanged and uses an ObservableCollection<string> to do it’s work.  The first thing ObservableFoo must do is to get the base class Foo to use an ObservableCollection<string> so it overrides the StringCollection property.

Second, Foo.Strings is a ReadOnlyCollection<string> which won’t do for data binding.  Instead we need to return a  data binding friendly ReadOnlyObservableCollection<string>. To do this I hide the Foo.Strings property with the new modifier.

Third, I override the Num property so I can fire a PropertyChanged notification when it is set.

Finally, I place ObservableFoo into a different assembly named FooLibrary.Observable since this project must reference System.Windows and forces all those who use it to do the same.

public sealed class ObservableFoo : Foo, INotifyPropertyChanged
{
private readonly ObservableCollection<string> strings = new ObservableCollection<string>();

public event PropertyChangedEventHandler PropertyChanged;

public override int Num
{
get
{
return base.Num;
}
set
{
base.Num = value;
this.OnPropertyChanged("Num");
}
}

public new ReadOnlyObservableCollection<string> Strings
{
get
{
return new ReadOnlyObservableCollection<string>(this.strings);
}
}

protected override ICollection<string> StringsCollection
{
get
{
return this.strings;
}
}

private void OnPropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

The Unit Tests

Testing Foo is pretty straight forward so I won't go into detail about that here, but testing ObservableFoo was quite interesting.  I have found that in most projects with Model / View / View Model (MVVM) that people neglect to test property change notifications.  Then you get subtle bugs in the UI because the property change notifications are not firing as expected.  I wanted to create a test that would verify that ObservableFoo was indeed observable so I created the FooObserver.  First a test that uses it.

/// <summary>
/// Given
/// * An ObservableFoo
/// When
/// * Populated
/// Then
/// * The number of CollectionChangedNotifications is equal to Num
/// * The number of PropertyChangedNotifications is equal to Num * 2
/// </summary>
[TestMethod]
public void ObservableFooRaisesChangeNotificationsWhenPopulated()
{
// Arrange
const int Expected = 100;
const int ExpectedPropNotifications = Expected * 2;

var foo = new ObservableFoo() { Num = Expected };

// Create an observer to monitor the notifications
var observer = new FooObserver(foo);

// Act
foo.Populate();

// Assert
// Each item that was added to the collection should trigger a CollectionChangedNotification
Assert.AreEqual(Expected, observer.CollectionChangedNotifications.Count);

// Each time an item is added 2 property changed notifications are raised
// Count and Item[]
Assert.AreEqual(ExpectedPropNotifications, observer.PropertyChangedNotifications.Count);
}

Here you can see that my observer simply attaches itself to the ObservableFoo and captures the notifications received so I can assert them.  The implementation is not too difficult but interesting.

public class FooObserver
{
private readonly Collection<NotifyCollectionChangedEventArgs> collectionChangedNotifications =
new Collection<NotifyCollectionChangedEventArgs>();

private readonly Collection<PropertyChangedEventArgs> propertyChangedNotifications =
new Collection<PropertyChangedEventArgs>();

public FooObserver(ObservableFoo foo)
{
((INotifyCollectionChanged)foo.Strings).CollectionChanged += this.ObservableStringsOnCollectionChanged;
((INotifyPropertyChanged)foo.Strings).PropertyChanged += this.OnPropertyChanged;
foo.PropertyChanged += this.OnPropertyChanged;
}

public ReadOnlyCollection<NotifyCollectionChangedEventArgs> CollectionChangedNotifications
{
get
{
return new ReadOnlyCollection<NotifyCollectionChangedEventArgs>(this.collectionChangedNotifications);
}
}

public ReadOnlyCollection<PropertyChangedEventArgs> PropertyChangedNotifications
{
get
{
return new ReadOnlyCollection<PropertyChangedEventArgs>(this.propertyChangedNotifications);
}
}

private void ObservableStringsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
this.collectionChangedNotifications.Add(args);
}

private void OnPropertyChanged(object sender, PropertyChangedEventArgs args)
{
this.propertyChangedNotifications.Add(args);
}
}

What Now?

Frankly, I hate to ship another assembly, thankfully NuGet will make this less painful. If this works as well as it appears to, I suppose I will start shipping data binding friendly versions of some of the types found in Microsoft.Activities.Extensions. Am I on the right track? After all, I could be missing something obvious. I could just make the base classes data binding friendly and make everyone reference System.Windows. The performance penalty is not that great, but then when there is a good solution why not use it?

Happy Coding!

Ron Jacobs
blog: http://blogs.msdn.com/rjacobs
Twitter: @ronljacobs

  • The one thing I don't like about this - if your library also creates the Foo, which does it create?

    Since it's an either/or rather than a wrapper, at the time of creation you have to decide if the consumer will want a Foo or ObservableFoo.  So you need to do something like give multiple methods that return based on what the consumer calls, or you need some kind of global switch - neither of which is ideal.  You could allow the consumer to pass in the FooFactory (FooFactory.Observable) but that just makes your API all that more complicated.      Multiply this by the number of Foo Classes, and I'm not sure I love this idea yet.

    And before you ask no, I have nothing better - I'm throwing these stones from inside my glass house.

  • Good point.  The caller would have to decide which one they want.  If my library needed to create one I'd have to come up with a way such as a factory.  It's a tricky problem and when you account for the issues with threading it gets even more complicated.  It's definitely interesting to think about.

Page 1 of 1 (2 items)