Data Binding is one of XPF’s features that we’re excited about – bringing data binding to the world of XNA helps to encourage building of loosely coupled applications and helps enable the separation of presentation from implementation logic. We’ve previously discussed the inner workings of data binding in our insider post but for those whom data binding maybe an abstract concept, this series of posts is designed to introduce you to both the concepts and the implementation. Let’s walk through what it is, why you should use it and what XPF offers.
What is Data Binding?
Data binding can essentially be thought of as an implementation of the Observer Pattern, where the UI is the observer and the domain model the subject.
“The observer pattern (a subset of the publish/subscribe pattern) is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.”
In reality XPF turns that concept on its head in that the UI elements maintain the list of subjects and hooks onto them to watch for updates, it also supports two-way conversations between subjects and observers but we’ll come onto that later.
Let’s step back slightly; XPF goes a bit further than the observer pattern so let’s change our language terms to something more fitting. Instead of “subject” we’ll use source and in-lieu of “observer” let’s say target. Let’s look at what that means in practical terms:
In this example we have a player class that exposes the player’s score via a property. We also have a user interface which is going to display the player’s score as it updates. In this example the score property on the player object is the source of our data and the text block in the UI is the target. In a situation like this we would use data binding to establish a relationship between our player class and our UI once and then never worry about it again, knowing that if we alter the player’s score in our domain model the UI will automatically get updated via data binding.
Why use Data Binding?
Data binding is an enabler of other patterns and practices that ultimately make your life easier and your code easier to manage.
The quest to isolate domain logic from the user interface has spawned dozens of architectural patterns, MVC and MVVM being amongst the most popular at the moment. Both concentrate on allowing your domain model to be focused on its job whilst being agnostic to any UI that maybe influenced by it. This has some distinct advantages.
Generally speaking the logic you use to determine whether a player’s score should increase and the logic you use to display that change in score are very different beasts, as such when tackled together they don’t tend to produce particularly focused units of code.
Producing focused, isolated units of code makes your codebase easier to understand and eases unit testing. If your player class doesn’t care about UI, then it doesn’t need to know anything about any graphics related dependencies, thus a dependency is dropped, unit testing is eased, and your code base is simpler and less brittle as a result.
Data binding encourages this separation by providing a bridge between the two disciplines.
Data Binding in XPF
As mentioned previously, XPF turns the Observer pattern on its head slightly in regards to which side of the equation maintains the list of observers (targets) that should be updated when the subject (source) changes.
In XPF the target maintains the list of sources with which it is bound. The switch in responsibility here frees up the source (domain model) from being anything much other than a POCO.
The target is a UI element; all elements in XPF inherit from ReactiveObject and expose Reactive Properties which can be bound to. Together ReactiveObject and ReactiveProperty provide the required mechanisms for data binding to work.
Three modes of binding are supported: one way, one way to source and two way. The modes describe the direction in which data flows relative to the target. One way is from the source to the target, one way to source is from the target to the source and two way moves data in both directions.Whilst all of the heavy lifting is taken care of by ReactiveObject and ReactiveProperty the source (domain model) side of the equation still has to agree to a couple of rules if it wants to take part. The source needs to expose a known hook for the binding system to latch onto which it can use as a channel to push data in one or both directions.
In XPF this hook is provided by the new IObservable<T> and IObserver<T> interfaces introduced in .Net 4.0 (and on WP7) which align to the concept of moving data in either direction. They are the mathematical dual of IEnumerable<T> and IEnumerator<T>, in that they push rather than pull their data.
“The IObserver<T> and IObservable<T> interfaces provide a generalized mechanism for push-based notification, also known as the observer design pattern. The IObservable<T> interface represents the class that sends notifications (the provider); the IObserver<T> interface represents the class that receives them (the observer).”
One way binding expects an IObservable<T> as its source which the binding system subscribes to. One way to source expects an IObserver<T> to which the binding system can push updates. Two way expects both.
How to use Data Binding
Continuing on the example application above, the score would be defined in the UI as a TextBlock and we would bind our player class to its text property.
Bindings are always setup against a ReactiveProperty on a ReactiveObject via the Bind() method. In XPF all controls ultimately inherit from ReactiveObject and most expose a number of ReactiveProperty properties that can be bound to.
Each control exposes the Reactive Properties available for binding as static members, here are some of the Reactive Properties exposed by TextBlock, all of which can be bound to:
Once we have an instance of a TextBlock we can call its Bind method and specify what property we want to bind to along with the mode and source we want to use. It’s at this point we decide what binding mode we want to use by providing either an IObservable<T> (one way), IObserver<T> (one way to source) or both (two way):
The binding is now set and in the example above any changes to the source provided would update the TextBlock’s text property, meaning we don’t have to worry about updating the UI ourselves.
Don’t worry if all this talk of observables and observers is worrying you, we’ll cover the BindingFactory in a future post that can be used to create bindings around normal typed properties, but it’s good to get an understanding from the ground up.
In the next post in this series we’ll look at a domain object that exposes IObservable<T> and IObserver<T> properties and build a working sample that uses them to create both one way and two way bindings.