Colin Eberhardt's Technology Adventures

An Introduction and Thoughts on Developing iOS Applications with MonoTouch

July 24th, 2012

This blog post describes the creation of a simple twitter search application for iOS, based on a similar application I wrote for Windows Phone a few months back. In this blog post I’ll used the MonoTouch platform, which allows you to write iOS applications using C#. This blog posts describes my experiences, and how it compares to Windows Phone and .NET development in general.


Colin Eberhardt is CIO at ShinobiControls, suppliers of highly interactive and fun charts, grids and UI controls for iOS developers.

With the rise in popularity of smartphones, tablets and the web as a platform, now is the time for developers to diversify and learn new skills. A few years ago, .NET was a dominant force, but recent statistics have shown a real drop in demand for .NET developers. I have been busy picking up new skills, mostly in HTML5-related technologies, but more recently I have been eyeing up iOS as a result of my work with ShinobiControls, which are an iOS UI component vendor.

Whilst the transition from .NET to HTML5 means learning new languages and frameworks, for the most part, the tools (Visual Studio + Windows PC) remain the same. Transitioning from .NET to iOS means that everything changes! There’s a new language, Objective-C, the Cocoa Touch framework, new tools, Xcode, and the Mac OS itself. When learning new skills we tend to gravitate towards the most familiar concepts, these allow us to adapt and use our existing skill. The first time I fired up a Mac, fumbled around to find Xcode, and stared blankly at some Objective-C, I realised there are very few familiar footholds for a .NET developer to leverage when climbing the iOS learning mountain. MonoTouch helps make the transition from .NET to iOS development a little less daunting by allowing you to leverage your existing C# skills.

The Mono framework has had a long history, originally been released in 2004 as an open source implementation of the Microsoft .NET framework. The Mono framework covers many of the core .NET frameworks (ASP.NET, WPF, WinForms), but more recently it has extended its reach to mobile devices, providing an alternative to HTML5 for cross platform mobile application development. Released under the Xamarin banner you can download the tools required to develop C# application for iOS (MonoTouch) and Android (Mono for Android). I originally ‘pigeonholed’ MonoTouch as a technology for cross-platform applications, however, on meeting a number of MonoTouch developers I have found that the majority use this technology simply to leverage their C# and .NET skills for iOS development.

In this blog post I’ll share my impressions of MonoTouch and the first application which I wrote. As a starting point I decided to create an iOS port of the simple Twitter-Search application I developed a few months back to demonstrate the use of the MVVM pattern for Windows Phone development.

From MVVM to MVP

In order to get started with MonoTouch development, you need a Mac, Xcode and MonoDevelop (the graphical IDE for MonoTouch development). You can find information regarding the required tools and where to find them on the Xamarin website.

The Windows Phone twitter search application which I previously wrote uses the Model-View-ViewModel (MVVM) pattern, which is pretty much the de-facto pattern for Windows Phone, Silverlight and WPF development. The first step I took in migrating this application to iOS was to copy the view models into the project that I created via the MonoTouch project template. I was happy to see that these classes, which make use of Linq, Linq-to-XML and various other base-classes compiled immediately!

With an MVVM application the View Model state is kept in synch with the UI via the built-in binding framework. Unfortunately iOS doesn’t have a binding framework, as a result iOS developers do not use the MVVM pattern.

With the MVVM pattern the direction of ‘visibility’ is as follows:

i.e. the View Model is aware of the Model, but the Model is not aware of the View Model. Likewise, the View is aware of the View Model, but not vice-versa. In the absence of a binding framework, you have to manually ‘bind’ the view model to the UI, handling property and collection changes and updating the view accordingly. As an alternative, we give the View Model a reference to the View, allowing it to ‘push’ these changes directly to the view. This change of visibility means that we are no longer using the MVVM pattern, the View Model is now a Presenter as described by the Model View Presenter (MVP) pattern:

I tend to use the pattern where the view for a presenter is declared as an inner-interface of the presenter class (a convention I learnt from using Google Web Toolkit). Properties that would raise PropertyChanged events in a View Model now invoke methods on the View interface to indicate their state change. The View interface can also define events in order to indicate user interactions in place of commands. The complete presenter for my iOS application is given below:

public class TwitterSearchPresenter
{
  /// <summary>
  /// The interface that this presenter depends upon
  /// </summary>
  public interface View
  {
    string SearchText { get; }
 
    void SetIsSearching(bool isSearching);
 
    void SetSearchResults(List<TweetViewModel> results);
 
    event EventHandler StartSearch;
  }
 
  private readonly string _twitterUrl = "http://search.twitter.com/search.atom?rpp=100&&q=";
 
  private View _view;
 
  public TwitterSearchPresenter()
  {
  }
 
  // assocaites this presenter with a view
  public void SetView(View view)
  {
    this._view = view;
 
    // handles events from the view
    view.StartSearch += View_StartSearch;
  }
 
  private void View_StartSearch(object sender, EventArgs e)
  {
    string uri = _twitterUrl + _view.SearchText;
 
    _view.SetIsSearching(true);
 
    WebClient client = new WebClient();
    client.DownloadStringCompleted += Client_SearchComplete;
    client.DownloadStringAsync(new Uri(uri), null);
  }
 
  private void Client_SearchComplete(object sender, DownloadStringCompletedEventArgs e)
  {
    var tweets = ParseXMLResponse(e.Result);
    _view.SetSearchResults(tweets);
    _view.SetIsSearching(false);
  }
 
  /// <summary>
  /// Parses the response from our twitter request, creating a list of TweetViewModel instances
  /// </summary>
  private List<TweetModel> ParseXMLResponse(string xml)
  {
 
    var doc = XDocument.Parse(xml);
    var items = doc.Descendants(AtomConst.Entry)
                      .Select(entryElement => new TweetModel()
                      {
                        Title = entryElement.Descendants(AtomConst.Title).Single().Value,
                        Id = long.Parse(entryElement.Descendants(AtomConst.ID).Single().Value.Split(':')[2]),
                        ProfileImageUrl = entryElement.Descendants(AtomConst.Link).Skip(1).First().Attribute("href").Value,
                        Timestamp = DateTime.Parse(entryElement.Descendants(AtomConst.Published).Single().Value),
                        AuthorId = ExtractTwitterAuthorId(entryElement.Descendants(AtomConst.Name).Single().Value),
                        AuthorName = ExtractTwitterAuthorName(entryElement.Descendants(AtomConst.Name).Single().Value)
                      }
    );
 
    return items.ToList();
  }
 
  private static string ExtractTwitterAuthorId(string name)
  {
    return name.Substring(0, name.IndexOf(" "));
  }
 
  private static string ExtractTwitterAuthorName(string name)
  {
    int bracketIndex = name.IndexOf("(") + 1;
    return name.Substring(bracketIndex, name.Length - bracketIndex - 1);
  }
}

Creating a View

Now that we have a presenter, we need a view!

Windows Phone applications are composed of PhoneApplicationPage instances, the iOS equivalent is a UIViewController. MonoDevelop does not have a built-in editor for view controllers, however, double-clicking the XIB files (which are roughly equivalent to XAML files), launches the Xcode Interface Builder. This tool allows you to create the UI via a simple drag and drop interface. The UI for my application is shown below:

Interface Builder also allows you to wire up controls and their ‘events’ to your Objective-C code, using outlets and actions. The screenshot above shows how I have created outlets for the text-field, activity-indicator and table-view controls, together with an action which is invoked when the search button is pressed.

When you save the view-controller file, MonoDevelop steps in and performs its magic, generating a C# partial class with properties for each outlet and partial methods for actions:

[Register("TwitterSearchViewController")]
partial class TwitterSearchViewController
{
  [Outlet]
  MonoTouch.UIKit.UITextField txtSearch { get; set; }
 
  [Outlet]
  MonoTouch.UIKit.UITableView tweetList { get; set; }
 
  [Outlet]
  MonoTouch.UIKit.UIActivityIndicatorView activityIndicator { get; set; }
 
  [Action("searchButtonPressed:")]
  partial void searchButtonPressed(MonoTouch.Foundation.NSObject sender);
 
  void ReleaseDesignerOutlets()
  {
    ...
  }
}

The net result is that you can wire-up UI controls in much the same way you would using the VS designer.

Your view logic is placed in the associated partial class, in my example this implements the view interface declared by the presenter. It didn’t take me too long to navigate round the API for the various UI controls, using the Xamarin MonoTouch reference as a guide:

public partial class TwitterSearchViewController : UIViewController, TwitterSearchPresenter.View
{
  public TwitterSearchViewController()
    : base("TwitterSearchViewController", null)
  {
    this.Title = "Twitter Search";
  }
 
  ...
 
  public string SearchText
  {
    get
    {
      return txtSearch.Text;
    }
  }
 
  public void SetSearchResults(List<TweetViewModel> results)
  {
    tweetList.Source = new TableSource(NavigationController, results.ToArray());
    tweetList.ReloadData();
  }
 
  public void SetIsSearching(bool isSearching)
  {
    if (isSearching)
    {
      activityIndicator.StartAnimating();
      tweetList.Hidden = true;
    }
    else
    {
      activityIndicator.StopAnimating();
      tweetList.Hidden = false;
    }
  }
 
  partial void searchButtonPressed(NSObject sender)
  {
    // hide the keyboard
    txtSearch.ResignFirstResponder();
 
    // start the search
    OnStartSearch();
  }
 
  public event EventHandler StartSearch;
 
  protected void OnStartSearch()
  {
    if (StartSearch != null)
    {
      StartSearch(this, EventArgs.Empty);
    }
  }
 
  ...
}

Handling the Enter key

When the user taps on the search box, the keyboard is shown. When they hit the enter key we would like to hide the keyboard. This is not the default behaviour for the text field control.

In the .NET world you would expect controls to raise events that you can handle in order to react to user input, for example the TextBox control raises a KeyUp event which could be used to detect an enter key press. The Objective-C approach to this is for UI controls to declare a delegate, which is defined by a protocol. You can supply a delegate to a control and it will be notified of user interactions. For example, the UITextField exposes a UITextFieldDelegate which receives notifications of user interaction.

Protocols are similar to C# interfaces, but with one subtle difference, they can have optional methods. As a result your delegate does not have to handle all of the ‘events’ that a UI control can raise. Unfortunately because C# interfaces cannot have optional methods, it is not possible to map directly from the Objective-C to the C# APIs. MonoTouch solves this by supplying base-classes for each delegate, which implements all the methods defined by a delegate’s protocol. You can sub-class this base implementation so that you just need to add the methods you are interested in.

For example, in order to hide the keyboard on enter key press, we create a delegate implementation and assign it to the UI control as follows:

public override void ViewDidLoad()
{
  base.ViewDidLoad();
 
  txtSearch.Delegate = new CatchEnterDelegate();
}
 
 
public class CatchEnterDelegate : UITextFieldDelegate
{
  public override bool ShouldReturn(UITextField textField)
  {
    textField.ResignFirstResponder();
    return true;
  }
}

This feels like a slightly peculiar pattern for an .NET developer, but it is perfectly workable.

Creating a List of Tweets

For rendering lists of items CocoaTouch provides the UITableView control. This is somewhat equivalent to the Silverlight ItemsControl in terms of where you might use it in your application, however, the API and capabilities are quite different.

In order to render data within a UITableView you must supply a datasource, which is defined by a protocol. MonoTouch again exposes this via a base-class that implements all of the protocol methods, in the case of the UITableView it also combines this with the delegate protocol. The UITableView is virtualised, which means you do not present it with your full set of data, instead you simply inform the table of the number of rows. As the user scrolls the table, the UITableView determines which rows are visible and requests the corresponding cells via the datasource protocol. The UITableView also has a built-in mechanism for re-cycling cells in order to reduce memory usage.

The datasource implementation for the twitter application is shown below:

public void SetSearchResults(List<TweetViewModel> results)
{
  tweetList.Source = new TableSource(NavigationController, results.ToArray());
  tweetList.ReloadData();
}
 
public class TableSource : UITableViewSource
{
  private TweetViewModel[] _tableItems;
  private static readonly string _cellIdentifier = "TableCell";
  private UINavigationController _navigationController;
 
  public TableSource(UINavigationController navigationController, TweetViewModel[] items)
  {
    _tableItems = items;
    _navigationController = navigationController;
  }
 
  public override int RowsInSection(UITableView tableview, int section)
  {
    return _tableItems.Length;
  }
 
  public override UITableViewCell GetCell(UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
  {
    UITableViewCell cell = tableView.DequeueReusableCell(_cellIdentifier);
    // if there are no cells to reuse, create a new one
    if (cell == null)
    {
      cell = new UITableViewCell(UITableViewCellStyle.Subtitle, _cellIdentifier);
    }
    var tweet = _tableItems[indexPath.Row];
    cell.TextLabel.Text = tweet.AuthorName;
    cell.DetailTextLabel.Text = tweet.Title;
    cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
    cell.ImageView.Image = UIImage.LoadFromData(NSData.FromUrl(new NSUrl(tweet.ProfileImageUrl)));
    return cell;
  }
}

The UITableView has a standard cell type which has text, a sub-title, an image and an ‘accessory’ (the item rendered on the right-hand edge) – each of these components is optional.

Again, much of the API was discoverable via the MonoTouch documentation. However, when I wanted to find out how to render an image from a URL the first thing I did was google it, finding the following answer via StackOverflow:

UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:MyURL]]];

It did take a little while to work out how to translate the above to my required C# equivalent:

cell.ImageView.Image = UIImage.LoadFromData(NSData.FromUrl(new NSUrl(tweet.ProfileImageUrl)));

Navigation Structure

So far my discussion of the iOS application has been based on a single view-controller. When the user clicks on a tweet, the application should navigate to a ‘detail’ page:

iOS applications can make use of a UINavigationController, which is similar to the Windows Phone NavigationContext in that it controls the navigation flow of an application, including the back-stack. However, there is a subtle difference, while the NavigationContext is not a UI control, the iOS UINavigationController is responsible for rendering the header-panel and the back-button. This results in a more uniform look and feel for iOS applications and makes it a bit easier to implement basic navigation-based applications.

Using the UINavigationController is simple, you create an instance and set it as your ‘root’ view controller. You can then navigate from one view to the next by ‘pushing’ it:

[Register("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
  // class-level declarations
  UIWindow window;
 
  public override bool FinishedLaunching(UIApplication app, NSDictionary options)
  {
    // create a new window instance based on the screen size
    window = new UIWindow(UIScreen.MainScreen.Bounds);
 
    // create our presenter and view
    var presenter = new TwitterSearchPresenter();
    var viewController = new TwitterSearchViewController();
    presenter.SetView(viewController);
 
    // create the navigation controller
    var navigationController = new UINavigationController();
    navigationController.PushViewController(viewController, false);
 
    window.RootViewController = navigationController;
 
    // make the window visible
    window.MakeKeyAndVisible();
 
    return true;
  }
}

In order to navigate from a tweet to the detail page, we simply handle the row selection within our table source / delegate:

public class TableSource : UITableViewSource
{
  ...
 
  public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
  {
    var tweet = _tableItems[indexPath.Row];
 
    var controller = new TweetViewController(tweet);
 
    _navigationController.PushViewController(controller, true);
  }
}

Conclusions

Using MonoTouch I was able to implement this simple twitter search application in the space of just a few hours. I have a feeling that if I had tried to use Objective-C, which lacks a garbage collector and a familiar syntax, it would have taken me days rather than hours. For a .NET developer starting out in the world of iOS, MonoTouch certainly helps.
However, by choosing MonoTouch over Objective-C you do make a few compromises, including an increased application size (to include the Mono framework) and the need to generate your own C# bindings for third-party libraries.

Using MonoTouch did allow me to ‘look over the fence’ at what life is like for iOS developers. One thing that immediately struck me was the performance of the UITableView. The WP7 Mango release improved scroll performance, but it is still pretty poor. In contrast the iOS UITableView is lightning fast, regardless of how much data you throw at it.

The iOS APIs also make it much easier to create applications that conform the UI design guidelines. By using the UINavigationController, your applications will have a correctly styled back-button (and will also use the fancy transitions between pages as you navigate between them). The UITableView also has a very useable set of default cell styles.

In conclusion, my feeling is that iOS development requires a bit more effort and the framework is not as ‘rich’ as the Windows Phone Silverlight framework. However, what it does have is speed and consistency. To my mind this is a pretty fair compromise.

I think you’ll see quite a bit more iOS development from me in future!

You can download the code for both the Windows Phone and iOS applications: TwitterSearch.zip

Regards, Colin E.

A gesture-driven Windows Phone to-do application Part Two – drag re-ordering

June 27th, 2012

A couple of weeks ago I blogged about a todo list application which uses gestures to achieve its basic functions, a left swipe deletes an item, while a right-swipe marks it as complete. In this blog post I am adding re-ordering which is initiated via a tap-and-hold gesture and performed via a drag.

As mentioned previously, this application is heavily inspired by the iPhone application Clear, who I give full credit for coming up with such an innovative user-interface design. This blog post is for fun an education, you are strictly prohibited from using this as the basis of a ‘Clear’ clone for WP7.

The video below shows the application so far, with the new re-order functionality:

Initiating a Drag

In the previous blog post we saw how the Toolkit GestureListener can be used to convert the low-level manipulation events into high level gestures. In order to initiate an item drag we could use the Hold event that the GestureListener exposes. The Hold event is fired when the user taps and holds the location of their finger for a few seconds. When I published my previous blogpost one of my readers Simon (Darkside) Jackson kindly pointed out that some of the gesture events are now supported by FrameworkElement directly, Hold is one such event. For this reason I’ll use FrameworkElement.Hold, the equivalent event on GestureListener should be considered deprecated.

The easiest way to allow the user to ‘pick up’ and drag the item is to clone it using a WriteableBitmap, hiding the original. This technique allows us to place the item at a higher Z-index than the list which it comes from, so that it will always be top-most as it is moved up and down the list.

We’ll add the element that is used to render the dragged item to the XAML:

<Grid>
  <ItemsControl ItemsSource="{Binding}" x:Name="todoList">
    ... markup from previous blog post
  </ItemsControl>
 
  <Grid x:Name="dragImageContainer"
        VerticalAlignment="Top"
        Visibility="Collapsed">
    <!-- the image that displays the dragged item -->
    <Image x:Name="dragImage"
          VerticalAlignment="Top">
    </Image>
 
    <!-- lower drop shadow -->
    <Rectangle Height="10"
                VerticalAlignment="Bottom">
      <Rectangle.Fill>
        <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
          <GradientStop Color="#AA000000"/>
          <GradientStop Color="#00000000" Offset="1"/>
        </LinearGradientBrush>
      </Rectangle.Fill>
      <Rectangle.RenderTransform>
        <TranslateTransform Y="10"/>
      </Rectangle.RenderTransform>
    </Rectangle>
 
    <!-- upper drop shadow -->
    <Rectangle Height="10"
               VerticalAlignment="Top">
      <Rectangle.Fill>
        <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
          <GradientStop Color="#00000000"/>
          <GradientStop Color="#AA000000" Offset="1"/>
        </LinearGradientBrush>
      </Rectangle.Fill>
      <Rectangle.RenderTransform>
        <TranslateTransform Y="-10"/>
      </Rectangle.RenderTransform>
    </Rectangle>
  </Grid>
</Grid>

The markup contains an image, and a couple of Rectangle elements, each of which is filled with a subtle opacity gradient and offset in order to give the impression of a drop shadow. The Source of the image is set in the Hold event handler as shown:

private void GestureListener_Hold(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
{
  _dragReOrder = true;
 
  // copy the dragged item to our 'dragImage' 
  FrameworkElement draggedItem = sender as FrameworkElement;
  var bitmap = new WriteableBitmap(draggedItem, null);
  dragImage.Source = bitmap;
  dragImageContainer.Visibility = Visibility.Visible;
  dragImageContainer.Opacity = 1.0;\
  dragImageContainer.SetVerticalOffset(draggedItem.GetRelativePosition(todoList).Y);
 
  // hide the real item
  draggedItem.Opacity = 0.0;
 
  // fade out the list
  todoList.Animate(1.0, 0.7, FrameworkElement.OpacityProperty, 300, 0);
 
  _initialDragIndex = _todoItems.IndexOf(((ToDoItem)draggedItem.DataContext));
}

The code above also hides the real object and offsets our ‘fake’ vertically so that it occupies the same position as the original. The list is also faded slightly to give a visual indication that the dragged item is now above the rest of the list:

Dragging the item

In order to allow the user to support dragging of the item we also need to handle ManipulationDelta on the Border element, as shown below:

<ItemsControl.ItemTemplate>
  <DataTemplate>
    <Border Background="{Binding Path=Color, Converter={StaticResource ColorToBrushConverter}}"
            ManipulationDelta="Border_ManipulationDelta"
            ManipulationCompleted="Border_ManipulationCompleted"
            Hold="Border_Hold"
            Canvas.ZIndex="0">
      <!-- gestures that were added in the last blog post to support delete / complete -->
      <toolkit:GestureService.GestureListener>
        <toolkit:GestureListener
                  DragStarted="GestureListener_DragStarted"
                  DragDelta="GestureListener_DragDelta"
                  DragCompleted="GestureListener_DragCompleted"
                  GestureCompleted="GestureListener_GestureCompleted"
                  Flick="GestureListener_Flick"/>
      </toolkit:GestureService.GestureListener>
 
      <Grid>
        <!-- the todo item XAML from the previous blog post -->        
      </Grid>
    </Border>
  </DataTemplate>
</ItemsControl.ItemTemplate>

So why am I handling these events on the Border rather than re-using the DragDelta / GestureComplete on the GestureListener? There are a couple of reasons:

  1. The GestureListener ‘drag’ has a tolerance (as discussed in the previous blog post). The user has to move their finger beyond a certain distance before a drag is started. In the current context we want a drag to occur as soon as the Hold event fires.
  2. When handling the element ‘drag’ we need to suppress the event by setting e.Handled=true, otherwise a drag will bubble up to the ScrollViewer that hosts our elements causing it to scroll. I found (through trial and error) that the GestureListener.DragDelta.Handled property doesn’t appear to have any effect.

The handler for the drag event is pretty simple, moving the copy of our item by the required distance:

private void Border_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
  Debug.WriteLine("ManipulationDelta");
 
  if (!_dragReOrder)
    return;
 
  // set the event to handled in order to avoid scrolling the ScrollViewer
  e.Handled = true;
 
  // move our 'drag image'.
  dragImageContainer.SetVerticalOffset(dragImageContainer.GetVerticalOffset().Value + e.DeltaManipulation.Translation.Y);
 
  ShuffleItemsOnDrag();
}

Offsetting the items underneath

The ShuffleItemsOnDrag method is where the fun starts, we’ll get to that shortly. First we’ll take a look at a simple utility method that is used to determine the index that the item being dragged would occupy if it were dropped at the present location. This is achieved by a simple measurement:

// Determines the index that the dragged item would occupy when dropped
private int GetDragIndex()
{
  double dragLocation = dragImageContainer.GetRelativePosition(todoList).Y +
                          VerticalScrollViewer.VerticalOffset +
                          dragImage.ActualHeight / 2;
  int dragIndex = (int)(dragLocation / dragImage.ActualHeight);
  return dragIndex;
}
 
private ScrollViewer _scrollViewer;
 
 
// gets the scrollviewer from the ItemsControl template
private ScrollViewer VerticalScrollViewer
{
  get
  {
    if (_scrollViewer == null)
    {
      _scrollViewer = todoList.Descendants<ScrollViewer>()
                              .Cast<ScrollViewer>()
                              .Single();
    }
    return _scrollViewer;
  }
}

The above code needs to take the current scroll location into consideration, which is why the ScrollViewer property above uses Linq-to-VisualTree to find the ScrollViewer that the ItemsControl generates to hosts our elements.

ShuffleItemsOnDrag is where the fun begins, we want to create an effect where the dragged item ‘pushes’ the other items out of the way as it hovers over them, giving the impression that the list is re-ordering as we drag.

The method below iterates over all of the items in the list to determine whether they need to be offset. An item needs to be offset if it is between the current dragged item index and the items original location.

private void ShuffleItemsOnDrag()
{
  // find its current index
  int dragIndex = GetDragIndex();
 
  // iterate over the items in the list and offset as required
  double offset = dragImage.ActualHeight;
  for (int i = 0; i < _todoItems.Count; i++)
  {
    FrameworkElement item = todoList.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
 
    // determine which direction to offset this item by
    if (i <= dragIndex && i > _initialDragIndex)
    {
      OffsetItem(-offset, item);
    }
    else if (i >= dragIndex && i < _initialDragIndex)
    {
      OffsetItem(offset, item);
    }
    else
    {
      OffsetItem(0, item);
    }
  }
}

The OffsetItem method performs the actual offset by animating the Y position of each item. The target location is stored in the elements Tag property so that we don’t repeatedly fire the same animation on an element.

private void OffsetItem(double offset, FrameworkElement item)
{
  double targetLocation = item.Tag != null ? (double)item.Tag : 0;
  if (targetLocation != offset)
  {
    var trans = item.GetVerticalOffset().Transform;
    trans.Animate(null, offset, TranslateTransform.YProperty, 500, 0);
    item.Tag = offset;
    _moveSound.Play();
  }
}

Completing the drag

When the user stops dragging the item, the ManipulationCompleted event is fired. Here we perform a number of tasks:

  1. Fade the list back to full opacity
  2. Animate the dragged item so that it ‘snaps’ into location
  3. When the above is complete, we need to re-order the underlying collection of model items, then re-populate the ObservableCollection exposed to the view. This causes all the items to be re-rendered, removing all of the TranslateTransforms that have been applied.
  4. Finally, remove the image which is our copy of the dragged item.

This sounds like a lot of work, but our Animate utility method makes it quite simple:

private void Border_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
  if (!_dragReOrder)
    return;
 
  _dragReOrder = false;
  _autoScrollTimer.Stop();
 
  int dragIndex = GetDragIndex();
 
  // fade in the list
  todoList.Animate(null, 1.0, FrameworkElement.OpacityProperty, 200, 0);
 
  // animated the dragged item into location
  double targetLocation = dragIndex * dragImage.ActualHeight - VerticalScrollViewer.VerticalOffset;
  var trans = dragImageContainer.GetVerticalOffset().Transform;
  trans.Animate(null, targetLocation, TranslateTransform.YProperty, 200, 0, null,
    () =>
    {
      // clone the list and move the dragged item
      var items = _todoItems.ToList();
      var draggedItem = items[_initialDragIndex];
      items.Remove(draggedItem);
      items.Insert(dragIndex, draggedItem);
 
      // re-populate our ObservableCollection
      _todoItems.Clear();
      _todoItems.AddRange(items);
      UpdateToDoColors();
 
      // fade out the dragged image and collapse on completion
      dragImageContainer.Animate(null, 0.0, FrameworkElement.OpacityProperty, 1000, 0, null, ()
        => dragImageContainer.Visibility = Visibility.Collapsed);
    });
 
}

Scrolling the list

The current implementation only allows the user to drag the item within the bounds of the current screen. What if the list is larger than the screen and the users want to drag right from the bottom to the top?

A common solution to this problem is to auto-scroll the list if the item is dragged near to the top. The following method is invoked periodically by a timer to see whether the item has been dragged within the top or bottom ‘scroll zones’. The velocity of the scroll is proportional to just how far within these zones the item has been dragged. Scrolling is simply a matter of setting the scroll location on the ScrollViewer we located earlier:

// checks the current location of the item being dragged, and scrolls if it is
// close to the top or the bottom
private void AutoScrollList()
{
  // where is the dragged item relative to the list bounds?
  double draglocation = dragImage.GetRelativePosition(todoList).Y + dragImage.ActualHeight / 2;
 
  if (draglocation < AutoScrollHitRegionSize)
  {
    // if close to the top, scroll up
    double velocity = (AutoScrollHitRegionSize - draglocation);
    VerticalScrollViewer.ScrollToVerticalOffset(VerticalScrollViewer.VerticalOffset - velocity);
  }
  else if (draglocation > todoList.ActualHeight - AutoScrollHitRegionSize)
  {
    // if close to the bottom, scroll down
    double velocity = (AutoScrollHitRegionSize - (todoList.ActualHeight - draglocation));
    VerticalScrollViewer.ScrollToVerticalOffset(VerticalScrollViewer.VerticalOffset + velocity);
  }
}

You can see the scroll zones illustrated below:

And finally, we are all done! With our todo application you can use flick and drag gestures to mark items as complete or delete them, and now use hold and drag to re-order. I think it’s about time I made it so that you can add or edit items. We’ll get to that next time!

You can download the sourcecode here: ClearStyle.zip

Regards, Colin E.

A gesture-driven Windows Phone to-do application

June 6th, 2012

This blog post describes the implementation of a gesture-based todo-list application. The simple interface is controlled entirely by drag, flick and swipe:

So far the application supports deletion and completion of tasks, but not the addition of new ones. I’ll get to this in a later blog post!

Introduction – gestures, why don’t we use them more?

I think it is fair to say that most Windows Phone applications (and mobile applications in general) have user-interfaces that are a close reflection of how we interact with a desktop computer. Mobile applications have the same buttons, checkboxes and input controls as their desktop equivalent, with the user interacting with the majority of these controls via simple clicks / taps.

The mobile multi-touch interface allows for much more control and expression than a simple mouse pointer device. Standard gestures have been developed such as pinch/stretch, flick, pan, tap-and-hold, however these are quite rarely used; one notable exception being pinch/stretch which is the standard mechanism for manipulating images.
When an application comes along that makes great use of gestures, it really stands out from the crowds. One such application is the iPhone ‘Clear’ application, a simple todo-list with not one button or checkbox in sight. You can see the app in action below:

Interestingly, its use of pinch to navigate the three levels of menu is similar to the Windows 8 concept of ‘semantic zoom’.
When I first saw Clear – the clean, clutter-free interface immediately spoke ‘Metro’ to me! This blog post looks at how to recreate some of the features of Clear using Silverlight for Windows Phone, in order to create a gesture-driven todo application.

NOTE: All of the work on my blog is under a Creative Commons Share-alike licence. For this blog post I just want to add that I do not want someone to take this code in order to release a ‘Clear’ clone on the Windows Phone marketplace. This blog post is for fun and education, to make people think more about the possibilities of gestures.

Rendering the to-do items

I haven’t followed the MVVM pattern for this simple application (I don’t need to unit test or collaborate with a designer!), but have followed the standard approach of using databinding. Each item is represented by an instance of the ToDoItem class which has properties of Text, Completed and Color and implemented INotifyPropertyChanged. A collection of these items is bound to an ItemsControl in order to render the list:

<ItemsControl ItemsSource="{Binding}" x:Name="todoList">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Border Background="{Binding Path=Color, Converter={StaticResource ColorToBrushConverter}}">
        <Grid>
          <Grid.Background>
            <!-- create a subtle gradient that overlays the background -->
            <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
              <GradientStop Color="#22FFFFFF"/>
              <GradientStop Color="#00000000" Offset="0.1"/>
              <GradientStop Color="#00000000" Offset="0.7"/>
              <GradientStop Color="#22000000" Offset="1"/>
            </LinearGradientBrush>
          </Grid.Background>
 
          <!-- task text -->
          <TextBlock Text="{Binding Text}" Margin="15,15,0,15" FontSize="30"/>
        </Grid>
      </Border>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
 
  <ItemsControl.Template>
    <ControlTemplate TargetType="ItemsControl">
      <ScrollViewer>
        <ItemsPresenter/>
      </ScrollViewer>
    </ControlTemplate>
  </ItemsControl.Template>
</ItemsControl>

The items control is template to host the ItemsPanel within a ScrollViewer, the default panel, a vertically-oriented StackPanel, is used here. The template to render each item is a simple Border, Grid and TextBlock. The code-behind iterates over the ToDoItem instances setting their Color property to produce a pretty looking gradient from red to orange, representing the priority of each item:

Handling gestures

Silverlight for Windows Phone provides manipulation events which you can handle in order to track when a user places one or more fingers on the screen and moves them around. Turning low-level manipulation events into high-level gestures is actually quite tricky. Touch devices give a much greater control when dragging objects, or flicking them, but have a much lower accuracy for the more commonplace task of trying to hit a specific spot on the screen. For this reason, gestures have a built in tolerance. As an example, a drag manipulation gesture is not initiated if the user’s finger moves by a single pixel.

Fortunately, the Silverlight Toolkit contains a GestureListener which handles manipulation events and turns them into the standard gesture events for you. Unless you need a quite fancy gesture (two-finger-swipe for example), the GestureListener probably gives you all you need. To use this class, simply attach it to the element that you want to handle gestures on, then add handlers to the events that the GestureListener provides.

We’ll add a GestureListener to the template that is used to render each ToDoItem:

<ItemsControl ItemsSource="{Binding}" x:Name="todoList">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Border Background="{Binding Path=Color, Converter={StaticResource ColorToBrushConverter}}">
        <!-- handle gestures for the ToDoItem element -->
        <toolkit:GestureService.GestureListener>
          <toolkit:GestureListener
                    DragStarted="GestureListener_DragStarted"
                    DragDelta="GestureListener_DragDelta"
                    DragCompleted="GestureListener_DragCompleted"/>
        </toolkit:GestureService.GestureListener>
 
        <Grid>
          ...
 
          <!-- task text -->
          <TextBlock Text="{Binding Text}" Margin="15,15,0,15" FontSize="30"/>
 
        </Grid>
      </Border>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
 
  ...
</ItemsControl>

The events produced by the GestureListener are used to indicate that a user has dragged their finger across the screen, but they do not actually move the element that the listener is associated with. We need to handle these events and move the element ourselves:

private void GestureListener_DragStarted(object sender, DragStartedGestureEventArgs e)
{
  // initialize the drag
  FrameworkElement fe = sender as FrameworkElement;
  fe.SetHorizontalOffset(0);  
}
 
private void GestureListener_DragDelta(object sender, DragDeltaGestureEventArgs e)
{
  // handle the drag to offset the element
  FrameworkElement fe = sender as FrameworkElement;
  double offset = fe.GetHorizontalOffset().Value + e.HorizontalChange;
  fe.SetHorizontalOffset(offset);
}
 
private void GestureListener_DragCompleted(object sender, DragCompletedGestureEventArgs e)
{
  ToDoItemBounceBack(fe);
}

But what are these mysterious methods, SetHorizontalOffset and GetHorizontalOffset in the above code? They are not found on FrameworkElement. The task of offsetting an element is reasonably straightforward via a TranslateTransform. However, once you set the RenderTransform of an element, it is converted to a MatrixTransform, so you cannot easily retrieve the value of the offset that has just been applied.

In order to hide this slightly messy implementation, I have created a couple of extension methods that use FrameworkElement.Tag to store the current offset:

public static void SetHorizontalOffset(this FrameworkElement fe, double offset)
{
  var trans = new TranslateTransform()
  {
    X = offset
  };
  fe.RenderTransform = trans;
 
  fe.Tag = new Offset()
    {
      Value = offset,
      Transform  = trans
    };
}
 
public static Offset GetHorizontalOffset(this FrameworkElement fe)
{
  return fe.Tag == null ? new Offset() : (Offset)fe.Tag;
}
 
public struct Offset
{
  public double Value { get; set; }
  public TranslateTransform Transform { get; set; }
}

Yes, I know, Tag is never an elegant solution, but at least the above code is hidden behind extension methods, so feel free to replace with a more elegant implementation using attached properties if you wish!

When the drag stops we want the item to bounce back into place:

private void ToDoItemBounceBack(FrameworkElement fe)
{
  var trans = fe.GetHorizontalOffset().Transform;
 
  trans.Animate(trans.X, 0, TranslateTransform.XProperty, 300, 0, new BounceEase()
  {
    Bounciness = 5,
    Bounces = 2
  });
}

Animate is another extension method which I created in order to quickly create DoubleAnimations for the properties of an element:

public static void Animate(this DependencyObject target, double from, double to,
                          object propertyPath, int duration, int startTime,
                          IEasingFunction easing = null, Action completed = null)
{
  if (easing == null)
  {
    easing = new SineEase();
  }
 
  var db = new DoubleAnimation();
  db.To = to;
  db.From = from;
  db.EasingFunction = easing;
  db.Duration = TimeSpan.FromMilliseconds(duration);
  Storyboard.SetTarget(db, target);
  Storyboard.SetTargetProperty(db, new PropertyPath(propertyPath));
 
  var sb = new Storyboard();
  sb.BeginTime = TimeSpan.FromMilliseconds(startTime);
 
  if (completed != null)
  {
    sb.Completed += (s, e) => completed();
  }
 
  sb.Children.Add(db);
  sb.Begin();
}

With the above code in place, we can drag items to one side or the other, then release and watch them bounce back into place.

Mark as complete

When an item is dragged sufficiently far to the right, we’d like to have it marked as complete. To implement this, we’ll check how far an item was dragged when the user releases their finger. If it was dragged more than half way, we’ll mark the item as complete:

private void GestureListener_DragCompleted(object sender, DragCompletedGestureEventArgs e)
{  
  FrameworkElement fe = sender as FrameworkElement;
  if (e.HorizontalChange > fe.ActualWidth / 2)
  {
    ToDoItemCompletedAction(fe);
  }
  else
  {
    ToDoItemBounceBack(fe);
  }
}
 
private void ToDoItemCompletedAction(FrameworkElement fe)
{
  // set the ToDoItem to complete
  ToDoItem completedItem = fe.DataContext as ToDoItem;
  completedItem.Completed = true;
  completedItem.Color = Colors.Green;
 
  // bounce back into place
  ToDoItemBounceBack(fe);
}

The bindings take care of updating the UI so that our item is now green. I also added a Line element which has its Visibility bound to the Completed property of the ToDoItem:

Deleting an item

If instead the use slides the item to the left we’d like to delete it. The DragCompleted event handler can easily be extended to check whether the item was dragged more than half-way across the screen in the other direction. The method that performs the deletion is shown below:

private void ToDoItemDeletedAction(FrameworkElement deletedElement)
{
  var trans = deletedElement.GetHorizontalOffset().Transform;
  trans.Animate(trans.X, -(deletedElement.ActualWidth + 50),
                TranslateTransform.XProperty, 300, 0, new SineEase()
  {
    EasingMode = EasingMode.EaseOut
  },
  () =>
  {
    // find the model object that was deleted
    ToDoItem deletedItem = deletedElement.DataContext as ToDoItem;
 
    // determine how much we have to 'shuffle' up by
    double elementOffset = -deletedElement.ActualHeight;
 
    // find the items in view, and the location of the deleted item in this list
    var itemsInView = todoList.GetItemsInView().ToList();
    var lastItem = itemsInView.Last();
    int startTime = 0;
    int deletedItemIndex = itemsInView.Select(i => i.DataContext)
                                      .ToList().IndexOf(deletedItem);
 
    // iterate over each item
    foreach (FrameworkElement element in itemsInView.Skip(deletedItemIndex))
    {
      // for the last item, create an action that deletes the model object
      // and re-renders the list
      Action action = null;
      if (element == lastItem)
      {
        action = () =>
        {
          // clone the list
          var items = _todoItems.ToList();
          items.Remove(deletedItem);
 
          // re-populate our ObservableCollection
          _todoItems.Clear();
          _todoItems.AddRange(items);
          UpdateToDoColors();
        };
      }
 
      // shuffle this item up
      TranslateTransform elementTrans = new TranslateTransform();
      element.RenderTransform = elementTrans;
      elementTrans.Animate(0, elementOffset, TranslateTransform.YProperty, 200, startTime, null, action);
      startTime += 10;
    }
  });
}

There’s actually rather a lot going on in that method. Firstly the deleted item is animated so that it flies off the screen to the left. Once this animation is complete, we’d like to make the items below ‘shuffle’ up to fill the space. In order to do this, we measure the size of the deleted items, then iterate over all the items within the current view, that are below the deleted item, and apply an animation to each one. The code makes use of the GetItemsInView extension method that I wrote for the WP7 JumpList control – it returns a list of items that are currently visible to the user, taking vertical scroll into consideration.

Once all the elements have shuffled up, our UI now contains a number of ToDoItems that have been ‘artificially’ offset. Rather than try to keep track of how each item is offset, at this point we force the ItemsControl to re-render the entire list.

The result looks pretty cool …

Part of the power of manipulations is their ‘organic’ feel, which is why inertia and the feeling of friction are important considerations. With the current to-do application, when the user releases an item after dragging it, the item springs back to its original positions, as if it were tether via a piece of elastic. The user needs to ‘pull’ the item past the half way mark in order to invoke a delete / complete operation. However, in order to make the interaction feel more ‘organic’ the user should be able to give the todo item a short, fast flick, giving the item enough momentum to pass the critical point. In order to support this we can use the GestureListener.Flick event:

We could do a bit of physics, creating a spring-constant, give our items a nominal mass and determine whether they have ben flicked with a ‘critical velocity’. However, for such a simple application, I’m happy to just come up with a velocity constant, that if passed results in the delet or complete action:

private static double FLICK_VELOCITY = 2000.0;
 
private void GestureListener_Flick(object sender, FlickGestureEventArgs e)
{
  FrameworkElement fe = sender as FrameworkElement;
  if (e.HorizontalVelocity < -FLICK_VELOCITY)
  {
    _flickOccured = true;
    ToDoItemDeletedAction(fe);
  }
  else if (e.HorizontalVelocity > FLICK_VELOCITY)
  {
    _flickOccured = true;
    ToDoItemCompletedAction(fe);        
  }
}

Contextual cues

My friend Graham Odds wrote a great post on the use of contextual cues within user-interface design, which are subtle effects that in Graham’s words “can be invaluable in effectively communicating the functionality and behaviour of our increasingly complex user interfaces”.

The todo-list application uses gestures to delete / complete an item, however, these are not common use interactions so it is likely that the user would have to experiment with the application in order to discover this functionality. They would most likely have to first delete a todo-item by mistake before understanding how to perform a deletion, which could be quite frustrating!

In order to help the user understand the slightly novel interface, we’ll add some very simple contextual cues. In the XAML below a Canvas has been added to the item template, this enables us to position a cross and a tick outside of the visible screen, one to the left and one to the right:

<Grid>
  <!-- add a subtle gradient over the background color for this item -->
  ...
 
  <!-- task text -->
  <TextBlock Text="{Binding Text}" Margin="15,15,0,15" FontSize="30"/>
 
  <!-- the strike-through that is shown when a task is complete -->
  <Line Visibility="{Binding Path=Completed, Converter={StaticResource BoolToVisibilityConverter}}"
        X1="0" Y1="0" X2="1" Y2="0" 
        Stretch="UniformToFill"
        Stroke="White" StrokeThickness="2"
        Margin="8,5,8,0"/>
 
  <!-- a tick and a cross, rendered off screen -->
  <Canvas Opacity="0" x:Name="tickAndCross" >
    <TextBlock Text="×" FontWeight="Bold" FontSize="35"
                Canvas.Left="470" Canvas.Top="8"/>
    <TextBlock Text="✔" FontWeight="Bold" FontSize="35"
                Canvas.Left="-50" Canvas.Top="8"/>
  </Canvas>
</Grid>

In the code-behind, we can locate this Canvas element using Linq-to-VisualTree, then set the opacity so that it fades into view, with the tick and cross elements becoming more pronounced the further the user swipes:

private void GestureListener_DragStarted(object sender, DragStartedGestureEventArgs e)
{
  // initialize the drag
  FrameworkElement fe = sender as FrameworkElement;
  fe.SetHorizontalOffset(0);
  _flickOccured = false;
 
  // find the container for the tick and cross graphics
  _tickAndCrossContainer = fe.Descendants()
                              .OfType<Canvas>()
                              .Single(i => i.Name == "tickAndCross");
}
 
private void GestureListener_DragDelta(object sender, DragDeltaGestureEventArgs e)
{
  // handle the drag to offset the element
  FrameworkElement fe = sender as FrameworkElement;
  double offset = fe.GetHorizontalOffset().Value + e.HorizontalChange;
  fe.SetHorizontalOffset(offset);
 
 
  _tickAndCrossContainer.Opacity = TickAndCrossOpacity(offset);
}
 
private double TickAndCrossOpacity(double offset)
{
  offset = Math.Abs(offset);
  if (offset < 50)
    return 0;
 
  offset -= 50;
  double opacity = offset / 100;
 
  opacity = Math.Max(Math.Min(opacity, 1), 0);
  return opacity;
}

With that subtle visual effect, the first iteration of my gesture-driven to-do application is complete. I’ll add new features, such as drag-to-reorder, and the ability to add / edit items in the near future, again, all driven by gestures.

You can download the code here: ClearStyle.zip

Update: Read more about this application in part two, where I add drag re-ordering.

Regards, Colin E.

Everything you wanted to know about databinding in WPF, Silverlight and WP7 (Part One)

April 5th, 2012

OK, so the title is a little ambitious, but there is nothing wrong with setting yourself lofty aims! Because of the depth of this topic I have decided to split this tutorial up into a series of blog posts, each of which explore a different aspect of the binding framework.

I don’t usually write tutorial blog posts and series, preferring instead to develop new controls or novel techniques. However, I really felt this subject needed an in-depth tutorial. Databinding is a fundamental part of the WPF, Silverlight and the Silverlight for Windows Phone 7 frameworks. It is a powerful concept that once mastered allows you to write concise and elegant code. Yet for all its power, it is a little complex and that is my reason for launching into this blog series.

The rough outline for this series is as follows:

  • Part One – Life before binding, INotifyPropertyChanged and creating bindings in code-behind
  • Part Two – The binding markup extensions, the DataContext and path syntax
  • Part Three – Other binding sources, ElementName, TemplatedParent, TemplateBinding
  • Part Four – Value converters
  • Part Five – List binding

Life before binding

To understand what databinding is and the service it provides us with, it is worth looking at how you wire-up a user-interface without using databinding. We’ll start with a simple model object, or business object, and see how we can take the properties that this object exposes and display them in the UI using standard controls. We will also see how we can respond to event raised by these controls in order to update our model.

Note, that I am making the assumption that your code will contain some sort of model object. This doesn’t have to be the case! You could store your data within the UI controls directly, however this rapidly becomes un-maintainable. There are a whole host of UI patterns that have been developed in order to keep the model and the view separate (MVP, MVC, MVVM etc…)

We’ll look at how to manage the interactions between the model and the view without the help of a binding framework. For our example we’ll look at a very simple UI which displays the details of an event, its name and the date of the event:

The model that supports this view is shown below:

/// <summary>
/// A simple model object that represents an event
/// </summary>
public class EventModel : INotifyPropertyChanged
{
  private string _title;
 
  /// <summary>
  /// Gets / sets the event title
  /// </summary>
  public string Title
  {
    get { return _title; }
    set
    {
      if (value == _title)
        return;
 
      _title = value;
      OnPropertyChanged("Title");
    }
  }
 
  private DateTime _date;
 
  /// <summary>
  /// Gets / sets the date of this event
  /// </summary>
  public DateTime Date
  {
    get { return _date; }
    set
    {
      if (value == _date)
        return;
 
      _date = value;
      OnPropertyChanged("Date");
    }
  }
 
  public event PropertyChangedEventHandler  PropertyChanged;
 
  protected void OnPropertyChanged(string propertyName)
  {
    if (PropertyChanged != null)
    {
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

In our case the model implements INotifyPropertyChanged, allowing us to detect changes in its properties. We will use this to update the view when the model changes.

The view has the following XAML (with the various layout properties omitted for clarity):

<TextBlock Text="Name:"/>
<TextBox x:Name="EventTitle"
          TextChanged="EventTitle_TextChanged"
 
<TextBlock Text="Date:"/>
<sdk:DatePicker x:Name="EventDate"
                SelectedDateChanged="EventDate_SelectedDateChanged"/>
 
<Button Content="Modify Event"
        Click="Button_Click"/>

The code-behind that supports this view is given below:

public partial class MainPage : UserControl
{
  private EventModel _event;
 
  public MainPage()
  {
    InitializeComponent();
 
    // create a model object
    _event = new EventModel()
    {
      Date = new DateTime(2011, 7, 1),
      Title = "Silverlight User Group"
    };
 
    // copy our model object state to the UI
    EventDate.SelectedDate = _event.Date;
    EventTitle.Text = _event.Title;
 
    // 'listen' to changes in the model
    _event.PropertyChanged += Event_PropertyChanged;
  }
 
  /// <summary>
  /// Handles changes in the model, reflecting this change in the UI (view)
  /// </summary>
  private void Event_PropertyChanged(object sender, PropertyChangedEventArgs e)
  {
    if (e.PropertyName == "Title")
    {
      EventTitle.Text = _event.Title;
    }
    if (e.PropertyName == "Date")
    {
      EventDate.SelectedDate = _event.Date;
    }
  }
 
  /// <summary>
  /// Handles the TextChanged event updating the model accordingly
  /// </summary>
  private void EventTitle_TextChanged(object sender, TextChangedEventArgs e)
  {
    _event.Title = EventTitle.Text;
  }
 
  /// <summary>
  /// Handles the SelectedDateChanged event updating the model accordingly
  /// </summary>
  private void EventDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
  {
    _event.Date = EventDate.SelectedDate.Value;
  }
 
  private void Button_Click(object sender, RoutedEventArgs e)
  {
    // make some change to our event
    _event.Title = _event.Title.ToLower();
    _event.Date = _event.Date.AddDays(1);
  }
}

In order to wire-up the model with our view, the above code performs the following distinct tasks for each of the model’s properties:

  1. Sets the state of the UI controls to the initial state of the model. In the above example this is done in the constructor.
  2. Subscribes to the event that the UI control exposes to indicate a change in state. For the TextBox this is the TextChanged event, for the DatePicker this is the SelectedDateChanged event. When a change occurs, the UI state used to update the mode.
  3. Subscribes to PropertyChanged events from the model object. The handler for this event detects the property that has changed and updates the state of the corresponding UI control.

If we consider the model object to be the source of the data and the UI control to be the target. We can see that we have three separate flows of data:

The code for each of these three steps is distributed throughout our code, in the constructor and a variety of event handler. For each model property that we wish to expose to our user via the view, we have to add code to perform each of these three tasks. This leads to code that is hard to maintain and dataflow that are hard to trace.

Databinding – less code, greater clarity

Databinding provides an alternative to the manual coupling of the model to the UI controls in our view. The idea being that the binding framework takes care of all three of the tasks above. We simply state that we wish to synchronise a model property with a property of a UI control, and it does the rest. Our complex diagram above simply becomes the following:

Changes in the source property values are pushed to the target property by the binding framework, and (optionally) changes in the target are pushed to the source.

Modifying the code for our example to use the WPF / Silverlight framework results in the following code:

public MainPage()
{
  InitializeComponent();
 
  // create a model object
  _event = new EventModel()
  {
    Date = new DateTime(2011, 7, 1),
    Title = "Silverlight User Group"
  };
 
  // bind the Date to the UI
  EventDate.SetBinding(DatePicker.SelectedDateProperty, new Binding("Date")
  {
    Source = _event,
    Mode = BindingMode.TwoWay
  });
 
  // bind the Title to the UI
  EventTitle.SetBinding(TextBox.TextProperty, new Binding("Title")
  {
    Source = _event,
    Mode = BindingMode.TwoWay
  });
}

This is a big improvement on the previous ‘manual’ example where three separate event handlers were required to maintain synchronization between the model and the view. Databinding allows us to declare how the model is connected to the view, with the databinding framework taking care of the mechanics.

We’ll take a closer look at the databinding syntax in order to understand its various component parts. We can highlight these components by re-writing one of the bindings as follows:

FrameworkElement targetObject = EventTitle;
DependencyProperty targetProperty = TextBox.TextProperty;
object sourceObject = _event;
string sourceProperty = "Title";
 
var binding = new Binding(sourceProperty)
{
  Source = sourceObject,
  Mode = BindingMode.TwoWay
};
targetObject.SetBinding(targetProperty, binding);

From the above we can clearly see the following components:

  • The source object – this is the object which contains the data which we want to render within the UI
  • The source property – the property of the above object which we wish to render
  • The target object – this is a UI control which has a property which we are going to use to display our model property
  • The target property – the property of the UI control which visualises our data
  • The binding - this is used to indicate the source and source property, together with other information relating to the binding like the direction of data flow, value converters etc… (more on these later).
  • SetBinding – this is the method used to associate a databinding with a specific property on the target. Note that the first argument is the dependency property that is defined on TextBox and is public static.

Once a binding has been created and associated with a dependency property, the initial value is propagated from the source to the target. Following this, if the source object implements INotifyPropertyChanged, subsequent changes in the source property value are automatically propagated. If a BindingMode.TwoWay binding is used, changes to the target property, which typically occur due to user interactions, are propagated from the target to the source.

A brief digression into dependency properties

As you can see from the above, databinding is a feature of WPF and Silverlght dependency property mechanism. The type of properties that developers are used to from other .NET languages are typically termed ‘CLR properties’ (Where CLR refers to the Common Language Runtime) so that we know which type of property we are talking about!

CLR properties are simply shorthand for methods used to access a backing field. You cannot use the databinding framework to bind together two CLR properties. Dependency properties are something much more powerful, they provide property inheritance within the visual tree, animation support, precedence rules, coercion and, most importantly for the purposes of this article, databinding.

In the example below, a dependency property ‘TotalGoals’ is defined on a dependency object. By convention, this dependency property is exposed as a public static field on the dependency object. It is this static field that we use to identify the dependency property when binding to it:

public class MatchResult : DependencyObject
{
  /// <summary>
  /// Identifies the TotalGoals Dependency Property.
  /// <summary>
  public static readonly DependencyProperty TotalGoalsProperty =
      DependencyProperty.Register("TotalGoals", typeof(int),
      typeof(MatchResult), new PropertyMetadata(0));
 
}

Once a dependency property has been defined, its value can be get / set via the GetValue / SetValue methods:

var result = new MatchResult();
// set the property
result.SetValue(MatchResult.TotalGoalsProperty, 10);
 
// get the property
Debug.WriteLine(result.GetValue(MatchResult.TotalGoalsProperty))

Because the syntax to get or set a dependency property is not terribly friendly, using the GetValue / SetValue methods, dependency objects typically provide CLR properties that wrap the dependency property access, providing a better API for manipulating the state form code-behind.

/// <summary>
/// Gets or sets the total score. This is a dependency property.
/// </summary>
public int TotalScore
{
  set
  {
    SetValue(MatchResult.TotalGoalsProperty, value);
  }
  get
  {
    return (int)GetValue(MatchResult.TotalGoalsProperty);
  }
}

However, this is purely convention.

Whilst the target for a binding must be a dependency property (which must be defined on a dependency object), the source can be either a dependency property or a CLR property. In practice, unless you are creating your own controls, you will not need to create your own dependency properties. Instead, you will be binding your model to the properties of the various UI elements that are supplied with the WPF / Silverlight frameworks, for example TextBlock.Text. These are all dependency properties.

A quick note about INotifyPropertyChanged

Whilst dependency properties always notify the binding framework of any changes in value, CLR properties only notify of changes if the class which the belong to implements the INotifyPropertyChanged interface (as the class used in the example above does). It is not mandatory that you implement this interface, or raise the PropertyChanged event, for properties that your bind to your UI. However, if you do not, the binding framework will only perform a one-time update, pushing the property value from source to target at the point when the binding is created.

BindingModes

You can specify which direction you want property changes to propagate by setting the BindingMode on a binding. This is probably easiest to illustrate with a simple diagram:

OneWay bindings only propagate changes in the source value to the target (assuming the source implements INotifyPropertyChanged), whereas a TwoWay binding propagates changes in both directions, ensuring that the two values are always synchronized. There are a few other binding modes (OneWayToSource, OneTime…) but one / two way are by far the most commonly used.

WARNING: The default BindingMode for Silverlight is OneWay, whereas in WPF it is BindingMode.Default which means … it depends! From MSDN:

“The default value varies for each dependency property. In general, user-editable control properties, such as those of text boxes and check boxes, default to two-way bindings, whereas most other properties default to one-way bindings.”

This is very confusing if you are writing cross-platform WPF / Silverlight code! In this case I would always recommend specifying the BindingMode explicity.

Summary

So far we have seen what life was like before databinding, where we had to write code to handle changes from both the source and target properties, manually synchronizing the two. With binding, the framework handles this for us, allowing for a more declarative approach to wiring-up our UI to the model that backs it (you do have a model behind your view don’t you?!).

However, you might be wondering why there has been no mention of binding in XAML yet? This was intentional, I wanted to first show how bindings work under-the-hood, introducing the concept of source and target, before leaping into creating them in XAML … which is the subject of the next blog post …

You can download the example code here: BindingExamples.zip

Regards, Colin E.