Sunday, April 12, 2015

MVVM Part 2

In Part 2 of our MVVM walkthrough we will define a simple ViewModel. Our Config table only contains one row so our aim in this blog entry is to display the value from that row in a textbox.

Normally at this point we would add a textbox to MainWindow.xaml and start putting code in MainWindow.xaml.vb, but this is MVVM so we will start by creating our ViewModel. There is nearly always one ViewModel per page so lets start by adding a new class to the project called MainWindowViewModel. In a larger project you might want to group all your ViewModels into a folder called, perhaps, ViewModels. We won't need to do that here.

Create the ViewModel

    1. Add a new class called MainWindowViewModel
    2. Add "Imports System.ComponentModel"
    3. Add "Implements INotifyPropertyChanged". This will add a PropertyChanged event definition.
    4. After the PropertyChanged event, add the following method. We will discuss this later.

        Public Sub NotifyPropertyChanged(PropertyName As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(PropertyName))
        End Sub

    5. Add a private variable called Model as MVVM_WalkthroughEntities
    6. In the constructor add the following code...

        Dim an = (From a In Model.Configs Select a Where a.[Key] = "ApplicationName").ToList()
        Me.ApplicationName = an(0)

    7. Add a private member called _ApplicationName and a public property called ApplicationName. The only unusual thing here is that the property setter calls NotifyPropertyChanged.

    Private _ApplicationName As Config
    Public Property ApplicationName As Config
        Get
            Return _ApplicationName
        End Get
        Set(value As Config)
            If Not value.Equals(_ApplicationName) Then
                _ApplicationName = value
                NotifyPropertyChanged("ApplicationName")
            End If
        End Set
    End Property

It's about time we looked at INotifyPropertyChanged. Although it's very important in WPF, I find a lot of programmers don't understand it.

If your ViewModel does not implement INotifyPropertyChanged then when its properties are changed, the View will not update. When you call NotifyPropertyChanged you send a message to any view that is bound to it saying "Go refresh yourself". The important thing is that the ViewModel does not need to know what View is bound to it. Remember, in WPF the view contains a reference to the ViewModel - not the other way around.

So what have we achieved here? We have a single property called Config which represents a single row from the Config table. It has two useful properties called Key and Value which contain the data from the row and that the View can bind to. We populated the Config object in the ViewModel constructor using some LINQ.

It's time to create the View.

    1. Before you can reference the ViewModel you must build the project. Do it now.
    2. Open MainWindow.xaml in XAML mode.
    3. Add a namespace definition for the ModelView
            xmlns:vm="clr-namespace:MVVM_Walkthrough"

    4. Set the datacontext of the view to the ViewModel we created above. Note the editor may incorrectly flag this as an error but you will still be able to build and run.
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>

    5. Now we will be able to bind to every public property in MainWindowViewModel, such as the Config property. Add the following XAML inside the <Grid> tags.
    <Grid.RowDefinitions>
            <RowDefinition Height="auto"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto"></ColumnDefinition>
            <ColumnDefinition Width="auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="{Binding Path=ApplicationName.Key}"></Label>

        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=ApplicationName.Value}" Width="200"></TextBox>

The completed application.

If you build and run the application now you will see that the label and textbox are populated as expected. This may seem like a lot of work to achieve something trivial, but as you application becomes more realistically complicated the value of separation between View and ViewModel becomes more apparent.

Unfortunately, as the number of properties increases, so does the tedium of coding each one but there are toolkits such as MVVM Light that alleviate that.

In Part Three we will look at what it would take to save the Application Name back to the database. 

No comments:

Post a Comment