Click here to Skip to main content
15,889,281 members
Articles / Desktop Programming / WPF

MVVM Series: Part I

Rate me:
Please Sign up or sign in to vote.
1.00/5 (1 vote)
16 Jan 2012CPOL7 min read 10.7K   6   4
Setting up an MVVM application and some simple binding to text and commands.

In this basic introduction to MVVM, I will taking you through setting up an MVVM application and some simple binding to text and commands. This is intended for developers who know C# and Visual Studio, but an unfamiliar with MVVM.

Let’s jump straight in:

Create a new solution, selecting WPF application. The first thing to do to help enforce MVVM is create separate assemblies for Views and ViewModels. Also, a helpful assembly to add is one for Services. In this context, a service is usually a piece of business logic the ViewModels will use in order to perform their task. So, the first assembly to add to the solution will be Views, which should be added as a New Project with a type of WPF User Control Library. This will give us a reference to all the UI libraries we will need.

The next assembly to create will be the ViewModels. Just create this as a class library, as it shouldn’t contain any UI specific knowledge.

And finally, create a Services assembly, again, just a plain old class library assembly.

Let us now construct some sort of View for us to enter some information with a button that will add that information into a list to be displayed on the bottom in a grid. The Views assembly will have UserControl1.xaml, let’s remove this and add in something more sensible. Let’s call it InputForm, for lack of inspiration. So, remove the UserControl1.xaml via the solution and then add new item and select User Control (WPF). Now rename that to InputForm.xaml and select Add.

Now, inside the tags, add:

XML
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>

This will just setup the grid to have three columns, all sizing to their content.

After this, enter the following:

XML
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

This will tell the grid to have its first row to size to its contents and the rest of the grid should use the rest of the control’s space.

Add the following code:

XML
<TextBlock Text="Name"/>
<TextBox Grid.Column="1″/>
<Button Grid.Column="2″>Add</Button>

This creates a basic view that has a label, followed by a text box and finally a button that will allow us to add the name.

Now, let us add a control to the second row of our grid. This will display a list of the added names. For this, we may as well just use a listbox.

XML
<ListBox Grid.Row="1″ Grid.ColumnSpan="3″>
</ListBox>

This will add the ListBox to the second row of the grid and let it span across the three columns that we specified.

Ok, so we need to add this view to our MainWindow in order for it to display. Add a reference to the Views assembly in the main application.

Now open the MainWindow.xaml and add in a namespace to reference our view's assembly.

XML
xmlns:views="clr-namespace:Views;assembly=Views"

will do the trick. This says we are going to create a views namespace and that it comes from the namespace Views and assembly Views.

Now, in our XAML, we can reference our InputForm inside the Grid tags like so:

XML
<Grid>
<views:InputForm/>
</Grid>

In the designer, you should now see the InputForm control show up. Ok, run it up and you should be able to type some text into the box next to name and press the button. Not very elegant, I know, but we are just demonstrating the MVVM part of this.

Now, we want to be able to capture that input and display it in the ListBox below.

For this, we now need to move to the ViewModel's assembly and rename our Class1.cs to CustomerViewModel.cs.

And give it a property ‘Name’ which is of type string.

For now, just give make this an Auto property with a get and set:

C#
public string Name
{
    get;
    set;
}

Back in our main application, we need to add a reference to our ViewModel's assembly.

Now, back in our MainWindow.xaml.cs we can set the DataContext of the window to be a new one of these.

C#
public MainWindow()
{
    InitializeComponent();
    this.DataContext = new CustomerViewModel();
}

This will set our MainWindow’s DataContext to an instance of CustomerViewModel. Because the DataContext cascades down to its children, our InputForm will also have its DataContext set to the instance of CustomerViewModel.

Back in our InputForm.xaml we can now bind the TextBox to our Property ‘Name’ in the CustomerViewModel:

XML
<TextBox Grid.Column="1″ Text="{Binding Name}"/>

This means that the Name will be taken from what’s in the current DataContext (which in this case is our CustomerViewModel instance).

Now, anything typed into our TextBox will automatically be placed into our object’s Name property by the magic of binding.

Of course, you can’t see what’s in the ViewModel at this point. Ok, a little test to make sure it’s all working, lets place a TextBlock to the right of the Add button to display what’s currently in the ViewModel.

Our grid now looks like:

XML
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="Name"/>
<TextBox Grid.Column="1″ Text="{Binding Name}"/>
<Button Grid.Column="2″>Add</Button>
<TextBlock Grid.Column="3″ Text="{Binding Name}"/>
<ListBox Grid.Row="1″ Grid.ColumnSpan="4″>
</ListBox>
</Grid>

We’ve added in a 4th column to show the typed in text and added a new TextBlock that will display in that column. This time the TextBlock’s Text is bound to our Name property.

Now when we run the application and type information into our name and we tab out of the box, the name is displayed to the right of the Add button, exactly as you typed it in.

Now we know our binding is working, we can get on with displaying our list of customers. At the moment, we have a ViewModel representing 1 customer. This won’t be any good. Let’s create a new ViewModel and call it MainViewModel. This will have a view model for the new customer as well as a list of existing customers.

C#
public class MainViewModel
{
    public MainViewModel()
    {
        NewCustomer = new CustomerViewModel();
    }
    public CustomerViewModel NewCustomer
    {
        get;
        private set;
    }
}

This will expose our NewCustomer as a read-only variable, as we don’t want any other developer’s overwriting it.

Our InputForm.xaml will then change its bindings to:

XML
<TextBox Grid.Column="1″ Text="{Binding NewCustomer.Name}"/>
<TextBlock Grid.Column="3″ Text="{Binding NewCustomer.Name}"/>

Which says bind to our DataContext’s NewCustomer property and then its property Name.

In order for that to work, we must now change what the MainWindow’s DataContext is set to:

C#
this.DataContext = new MainViewModel();

Running that should react exactly as before, but we’ve now pushed the CustomerViewModel down a layer.

We now need to modify the MainViewModel to have a list of customers that have been added:

C#
public class MainViewModel
{
    private ObservableCollection customers = new ObservableCollection();
    public MainViewModel()
    {
        NewCustomer = new CustomerViewModel();
    }
    public CustomerViewModel NewCustomer
    {
        get;
        private set;
    }
    public ObservableCollectionCustomers
    {
        get { return this.customers; }
    }
}

Here we have introduced a list of customers in an ObservableCollection. This is a special type of collection that can be observed by the binding from XAML.

When items are added, removed etc, notifications are sent out which WPF binding knows about and can keep things up to date on screen.

Now we need to be able to add customers to this list.  This needs to be done when the user presses the Add button.

The nice thing about WPF buttons is they know about commands, more specifically commands that derive from ICommand. So on the MainVieWModel, we need to add a command for adding customers.

Unfortunately, ICommand resides in some WPF specific libraries and seeing we created this as a normal class library, their references aren’t there. We can easily remedy this and add the references to:

  • PresentationCore
  • PresentationFramework

Then add a new property to MainViewModel for the add command:

C#
public class MainViewModel
{
    private ObservableCollection customers = new ObservableCollection();
    public MainViewModel()
    {
        NewCustomer = new CustomerViewModel();
        AddCustomerCommand = new DelegateCommand
        public CustomerViewModel NewCustomer
        {
            get;
            private set;
        }
        public ObservableCollectionCustomers
        {
            get { return this.customers; }
        }
        public ICommand AddCustomerCommand
        {
            get;
            private set;
        }
    }

Here AddCustomerCommand has been constructed as a new DelegateCommand. This is a specialised command taken from Microsoft’s Prism Library.

The x=> represents what will happen when the command’s Execute method is called. Again, the button will know about ICommand and its Execute methods.

We now need to bind to the command from the InputForm.xaml:

XML
<Button Grid.Column="2″ Command="{Binding AddCustomerCommand}">Add</Button>

This will execute our command, which will then add the customer to our Customers list. You can check this with a breakpoint inside the command function.  We won’t see anything in the list yet, because we haven’t wired up the XAML to bind to the Customers. Let’s do that now:

XML
<ListBox Grid.Row="1″ Grid.ColumnSpan="4″ ItemsSource="{Binding Customers}">
</ListBox>

Run the application again and when you press add, it adds the customer to the list.  But, what’s this? It’s showing ViewModels.CustomerViewModel which is the class name. This is because the ListBox’s default item template is being used and that doesn’t know what we want to display from this class. Let’s rectify that:

XML
<ListBox Grid.Row="1″ Grid.ColumnSpan="4″ ItemsSource="{Binding Customers}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

That’s better. We have now specified a DataTemplate with which to display each item. Inside that, we have a TextBlock which is bound to the Name property. This now correctly displays our name in the list.  Pressing add now displays the correct information.

This has been a very basic introduction to MVVM using some basic ViewModels and Views. I’ll be expanding on this application with a series of articles getting into MVVM and more complex binding, IValueConverters and Behaviors.

I hope you enjoyed this and please leave comments on anything not understood or things you would like expanded upon.

This article was originally posted at http://tap-source.com?p=160

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) NoProblem Software Ltd
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 1 Pin
MZakhvatkin19-Jan-12 7:53
MZakhvatkin19-Jan-12 7:53 
GeneralRe: My vote of 1 Pin
SteveAdey19-Jan-12 11:01
SteveAdey19-Jan-12 11:01 
GeneralRe: My vote of 1 Pin
SteveAdey19-Jan-12 11:04
SteveAdey19-Jan-12 11:04 
GeneralRe: My vote of 1 Pin
SteveAdey19-Jan-12 11:07
SteveAdey19-Jan-12 11:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.