Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WPF Step by Step: Getting Started with WPF and Expression Blend

0.00/5 (No votes)
21 Aug 2010 8  
Getting started with your first WPF application using Microsoft Expression Blend 4.0.

Introduction

The Windows Presentation Foundation provides a fantastic way to develop your applications. However, getting started with WPF can be daunting. Data binding, MVVM, XAML, Pixel Shaders, Control Templates, Styles, Resources, and Triggers are all terms that may well be unfamiliar.

This article will help you get started with WPF. We'll create a simple application, going over points of interest blow by blow. By the end of the article, you will be comfortable with some of the core concepts of WPF development, and you'll be well on the way to being able to harness the power of WPF to create stunning applications.

One of the great things about WPF is that it encourages you to use a sensible pattern for writing software - separating content from design, keeping the business logic away from the UI. You will write code that is well organised, easily testable, and maintainable.

Background

The code in this article is C#. Visual Basic code will be very similar. If there is enough interest, I will update it with VB code. I am using the latest platforms and technologies - Expression Blend 4, Visual Studio 2010, and the .NET Framework 4.0.

Creating a New Project

Enough preamble. Let's dive in and get started. We'll start simple and build a skeleton application, then we can take our basic application and refine it. Rather than being bombarded with technical details and abstracts, we're going for a very hands on approach.

First of all, open Expression Blend 4 and choose 'New Project'. I'm calling this one WpfStepByStep1 - any name will do!

New Project Window

We've got some files. A bit of C# and a bit of XAML. XAML is Extensible Application Markup Language. We use it to lay out windows and UI elements. XAML is quite similar to HTML; it allows us to lay out windows, arrange controls, and more. We'll be using XAML a lot, but for now, let's simply see what we've got. Hit F5, or go to Project > Run Project.

Main Window

There's not much to see, but we've got quite a bit here really. A new window, a blank space for us to arrange content, and the typical features found in a Windows application (close button and so on). One thing is worth noticing - we can re-size, minimise, and maximise the window. In the world of HTML, we rarely know how big a user screen will be - or how big their browser window will be. Because of this, we rarely rely on absolute positioning, such as 'this button is 30 pixels from the left'. We try to arrange a window or page so that the content can be re-sized gracefully. WPF can do this very well - we're going to make sure that our app works whether the window is small or large.

Adding Some Controls

If you are completely unfamiliar with WPF and Expression Blend, now is a good time to have a play. The 'Assets' panel on the left has a 'Controls' section. Click on it. A set of controls is now displayed in the Assets panel.

Assets Panel

We have access to a variety of familiar and unfamiliar controls. There are also shapes to play with. Later on, we'll even look at effects and animation. The Expression Blend design window is geared towards UI design - visual hints are provided as items are moved and resized. In fact, some of the data presented may seem a bit confusing. For now, we'll accept that we can quickly drop controls onto our window.

Controls

Delete any controls that you have added - we're going to create a functional application and will need a clean slate. For this article, we're going to create an Address Book. It's not the most original idea, but is simple enough for us to look at some of the features we'll be interested in.

Getting Started with the Address Book

We've decided to write a simple address book application, to allow us to manage some information about our contacts. Typically, this is where we'd start to think about things like the information we want to present, how the UI might look, functional requirements and so on that we need to implement. For now, I'm going to speed things up by giving you the brief:

I want a simple Address Book app. I need the facility to:

  • Look at contacts.
  • Add new contacts.
  • View simple contact details - name, email address, and phone number.

On top of that, I have decided that I want it to look roughly like this:

UI Prototype

If you're interested in how I made the image above, then let me know. Expression Blend has a powerful UI prototyping tool called 'SketchFlow' that makes it easier than ever to mock up UI designs, as well as add animation, gather feedback from clients, and more. This is a large topic in itself, but if there is enough interest, then I'll write an article in this series focused on SketchFlow.

The hands-on approach is great for a project like this. The sketch above is basic, but complete enough for us to have a first crack at the UI. Follow the steps below:

  • Find the 'Text Block' control in the Assets panel (there's a handy search box if you can't find it). The Text Block is used for chunks of text - likes a Static in Win32/MFC, or a Label in Windows Forms. Drag the Text Block onto the design surface.
  • Go to selection mode by selecting the darker arrow from the top of the toolbar on the left. Click on the text block and open the 'Properties' panel on the right hand side. Find the 'Text' property in the 'Common Properties' tab, and change it to 'Address Book'.
  • Text Block Properties

  • Drag a 'List Box' control onto the left hand side of the window - this is where we'll show the list of contacts.
  • Create another text block on the right hand side of the window and set the text to 'Contact Details'.
  • Create the three text blocks shown in the UI prototype.
  • Hint: Speed things up by dragging copies. Select a text block and hold the Alt key. Drag the text block somewhere else. Release, and a copy will have been created. This works even when you've got groups of controls selected.

  • Drag three 'Text Box' controls onto the window. Arrange these just like in the UI prototype.
  • Finally, drag a 'Button' control onto the design surface and set its content to 'Create a New Contact'. Position it as in the prototype.

You should now have something like this:

Address Book

At this stage, you could have a closer look at the Properties panel. The controls we've laid out can be modified extensively using the Properties panel. We can change fonts, colours, brushes, visual effects, and more. Remember, at the bottom of each panel in the Properties window is a small bar - press it for even more advanced properties. Get used to using the search box too - it'll come in handy as you get more familiar with Blend and WPF.

Hit F5. We're off to a good start, the controls are there and positioned appropriately. Re-size the window. Depending on how you laid out your controls, you'll get a variety of behaviour for how controls are repositioned and re-sized. In any case, the re-size behaviour is probably not perfect - we'll come back to this. For now, we'll move on to getting some functionality done.

Creating Objects

From the specification, we have a fairly good idea of what sort of data objects we'll need. A Contact object will hold a name, email address, and phone number. The application as a whole will contain a set of contacts.

In Expression Blend, go to Project > New Item, and create a class file named 'Contact.cs'.

New Class

The Contact class will be very simple indeed. Here's the source:

using System;

namespace WpfStepByStep1
{
    public class Contact
    {
        public Contact()
        {
        }
        
        public string Name
        {
            get;
            set;
        }
        
        public string Email
        {
            get;
            set;
        }
        
        public string PhoneNumber
        {
            get;
            set;
        }
    }
}

It doesn't get much easier than this. If you have already played around with Model-View-ViewModel, then don't worry - we'll be coming to that soon. For now, we're keeping things as simple as possible.

We're now getting to the first real WPF challenge - where do we put contacts? Are they in the XAML? In the App class? In the MainWindow class? This is the sort of question that causes confusion - you may have heard that the place to put data is in the model and present it with the model view - but what are these entities? And where do they exist? We're going to come back to this shortly; for now, we'll go for what seems to be the quickest solution - then, we'll look at how to do it the WPF way, which it turns out is even quicker!

Open the MainWindow.xaml.cs file from the projects panel.

MainWindow.xaml.cs

Add a list of contacts to the class, as below.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
        // Insert code required on object
        // creation below this point.
    }
        
    protected List<Contact> contacts = new List<Contact>();

    public List<Contact> Contacts
    {
        get { return contacts; }
        set { contacts = value; }
    }
}

We're going to want some data to make sure our UI is working, so add a few contacts in the constructor of the MainWindow object.

public MainWindow()
{
    this.InitializeComponent();

    //    Add some contacts.
    contacts.Add(new Contact() {Name = "James", 
                 Email = "james@mail.com", 
                 PhoneNumber = "01234 111111"} );
    contacts.Add(new Contact() {Name = "Bob", Email = "bob@mail.com", 
                 PhoneNumber = "01234 222222"} );
    contacts.Add(new Contact() {Name = "Emma", Email = "emma@mail.com", 
                 PhoneNumber = "01234 333333"} );
}

Finally, we need to tie this into the window. WPF has its own way of doing this, called Data Binding. We'll get into this in detail later on. In a typical WinForms application, we'd probably go through the list of contacts, create a list view item for each one, set the tag to the data object, and insert it into a list box. With WPF, we'll tell the list view 'this is your data' and let it take over from there. We can do that with the data as we have it here, but it's a little bit convoluted. Build the project. Open the MainWindow.xaml file so that you can see the controls. Click on the list box on the left hand side and locate the 'ItemsSource' property. Open the advanced properties by pressing the little square next to it, and choose 'Data Binding'.

Item Source

We can bind to the 'Contacts' property of the MainWindow object by selecting 'Element' at the top and finding the 'Contacts' property.

Data Binding

Press OK and hit F5. We can see three contact objects in the list control. Not particularly useful. Also, finding that property was a bit tricky. What happens when we have more and more properties and we want to maybe interlink them. This is where MVVM (Model-View-ViewModel) design will come into play.

MVVM

The idea behind MVVM is this: we have three elements to the application:

The Model

The Model is the application data. It could be from a database, a file, memory, or whatever. The model may well contain business logic and some very complicated entities.

The View

The View is the presentation layer of the application. In this case, it is the XAML file that controls what is displayed and how it is rendered.

The ViewModel

The ViewModel is the object that ties the two together. In our case, the ViewModel would contain the list of contacts we're showing, the current contact, and anything else that we might need the view to connect to.

This is the very basic outline of MVVM. As with the previous concepts, we're going to learn this pattern by using it. We know from the above points that a ViewModel is an object that ties the content to the presentation. So, let's go ahead and write one. The view must show the contacts and the details for the selected contact, so we'll put that data in a model view class. Create a new class called 'AddressBookViewModel'.

public class AddressBookViewModel
{
    public AddressBookViewModel()
    {
    }

    protected List<Contact> contacts = new List<Contact>();
    
    protected Contact selectedContact = null;
    
    public List<Contact> Contacts
    {
        get { return contacts; }
        set { contacts = value; }
    }
    
    public Contact SelectedContact
    {
        get { return selectedContact; }
        set { selectedContact = value; }
    }
}

This class will hold all the data that we're going to present. Delete the 'contacts' member and 'Contacts' property from the MainWindow.xaml.cs file - we don't need them any more. Also remove the lines we added to the constructor adding the contacts.

Where is the ViewModel instance stored? This is another question that causes confusion. Does the View ask for a ViewModel, does the application create the ViewModel and set it into the View? How do we tie it together? The short answer is that we're going to have a single instance of the ViewModel in the window object. But we're going to do it without adding a single line of code. The next few steps are really important - you'll probably use them for every window in your app.

Delete the binding we set before by clicking on the 'Reset' advanced properties popup on the list box 'ItemsSource' property. Build the project. Select the MainWindow in the designer by double clicking on the MainWindow.xaml file in the projects panel. Below it is an 'Objects and Timeline' panel. This shows a visual tree of what is in the window. The window is the top level object. Once it's selected, go to the Properties panel and find 'Data Context'.

Data Context Property

Isn't the search feature useful? If you haven't used it, give it a try - it'll save you lots of time. The DataContext can be thought of as the object or data that we're going to be binding UI elements to. It is hierarchical, so by setting it in the window, we set the data context for all of the controls - we can set it once and forget about it. The plan is to set the data context of the window to an instance of the ViewModel - this will greatly simplify things. Click 'New'.

Select Object

We can set almost anything to be the data context. Search for 'view' or 'viewmodel' and select the AddressBookViewModel class. Choose 'OK'. Now that we've set the data context, select the list box on the left hand side and go back to the 'Items Source' property. Press the Advanced button and choose 'Data Binding'. We can now use the 'Data Context' tab at the top - and we have our AddressBookViewModel object to play with. Select 'Contacts' and press 'OK'.

Create Data Binding

We are now using the data context and binding directly to the contacts. What has this actually done? Go to 'Split' view by pressing the small icon shown below, at the top right of the window. The data context has been set near the top of the XAML:

<Window.DataContext>
    <local:AddressBookViewModel />
</Window.DataContext> 

We've told the window that its data context is an instance of our AddressBookViewModel class. If we add the 'x:Name' attribute, we can even use it in the code-behind. Change the XAML to this:

<Window.DataContext>
    <local:AddressBookViewModel x:Name="ViewModel" />
</Window.DataContext>

We've now named this instance. Go to the MainWindow constructor in MainWindow.xaml.cs and change it to add some contacts:

public MainWindow()
{
    this.InitializeComponent();

    //    Add some contacts.
    ViewModel.Contacts.Add(new Contact() {Name = "James", 
                           Email = "james@mail.com", 
                           PhoneNumber = "01234 111111"} );

    ViewModel.Contacts.Add(new Contact() {Name = "Bob", 
                           Email = "bob@mail.com", 
                           PhoneNumber = "01234 222222"} );

    ViewModel.Contacts.Add(new Contact() {Name = "Emma", 
                           Email = "emma@mail.com", 
                           PhoneNumber = "01234 333333"} );
}

This is smart. The object we created in the XAML is available in the code-behind.

Let's get even more clever. In the same way as we set the data binding before, set the bindings below:

  • For the list box, bind the 'SelectedItem' property to 'Selected Contact'.
  • In the 'Name' text box, bind the 'Text' property to the 'SelectedContact > Name' property ('SelectedContact' can be expanded to show its members).
  • In the 'Email' text box, bind the 'Text' property to the 'SelectedContact > Email' property.
  • In the 'Phone' text box, bind the 'Text' property to the 'SelectedContact > PhoneNumber' property.

Hit F5. We have the list as before - but because we told the list to bind its selected item to the 'SelectedContact' property in our ViewModel, selecting an item in the list sets the 'SelectedContact' property. The three text boxes are bound to various properties of the 'SelectedObject' - so when we change, the text boxes are updated. Edit the text in each of the boxes and change to another contact - then change back. Our changes have persisted - the selected object is simply a reference to one of the items in our 'Contacts' list, so everything ties in together perfectly. Remember - the only code we've done to get the UI of the app working is setting some simple contacts in the constructor - we've actually tied in the text boxes and list control without ever leaving the designer.

Notification of Property Changes

We have missed out on something subtle. If you were to continue building the app with this approach, you'd soon notice something that is lacking - when we change ViewModel properties programmatically, the UI doesn't update. As a demonstration of this, we're going to update the program so that when the window has loaded, the first contact is automatically selected.

Open the MainWindow.xaml file in the designer. In the 'Objects and Timeline' panel, double click on the 'Window' item at the top of the tree to select the main window. Go to the Properties panel and choose 'Events'. The events icon is at the top right, as shown below:

Events

There are a stack of events we can handle, but for now, we want the 'Loaded' event. Find it in the list and double click on the text box to the right of the 'Loaded' label. This will create the event handler for us and will open it in the code editor. Change the event handler to select the first contact.

private void Window_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
    //    Set the 'SelectedContact' of the view model to the first contact.
    ViewModel.SelectedContact = ViewModel.Contacts[0];
}

Run the program. The first contact isn't displayed as selected. So what's gone wrong?

I'll save you some time with the debugger (which you'd have to use from Visual Studio!). The code you've written is being called, but the UI doesn't know that the SelectedContact has changed. So what do we do?

In a WinForms or Win32 application, we'd need to tell the UI that the object has changed; we might call Invalidate, Refresh or something along those lines. This is is not particularly good; it means that our small chunk of business logic needs to know about the UI, it has to know what to update. What if we need to do lots of things when the selected contact changes? What we'll do is tweak the ViewModel to implement the INotifyPropertyChanged interface. This interface allows us to send a notification when the property changes; anything that has registered to receive this notification will be updated. If we implement this interface in our ViewModel, then the UI will be notified that the property has changed and updates itself accordingly.

Create a new class file class 'ViewModelEntity', as below:

using System;
using System.ComponentModel;

namespace WpfStepByStep1
{
     /// <summary>
     /// Standard viewmodel class base, simply allows
     /// property change notifications to be sent.
     /// </summary>
     public class ViewModelEntity : INotifyPropertyChanged
     {
         /// <summary>
         /// The property changed event.
         /// </summary>
         public event PropertyChangedEventHandler PropertyChanged;
        
         /// <summary>
         /// Raises the property changed event.
         /// </summary>
         /// <param name="propertyName">Name
         ///              of the property.</param>
         public virtual void NotifyPropertyChanged(string propertyName)
         {
             //  If the event has been subscribed to, fire it.
             if (PropertyChanged != null)
                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
         }
     }
}

We can now tweak our ViewModel class to use this interface. Change as shown, the changes are in bold:

public class AddressBookViewModel : ViewModelEntity
{
    public AddressBookViewModel()
    {
    }
 
    protected List<Contact> contacts = new List<Contact>();
 
    protected Contact selectedContact = null;
 
    public List<Contact> Contacts
    {
        get { return contacts; }
        set { contacts = value; }
    }
 
    public Contact SelectedContact
    {
        get { return selectedContact; }
        set 
        { 
            if(selectedContact != value)
            {
                selectedContact = value;
                NotifyPropertyChanged("SelectedContact");
            }
        }
    }
}

When the SelectedContact is set, we check to see if it's being set to something different. If it is, we set it and raise the event. Run the program. The first item in the list is now selected, and the text boxes are all updated.

When do we need to do this? The short answer is almost always. We can ignore the Contact object for now, because we don't change any of its properties programmatically. But if we did, we'd need to use the same approach. In this case, we'd probably wrap it in a ContactViewModel class to keep the ViewModel specifics separate. There's one more change we should make, again shown in bold.

// Keep everything else the same as before - only change
// the Contacts member and property.

protected ObservableCollection<Contact> contacts = 
            new ObservableCollection<Contact>();
 
public ObservableCollection<Contact> Contacts
{
    get { return contacts; }
    set { contacts = value; }
}

To get this to build, you'll need to add the line using System.Collections.ObjectModel; to the top of the file. An ObservableCollection is a collection that sends notifications when items are added or removed. Now if we change the collection, then the View will be updated automatically. Why don't we need to call the 'NotifyPropertyChanged' function in the 'set' part of the 'Contacts' property? Because we don't change the reference to the collection - we change the items in the collection. So using ObservableCollection will suffice. If we were switching between lots of different collections, we'd need to call the function just like we do for the 'SelectedContact' property.

MVVM

We've now used the Model-View-ViewModel pattern in our application. In our Model, we have a basic Contact object. For our view, we have the MainWindow XAML. And we have a dedicated AddressBookViewModel object to tie the two together. We can keep the business logic and data layer separate to the presentation of the data; when you get used to this pattern, it makes more and more sense. One of the nice things about WPF is that it really forces you into this approach to get the most out of it - it'll help you design and write better code.

Moving On

There are still a few things left to do. For one thing, the list box on the left shows the name of the object it's displaying, but we want the contact name. Select the list box in the designer, and find the 'DisplayMemberPath' property. Set it to 'Name'.

DisplayMemberPath

Run the application. We now see the 'Name' property of the Contact object in the list. This is a quick way to get what we want. We could create an 'ItemTemplate' in the XAML that does much more - show the name, the email address below as a hyperlink, and so on, but that is a more advanced topic.

Now that we have the name set as the display member, we can see that we still have a limitation. Changing the name of a contact in the text box on the right doesn't update the list box. We know why now - the property is being changed by the list box, but the property doesn't send a notification when it is changed. We need to change the Contact object so that it derives from ViewModelEntity and sends notifications. Here's the code:

public class Contact : ViewModelEntity
{
    public Contact()
    {
    }
 
    protected string name;
    protected string email;
    protected string phonenumber;
 
    public string Name
    {
        get {return name;}
        set
        {
            if(name != value)
            {
                name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }
 
     public string Email
     {
         get {return email;}
         set
         {
             if(email != value)
             {
                 email = value;
                 NotifyPropertyChanged("Email");
            }
        }
    }
 
     public string PhoneNumber
     {
        get {return phonenumber;}
         set
        {
             if(phonenumber != value)
             {
                 phonenumber = value;
                 NotifyPropertyChanged("PhoneNumber");
             }
         }
     }
}

Make the changes and run the program. Now when you change the name and tab out of the control or select another, this list is updated. The Name property is not actually changed until we leave the box.

Adding New Data

We want to get the 'Create New Contact' button working. Select it in the designer, go to the events (in the property panel), and choose 'Click'. Double click the box to create an event hander, and add the code below:

private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
    //    Create a new contact.
    Contact contact = new Contact() {Name = "New Contact"};
 
    //    Add it to the list.
    ViewModel.Contacts.Add(contact);
 
    //    Set it as the selected contact.
    ViewModel.SelectedContact = contact;
}

After the initial complexity of setting the data context and creating some view model entities, we can implement business logic very rapidly now. In the code above, we don't tell the UI to update, we don't care whether the view is showing a list or how it displays itself. The bindings we've set up handle that side of things and the XAML controls rendering.

Back to MVVM

As an aside, it is worth pointing out that now that we've got to this stage, we're even closer to an ideal MVVM pattern. The 'Contact' object has actually become, in essence, a 'ContactViewModel' entity. Contact data will probably be stored in a file or database - these will be Contact Model entities - from these, we create Contact ViewModel entities - which might be quite different. For example, the ContactViewModel entity might want to store other data - such as whether it has been changed (allowing the view to show a 'Save Changes' button perhaps).

Rather than starting out with the MVVM pattern, we've moved towards it because we've needed to. Now that we're using it, we can extend this application with ease.

Next Steps

We've still got plenty of work to do on the Address Book application. It doesn't handle resizing well, it doesn't persist data, and looks very basic. But we've covered a lot - creating a new application, using a Data Context and Data Bindings, INotifyPropertyChanged, and ObservableCollections. Hopefully, you have become a bit more familiar with Expression Blend along the way. This is the first in a series of articles I am planning - any feedback would be great - let me know what you like or dislike and anything that's unclear. Where would you like to go from here? E-mail me at dwmkerr@googlemail.com and let me know - I'll write the next step by step based on what it seems people want to learn about next. For example:

  • Layout: Using Grids and Panels to lay out controls.
  • Style: Customising controls with styles and templates.
  • Data: Design-time data, XML, and more CLR.

Visual Studio 2010 vs. Expression Blend 4

Use them together! Expression Blend is great for layout, design, and styling, but Visual Studio is required for anything relating to code that is non-trivial. I always have both open, and use the two concurrently.

This project could be written in the same way using Visual Studio. It has a slightly less powerful data binding editor, and does things like creating data contexts visually less well, but when you're a bit more familiar with XAML, you'll probably end up writing a lot of it by hand. Expression Blend is the choice for designing your UIs, but Visual Studio is generally needed for the code behind.

History

  • 5 August 2010: Initial revision.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here