Use Interfaces to Keep it Loose in the UI

We have all been using interfaces in .NET and even before that to maintain loose coupling between objects.  These days this is most often done for things like a data provider layer, a plug-in model where assemblies are loaded at run-time, and various other “behind the UI” areas of functionality.  The idea behind using interfaces is to allow us to program against the interface and not the object class itself, so that the object class can be swapped out for another one that implements that interface and the caller never knows. 

I have been working on a rapid UI prototyping effort for the past couple years and we have taken this use of interfaces to the UI layer, where I don’t see them used much, to allow us to remain very de-coupled amongst the various pieces of UI. 

If you’re developing WPF apps, you have most likely heard of the Model-View-ViewModel pattern, whereby the ViewModel is the DataContext for the View and it’s job is to transform and store the Model data in such a way to allow easy data binding from the View.   Typically you have a different VM for each view and even for “sub-views” or even items in a list, so hooking them all together gets complicated.  We have added the use of C# interfaces to these ViewModels to keep us from coupling them all together where they’re rely on their relative position to each other, allowing us to quickly and easily move things around.  Many times in rapid prototyping, the requests come streaming in:  “move this over there, change this list to a toolbar, make this other thing a menu, get rid of that thing and replace it with this thing” …

If you have all these “widgets” (ViewModels) in the UI tied together with binding statements or other tightly coupling coding practices, you will be doing LOTS of refactoring when these requests come in. 

We chose to represent the logical chunks of functionality found in the ViewModels as interfaces and hook ViewModels up by passing interfaces around.  This way, if a request comes in to move/replace/change the look or placement of the view, as long as you replace it with one that either talks to the same ViewModel, or minimally a new ViewModel that implements the same interface as the one you’re replacing, no other code has to change.

Let’s go through a simple example to illustrate what I’m talking about.

I threw together a pretty standard Master-Detail type of UI, one that shows Super Bowl players on the left, and shows details about the selected one on the right.


You could certainly write this as a simple WPF app with all XAML based Binding statements using ElementName bindings to each other, but then when the request comes across your desk to move the ListBox area to a Menu or a completely different view in a popup or some such, you’ll be bumming on the XAML bindings idea.

Instead, we’re going to implement the 2 different pieces of the app (master and detail) as two different ViewModels, and the one that handles selection of a player will do so as an interface.

We create a ViewModel called PlayerListVM for the player selection area (ListBox) that backs the UI area that holds the ListBox.

When looking at its main duty as the ViewModel for player selection (tracking the currently selected player), we can express that in an interface called IPlayerSelection.

// PlayerListVM.cs

interface IPlayerSelector{    Player CurrentPlayer { get; }    event EventHandler PlayerChanged;}

class PlayerListVM : IPlayerSelector, INotifyPropertyChanged{  ...

  private Player _currentPlayer;  public Player CurrentPlayer  {    get { return _currentPlayer; }    set    {      if ( value != _currentPlayer )      {        _currentPlayer = value;        OnPropertyChanged( "CurrentPlayer" );      }    }  }}

Now when we create the Details view, we feed the IPlayerSelector interface to the PlayerDetailsVM, and then expose the interface as a public property of the ViewModel so the View can bind to it in XAML.

// PlayerDetailsVM.cs

public PlayerDetailsVM( IPlayerSelector playerSelector ){   PlayerSelector = playerSelector;}

private IPlayerSelector _playerSelector;public IPlayerSelector PlayerSelector{    get { return _playerSelector; }    set    {        if ( value != _playerSelector )        {            _playerSelector = value;            OnPropertyChanged( "PlayerSelector" );        }    }}

As you can see, we do this via a constructor argument.  The code that creates the ViewModels creates the PlayerListVM, and when creating the PlayerDetailsVM, it passes the IPlayerSelector interface (the PlayerListVM) in the constructor.  The bottom line is that the PlayerDetailsVM has a dependency on the IPlayerSelector interface, which needs to be set for the VM (and its view) to work correctly.

    PlayerListVM playerListVM = new PlayerListVM();    DataContext = playerListVM;

    PlayerDetails details = new PlayerDetails();    details.DataContext = new PlayerDetailsVM( playerListVM );

OK – so you Blend people out there (or even those that like to construct and wire up the DataContext of a View to its ViewModel in XAML) are now saying, “but wait, I don’t want this code-based dependency injection!”. 

Easy enough if you use an Inversion of Control (IOC) container to resolve dependencies for you.  Here’s how I did it with Microsoft’s Unity framework:

// App startup ...

PlayerListVM playerListVM = new PlayerListVM();DataContext = playerListVM;

// Register this interface in the IOC container for others to useApp.IOC.RegisterInstance<IPlayerSelector>( playerListVM );

// -- PlayerDetailsVM.cs --

public PlayerDetailsVM()  // now it's a no-arg ctor{  // use IOC container to resolve dependency  PlayerSelector = App.IOC.Resolve<IPlayerSelector>();}

// -- PlayerDetails.xaml --// you can also setup the DataContext in XAML now

<UserControl ...>  <UserControl.DataContext>    <viewModel:PlayerDetailsVM />  </UserControl.DataContext></UserControl>

You get rid of the constructor-based dependency on the PlayerDetailsVM class and it resolves its dependency on IPlayerSelector on its own.  (and you can even do the ViewModel construction and binding in the View’s XAML)

So now your XAML for the details view goes from tightly bound ElementName-based bindings to much more loosely coupled interface-based bindings like this:

<!-- PlayerDetails.xaml -->

<!-- tightly bound XAML, based -->
<TextBlock Text="{Binding SelectedItem.Team, ElementName=PlayerList}" />

<!-- Access the CurrentPlayer via the interface, stored in the VM -->
<TextBlock Text="{Binding PlayerSelector.CurrentPlayer.Team}" />

Admittedly, all this is definitely overkill for a simple master-detail app like I’m showing.  It has worked very well though for our UI that has over 10 ViewModels all playing together at the same time, and on more than one occasion had to be moved, changed, or replaced.

Hope that’s helpful. 

Here is a zip of the sample project that shows the loosely coupled ViewModels.

Leave a Reply

Your email address will not be published. Required fields are marked *