Click here to Skip to main content
15,867,568 members
Articles / Desktop Programming / WPF

Basic Outlines and Examples on MVVM pattern

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
5 Jan 2015CPOL5 min read 18.2K   163   4   5
Entry-level examples on MVVM pattern, explaining the basic methods to mantain separated a program's graphical interface from its business logic

Introduction

In this article, we'll see some basic concepts about MVVM pattern (Model View Viewmodel), trying to stick as much as possible to its paradigms, namely a strong reduction (aiming at the complete suppression) of the code behind controls and graphics in general. We'll do that through XAML, and some classes prepared for that mean, and for data presentation.

MVVM pattern was made to keep an app graphical part separated from the business logic. Its fundamental paradigm is therefore the introduction, by the developer's efforts, of an intermediate layer between the View (namely, everything in the program which can be traced back to its UI) and the Model (or, the program logic, its flow, independently from graphical context. In this definition is also included the data management of data for which we desire to produce a graphical representation). I will put more emphasis on clarity compared to excessive technicality, aiming to be as simple as possible.

A first example

In this section we'll see two primary concepts about MVVM pattern. First, we must look briefly at DataContext and Binding concepts. DataContext is, in short, the source, or the origin, of the elements on the base of which we could use the Binding, which is the link between the value of a certain property and a visual control.


Let's suppose, for example, to have a WPF window with a TextBox, and in the latter we want to visualize the window's title. As a second thing, we want to be able to modify the window's title by modifying the content of TextBox. In other words, we desire to bind the two control in a bidirectional way. Therefore, we need to tell to the TextBox that its DataContext is the window, and the Binding to be executed on the Text property must lay on the Title property of the window. In the XAML of our window, we can realize such a thing with the following code:

XML
<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Name="MainWindow"
    Title="MainWindow" Height="111.194" Width="295.149">
     
    <TextBox Name="TB1" Text="{Binding Title, ElementName=MainWindow, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
             HorizontalAlignment="Left" Height="22"  VerticalAlignment="Top" Width="248"/>
</Window>

In short, we assigned to the window a Name (MainWindow in the example). After that, we have binded the Text property of TextBox to the Title property, which belongs to MainWindow (which is, in such a case, DataContext of TextBox), in a bidirectional mode (TwoWay), indicating the property modification as the event which will launch the counterparts'update operations (PropertyChanged). For additional information on the syntax relative to Binding operations, see Basic Examples on WPF Data Binding.

Running this small example, we'll notice that the windows'title will be modified in function of which is digited in the TextBox. In the same way, if we modify our code to intervene on the windows'title, we'll see and update of the TextBox content.

Binding of a DataModel

Let's suppose we're in the need of managing a binding toward an external class, relatively to the context in which we'll show it. A class example follows, useful for an hypothetical product representation, with properties as a product's code and a description:

VB.NET
Public Class ItemData
    Public _code As String
    Public _des As String
 
    Public Property Code As String
        Get
            Return _code
        End Get
        Set(value As String)
            _code = value
        End Set
    End Property
 
    Public Property Description As String
        Get
            Return _des
        End Get
        Set(value As String)
            _des = value
        End Set
    End Property
 
    Public Sub New(ByVal code As String, ByVal des As String)
        _code = code
        _des = des
    End Sub
End Class

Being a class which can define new products and entities, equipped with a constructor which initializes its fundamental properties, that class can't be directly used as a DataContext as long as it isn't referenced in a variable. That means we must operate on the code-behind, if we wish to execute a Binding - let's say, of Code property - indicating the TextBox's DataContext only after we've successfully initialized an ItemData type variable.

For example, if we decide to manage the window's Loaded event, we could write:

VB.NET
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs)
  Dim item As New ItemData("PRDCODE01", "TEST PRODUCT")
  TB1.DataContext = item
End Sub

Where the corresponding XAML will be:

VB.NET
<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation [This link is external to TechNet Wiki. It will open in a new window.] "
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml [This link is external to TechNet Wiki. It will open in a new window.] "
    xmlns:local="clr-namespace:WpfApplication1"
    Name="MainWindow" Loaded="MainWindow_Loaded"
    Title="MainWindow" Height="111.194" Width="295.149">
     
    <TextBox Name="TB1" Text="{Binding Code}"
             HorizontalAlignment="Left" Height="22"  VerticalAlignment="Top" Width="248"/>   
</Window>

Here, we'll indicate in the TextBox's Text property a more concise syntax, compared to its predecessor. Beyond the fact that we are not managing here the data bidirectionality, note the presence alone of Code property, without any hint to the element (or DataContext) from which it must be derived. This is because the DataContext is specified code-side, initializing an ItemData-type variable, and subsequently indicating as the TextBox data context the brand new variable. Running this example, we'll note that the TextBox exposes a value equal to PR_CODE_01, namely the string we've used to initialize the Code property of our ItemData.

As described in the opening, that kind of approach - although working - does not meet fully MVVM paradigms. In the above example, we have the View (our window) and the Model (item variable, referenced as ItemData). In the window's code-behind, we've created a reference to the model, creating an interdependence between the two: if we delete our code from the Loaded event, the TextBox binding will naturally cease to work. To keep separated the two entities, it is necessary an intermediate layer introduction, or the ViewModel: that will be a class through which we'll expose the Model to the View, making the two layers completely mutually independent. Let's see how it can be done.

A simple ViewModel

A ViewModel encapsulate a model, exposing all the properties which can be useful for the View to access underlying data. In general, it implements the INotifyPropertyChanged [This link is external to TechNet Wiki. It will open in a new window.] interface, which will be used, as an event, to trace all the changes of a specific property. In our case, assuming we want to make the more minimal of possible ViewModels, we could write a class like the following:

VB.NET
Imports System.ComponentModel
Public Class ItemDataView
    Implements INotifyPropertyChanged
 
    Dim item As New ItemData("PR_CODE_01", "TEST PRODUCT")
 
    Public Property Code
        Get
            Return item.Code
        End Get
        Set(value)
            If Not (item.Code = value) Then
                item.Code = value
                NotifyPropertyChanged("Code")
            End If
        End Set
    End Property
 
    Public Event PropertyChanged As PropertyChangedEventHandler _
        Implements INotifyPropertyChanged.PropertyChanged
 
    Private Sub NotifyPropertyChanged(Optional ByVal propertyName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub
End Class

This class initializes an ItemData, creating a new instance of it, and exposing its Code property. At the same time, it allows the modification of such property, raising a call to the PropertyChanged event, to produce a notification of the occurred change.

To make this ItemDataView visible and usable in the entire MainWindow context, we could indicate in the window's XAML the DataContext as global for all the controls contained in it. The TextBox Binding property will continue to be Code, exposed by the ViewModel:

XML
<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Name="MainWindow"
    Title="MainWindow" Height="111.194" Width="295.149">
     
    <Window.DataContext>
        <local:ItemDataView x:Name="MyItemView"/>
    </Window.DataContext>
     
    <TextBox Name="TB1" Text="{Binding Code}"
             HorizontalAlignment="Left" Height="22"  VerticalAlignment="Top" Width="248"/>   
</Window>

Alternately, if we wish to indicate the specific TextBox DataContext, we could write:

XML
<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Name="MainWindow" Title="MainWindow" Height="111.194" Width="295.149">
        
    <TextBox Name="TB1" DataContext="{Binding Source=ItemDataView}" Text="{Binding Code}"
             HorizontalAlignment="Left" Height="22"  VerticalAlignment="Top" Width="248"/>   
</Window>

In both cases, at runtime we'll see the TextBox Text property with a value of PR_CODE_01, obtained from the exposed ItemDataView's ItemData.

History

  • 2015-01-05: First Release for CodeProject

License

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


Written By
Software Developer
Italy Italy
Working in IT since 2003 as Software Developer for Essetre Srl, a company in Northern Italy.
I was awarded in 2014, 2015 and 2016 with Microsoft MVP, for Visual Studio and Development Technologies expertise. My technology interests and main skills are in .NET Framework, Visual Basic, Visual C# and SQL Server, but i'm proficient in PHP and MySQL also.

Comments and Discussions

 
SuggestionOption Strict On Pin
Mr.PoorEnglish5-Oct-15 5:37
Mr.PoorEnglish5-Oct-15 5:37 
GeneralRe: Option Strict On Pin
Emiliano Musso5-Oct-15 20:48
professionalEmiliano Musso5-Oct-15 20:48 
GeneralMy vote of 5 Pin
FranzBe7-Jan-15 0:06
FranzBe7-Jan-15 0:06 
QuestionWell done. Pin
bojammis6-Jan-15 7:20
professionalbojammis6-Jan-15 7:20 
AnswerRe: Well done. Pin
Emiliano Musso6-Jan-15 7:50
professionalEmiliano Musso6-Jan-15 7:50 

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.