WPF

I've been wanting to get into WPF for sometime. As a GP it's hard to keep up with software development and my personal niche is always going to be desktop. That's not to say WPF is new but its principals are here to stay in the desktop .net world. Now I've done a little example app and it's fresh in my mind it's a good place to share my thoughts. When looking into this there were a lot of basic principals which I felt weren't explained properly, little key points when I got after a little while which I hope will be helpful to newcomers.

Pre-requisites

Before looking into WPF your C# knowledge should be up to at least knowing about

XML - a structured format of storing data

Events - A way of encapsulating method calls

Interfaces - A robust way of getting classes to communicate with each other

If not you are going to struggle with basic concepts in WPF. Unfortunately, it's not a subset of C# which is as easy as Windows Forms.

MVVM - Model-view-viewModel

MVVM Pattern

The Cornerstone of WPF is MVVM. It's a pattern around how to layout your application into separate sections which have separate responsibilities

The View

All Classes relating to the view are in XAML with Code Behind. Put these in a separate namespace|folder within your UI project|assembly. XAML is XML for WPF and allows you to create controls easily via elements and attributes. eg <Grid></Grid> will create a Grid Control where you can define the number of rows and columns with separate attributes and elements.

The View Model

The View Model is the powerhouse of MVVM and is where most of the work is done to manage data from the Model to the View. This should be as a separate cs file in a different folder|namespace as per the diagram below.

You need to have one ViewModel for every View

Laying out your Views and ViewModels

The Model

The model is well, the model and is where the data is housed. Naturally, you'd map the database entities to Models to facilitate using them in the code but this is out of the scope of this blog. However the data is fetched, the data for the view model should be only models relevant for the view.

View knows nothing

The view is dumb and knows nothing. It and its code behind should not contain any properties or methods related to the view. This is all managed by the corresponding View Model. The way data is viewed in the View is indirect via bindings. More about this later.

This way you can create a totally different view or layout with the same bindings without changing any code. The vision was that an Artist created the views and all they needed to know was the Binding Names without knowledge of any code.

The View has no properties and methods but does have indirect access to them via data binding

Binding and the ViewModel

This is the important bit of MVVM and the one I found the hardest to find a decent simple explanation about.

You shouldn't have any properties or methods in your View but you can in your corresponding ViewModel. You connect the corresponding entities via data bindings.  A binding is basically a bit of reference text which links the property or event in the view with the corresponding property or event in the ViewModel. It is defined in the View Model and referenced in the view. It can be any bit of text defined by the coder but normally relates to the property or event in question.

To do this you need to do 2 things as explained below

1. Inform the View of changes in the ViewModel and

2. Tell WPF which ViewModel is linked to which view. 

1. To notify the View when changes have been made to the ViewModel to update the View accordingly

 We do this by using the INotifyPropertyChanged Interface. This is a bit of boilerplate code but basically, it allows you to have properties which the View Model can tell the View to update when a change is made

This is an example of the implementation in a ViewModel

ViewModel implementing INotifyPropertyChanged

In the above example, what is an Observable Collection? It's basically a List, So if your property is a List of Objects, Change it from a List<> to ObservableCollection<>. The key to the above example is that whenever I set the property, I raise an event which triggers an update on the View. But where does WPF know which area in the view needs to be triggered?

Here is a picture of the relevent place in the view. Notice how the Text next to the word Binding relates to the corresponding property within the View Model. The word Two Way means that I want to connect the view and model so that changes in one will automatically update with changes in the other and visa versa! This is a very powerful feature.

2. Which View relates to which View Model

There is one missing piece of the jigsaw, we need to tell WPF which ViewModel Object relates to which View. We do this via the DataContext. It's simply a reference to connect the View to ViewModels. Once this is done the Bindings make sense. You can do this in the code behind but I think it's slicker doing this in the XAML

In this example xmlns is just the XAML equivalent of the "using" term in the header code of a cs file.

Once the Data Context is set the Bindings and Notifications should marry up and the connection will then make sense to WPF

Properties,  Buttons and Behaviours

Ok so we said that INotifyPropertyChanged is used to inform the View of changes made in the ViewModel (and visa versa for Two Way Binding) and we use the setter of the property accessor to raise the notification but what about events eg mouse button clicks?

In this case, we have the Command Interface which Button Events use to the link the View to the ViewModel via Data Binding. They are a way of abstracting out your execution logic for actions like clicking on a button. Even though they are associated with buttons they can be supported by almost all WPF Controls. Unlike commands, Behaviours extend controls without having to subclass them. This makes changing the behaviour of an associated element easier. So commands delegate out responsibility to another entity (ie the ViewModel) and behaviours extend the functionality of existing classes.

In the Example below clicking on Export to XML triggers a method to run an export on a linq query to export a List to a XML File

You start off by defining the ButtonCommand which implements ICommand. This can be put into a utilities project|assembly

Here is the boilerplate code (note you to reference PresentationCore!)

ButtonCommand

In your ViewModel you then define your ICommand Object which exposes the method calls relating to the constructor of the ICommand Interface. In this example it's ExportToXML and CanExportToXml

In ViewModel

Within your XAML you can now bind your Button to this Interface

In the View

Behaviours are similar to Commands but apply to non-button controls (ie not buttons, check boxes or radio buttons)

So the View Models Interface with the View via 

- Data Bindings for Properties 

- Commands for delegating the responsibility of events to other classes eg Buttons, radio buttons and checkboxes 

- Behaviours which extend existing classes enhancing functionality

Features out of this Blog's Scope

Toolkits

MVVMLight is probably the main toolkit for WPF developers to help them simplify a lot of WPF. Look at this for further development

Data Templates

Data Templates are a way of massaging the data shown in the view for example if you want to not show primary keys from the Models or have the date in a different format in the View from a Model. Out of the scope of this Blog to go in more detail

Getting ViewModels talking

It gets very messy when you want ViewModelA to talk to ViewModelB and C and can create spaghetti coding. A better way is for ViewModels to talk to each other via a Messenger Service which acts as a mediator where you can get a ViewModel to register to listen for a message and another ViewModel to send a message to be picked up by the listeners.  MVVM Light for example provides this service off the bat.

Example Project

I've written a little application showcasing the above which I hope you will find useful. In PatientLeaf we needed a better way to export Read Code | Snomed Code to our own XML standard and created a small parsing tool to do this.

You can find it in GitHub over here.

Previous
Previous

Email Consultations

Next
Next

Coding Blood Pressure