Null Object pattern for a WPF ComboBox’s deselected value

Last week, I encountered a problem doing some fiddly UI behaviour in a Prism/MVVM app. I wanted something like this:

I wanted a ComboBox where you can choose one of the available options, or none of them. Null, deselected, whatever.

Unfortunately for me, WPF doesn’t support binding null values in ComboBoxes, ListBoxes or ListViews. Now this is a pretty common problem, and a quick google reveals a few solutions available to this problem:

However, if like us, your domain model is all nicely decoupled through interfaces, the easiest way to get null values into a ComboBox is with the null object pattern. (And thankfully for me doesn’t require any knowledge of WPF control internals to implement).

Here’s what my null object looked like:

public class NullCurve : IFxCurve, IEquatable<NullCurve>
{
    public string Name { get { return ""; } }

    public void DoStuff() {} // Has no implementation

    // Note the equality overload. Null objects are value types -- they
    // have no identity, and are all equal.
    public bool Equals(NullCurve other)
    {
        return other != null;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as NullCurve);
    }

    public override int GetHashCode() { return -1; }
}

To use it, you simply pop a null object at the start of your list. And check whether it was selected on submit:

public class FxCurveSelectionViewModel : ViewModelBase
{
    public ObserableCollection<IFxCurve> AvailableCurves { get; private set; }
    public IFxCurve SelectedCurve { get; set; }

    public FxCurveSelectionViewModel(ICurveRepository curves)
    {
        AvailableCurves = new ObservableCollection<IFxCurve>();
        AvailableCurves.Add(new NullCurve());
        AvailableCurves.AddRange(curves.GetAllCurves());
    }

    public void Submit()
    {
        if (SelectedCurve.Equals(new NullCurve()))
            // nothing was selected
    }
}

XAML binding is standard; no need to change anything because we handle it all in the view model. Which arguably is not the most DRY solution long-term, but sufficient until I learn more about WPF internals to do it elegantly with XAML.

March 27, 2010

6 Comments

Daniel on March 28, 2010 at 12:09 pm.

Could BindingBase.TargetNullValue be of any use ?

http://msdn.microsoft.com/en-us/library/system.windows.data.bindingbase.targetnullvalue.aspx

Kevin Berridge on March 28, 2010 at 8:04 pm.

Other than for this, why do you have all of your models implement interfaces?

Simon Fox on March 28, 2010 at 9:49 pm.

This solution may help in this case, follow the link in the comments for a solution for binding the CollectionContainer http://stackoverflow.com/questions/2151710/how-do-you-add-a-generic-item-to-a-combobox-bound-to-a-collection-in-wpf/2152119#2152119

Richard on March 29, 2010 at 9:06 am.

Kevin : we start with classes for entities, but usually end up extracting interfaces so we can mock their behaviour in tests for collaborating objects.

Richard on March 29, 2010 at 9:44 pm.

Daniel : I believe TargetNullValue would be good for displaying the null value, but the ComboBox wouldn’t let you return to null after choosing something.

Simon : if I can put null in a CompositeCollection, that would be a better solution. Will try it out.

Leave a Reply