Skip To Content

Use the MVVM design pattern

In this topic

Model-View-ViewModel (MVVM) is a popular design pattern for XAML-based app development. MVVM helps you separate the user interface components of your app from the data and logic components.To accomplish this, the pattern divides components into the following three categories.

  • Model—Classes to represent data consumed in the app
  • View—User interface (UI) elements with which the user interacts
  • ViewModel—Classes that wrap data (coming from a model) and provide business logic for the UI (views)

In a pure MVVM implementation, components should fall exclusively within one of these categories. A UI class, such as a XAML page, should not contain code for the controls it contains. Instead, all code that is not directly related to the View (such as code for setting a page's data context) must be provided by a ViewModel. The data binding support provided in WPF, Windows Store, and Windows Phone apps allows you to define your UI with XAML and to bind controls in the View to ViewModel classes for required data and functionality

Generally, when creating an app using MVVM, most of your time is spent working within ViewModels. These classes provide data (either coming from a Model or within the ViewModel) in a form that is usable for the View. ViewModels may also contain code to handle events for controls on the page or other logic required by the View.

The MVVM pattern is well documented. The purpose of this tutorial is not to teach the details of the pattern, but rather to introduce it and illustrate its use with ArcGIS Runtime SDK for .NET. To learn more about the MVVM design pattern, refer to the links at the end of the tutorial.

Prerequisites

This tutorial requires a supported version of Microsoft Visual Studio and ArcGIS Runtime SDK for .NET. Refer to the appropriate topics in the guide for information on installing the SDK and system requirements.

Familiarity with Visual Studio, XAML, and C# is recommended.

Create a WPF app

You'll use Visual Studio to create a WPF app.

  1. Open a supported version of Microsoft Visual Studio.
  2. Choose File > New > Project (or click New Project on the Start page) to create a project.
  3. Click Windows Desktop > WPF Application in the New Project dialog box (you can create your project in either C# or VB .NET).
    Note:

    Visual Studio 2015 organizes project types slightly differently. You'll find WPF Application projects under Windows > Classic Desktop

    Tip:

    ArcGIS Runtime SDK for .NET provides a project template for creating your mapping app, called ArcGIS Runtime 10.2.7 for .NET App. Creating your project from the template will add the appropriate references and a page with a map view containing a single base layer. In this tutorial, you'll build your app from a blank template.

  4. Choose a folder location for your new project and name it MvvmApp.

    Visual Studio New Project dialog box

  5. Click OK to create the project.

    Your project opens in Visual Studio and contains a single WPF window called MainWindow.xaml.

  6. Next, you'll add a reference to the ArcGIS Runtime SDK for .NET API assembly.
  7. Right-click the References node under the MvvmApp project listing in the Visual Studio Solution Explorer window, and click Add Reference in the context menu.
  8. Check the listing for the Esri.ArcGISRuntime assembly under Assemblies > Extensions.

    Visual Studio Reference Manager dialog box

  9. Click OK to add the reference to ArcGIS Runtime for .NET.

    Visual Studio project references

  10. The Esri.ArcGISRuntime library contains the Map control and all core API components and classes you'll need.

Add a map

Now that you've created your project and added a reference to ArcGIS Runtime, you're ready to add a map to your app. In your map, you'll display a satellite imagery basemap from a public map service provided by ArcGIS Online and a point layer showing (fictional) community submitted incident reports. You'll define a custom renderer for the points and set an initial extent centered on Europe.

    To use the ArcGIS Runtime in the XAML designer, make references to required XML namespaces.
  1. Open the MainWindow.xaml file in the Visual Studio designer.
  2. Go to the XAML view of the designer, and add the following XML namespace reference to the Window XAML element. Visual Studio offers IntelliSense to help complete the URL portion of the statement.
    xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013"
  3. Add the following XAML inside the <Grid> element to define a new MapView control on the page containing a Map control with a few layers.
    <esri:MapView x:Name="MyMapView">
        <esri:Map>
            <esri:Map.InitialViewpoint>
                <esri:ViewpointExtent XMin="-1631122.453"  YMin="4253523.549" XMax="4163264.136"  YMax="8976345.495" />
            </esri:Map.InitialViewpoint>
            <esri:ArcGISTiledMapServiceLayer ID="BaseMap" 
                    ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"/>
            <esri:FeatureLayer ID="Incidents">
                <esri:ServiceFeatureTable 
                    ServiceUri="http://sampleserver6.arcgisonline.com/arcgis/rest/services/SF311/FeatureServer/0"/>
                <esri:FeatureLayer.Renderer>
                    <esri:SimpleRenderer>
                        <esri:SimpleMarkerSymbol Color="Red" Size="16" Style="Triangle"/>
                    </esri:SimpleRenderer>
                </esri:FeatureLayer.Renderer>
            </esri:FeatureLayer>
            <esri:GraphicsLayer ID="PointGraphics"/>
        </esri:Map>
    </esri:MapView>
  4. Run your app. A map similar to the one shown below appears.
    Note:

    The Incidents layer is based on an editable feature service. The number and location of features (red triangles) can vary day to day. If features (red triangles) don't appear in your initial map extent, try zooming to another location.

    Incident points with imagery basemap

Move the map out of the page

As a step towards separating the UI from data and app logic, move the XAML that defines the contents of the MapView control (the map) out of the page. You will store it in the application's resource dictionary and use data binding to display it in the MapView control.

  1. In your MainWindow.xaml file, select the entire contents of the MapView control (but not the map view itself). Choose Cut from the Edit menu to remove this XAML from its containing MapView.

    Your page should now contain an empty MapView, as shown in the following example:

    <Grid>
        <esri:MapView x:Name="MyMapView">
    
        </esri:MapView>
    </Grid>
  2. Open the App.xaml file in your project.
  3. If it doesn't exist, create an Application.Resources element, as shown in the following example.

    <Application.Resources>
            
     </Application.Resources>

  4. Place your mouse cursor inside the Application.Resources element in the page, and choose Paste from the Edit menu.

    The XAML that defines your map is added to the application's resource dictionary as shown in the example below.

    <Application.Resources>
        <esri:Map>
            <esri:Map.InitialViewpoint>
                <esri:ViewpointExtent XMin="-1631122.453"  
                                YMin="4253523.549" 
                                XMax="4163264.136"  
                                YMax="8976345.495" />
            </esri:Map.InitialViewpoint>
            <esri:ArcGISTiledMapServiceLayer ID="BaseMap" 
                    ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"/>
            <esri:FeatureLayer ID="Incidents">
                <esri:ServiceFeatureTable 
                    ServiceUri="http://sampleserver6.arcgisonline.com/arcgis/rest/services/SF311/FeatureServer/0"/>
                <esri:FeatureLayer.Renderer>
                    <esri:SimpleRenderer>
                        <esri:SimpleMarkerSymbol Color="Red" Size="16" Style="Triangle"/>
                    </esri:SimpleRenderer>
                </esri:FeatureLayer.Renderer>
            </esri:FeatureLayer>
            <esri:GraphicsLayer ID="PointGraphics"/>
        </esri:Map>
    </Application.Resources>
  5. You now have several warnings displayed in your Visual Studio designer. You will add required XML namespace references and provide a value for the x:Key property to fix them.
  6. Add the same XML namespace reference you added earlier to the Application element of the App.xaml page, as shown in bold in the following example.

    <Application x:Class="MvvmApp.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013"
                 StartupUri="MainWindow.xaml">

  7. Add an x:Key property to the Map element and give it a value of IncidentMap.

    <esri:Map x:Key="IncidentMap">

    Note:

    The x:Key property is used to identify a resource and should be unique within the scope of the object (in this case, the entire application).

  8. Return to the XAML for your Window and add XAML to bind the IncidentMap resource to the MapView element, as shown below.

    <esri:MapView x:Name="MyMapView" Map="{Binding Source={StaticResource IncidentMap}}">           
    </esri:MapView>

    A data binding for the Map property is specified using the binding markup extension in XAML. Bindings can be made to resources in the application, other elements on the page, or to a class in the app that provides data. More information about data binding in a XAML app can be found at Data binding overview (MSDN).

  9. Run your app. The map displays as it did when it was defined directly in the MapView.

Is your app implementing the MVVM pattern? Not in its purest form, but the App.xaml page is acting as a view model by providing a Map to which the MapView can bind. This illustrates one of the benefits of using the pattern, which is clearly separating the UI from implementation details where possible. The MapView is a UI control, which belongs on the page. The Map and the layers it contains are data displayed in the control, which is subject to change and should be managed outside the UI. With this architecture, the page and the map are loosely coupled, which means you can easily make changes to one without affecting the other. To change the map displayed in the page, for example, you could point the binding to another resource available in your application.

To implement the more traditional form of the MVVM pattern, you will create a view model class. The class acts as the data context for the page, and exposes data and functionality to which the UI can bind.

Create a view model class

A view model provides data and functionality that a view can access through data binding. It's common for a view to use a single view model, but it's not unusual for several view models to be associated with a single view. You can also have one view model that is used by several different views in your app. You will create a single view model (MapViewModel) to provide all data and functionality needed by your view.

  1. Right-click the MvvmApp node in the Solution Explorer and choose Add > Class from the context menu to add a new class to your project. Name the class MapViewModel.cs.

    Visual Studio Add New Item dialog box

  2. At the top of the MapViewModel code module, add the following using statements.

    using Esri.ArcGISRuntime.Controls;
    using Esri.ArcGISRuntime.Layers;
    The Esri.ArcGISRuntime.Controls namespace contains the Map class. You will use classes from the Esri.ArcGISRuntime.Layers namespace later.

  3. Add a new property to the class called IncidentMap, as shown in the following example.

    private Map map;
    public Map IncidentMap
    {
        get { return this.map; }
        set { this.map = value; }
    }
    The IncidentMap property provides a Map to which the view can bind.

  4. Add a constructor to the MapViewModel class that initializes the map, as shown in the following example. You could build the map programmatically by creating all of the required layers, symbolizing them, and setting the initial extent, and so on. Instead, reference the Map that you defined earlier in the App.xaml resources.

    public MapViewModel()
    {
        // when the view model initializes, read the map from the App.xaml resources
        this.map = App.Current.Resources["IncidentMap"] as Map;
    }
    The map property of your view model is complete. Next, you will update the data binding to display the map on the page.

Bind the view model to the view using XAML

To associate a view model with a view, you set the view's DataContext property to an instance of a view model. You can set the data context using XAML or by adding code to the view's code behind. In the following steps, you will use XAML to set the data context and bind the IncidentMap property in the view model to the Map property of the page's MapView.

Note:

If you want to set the view's data context programmatically, you can add the following two lines of code to the constructor in your code behind for (MainWindow.xaml.cs). If you add this code, proceed to step 4 to update the data binding for the map.

this.DataContext = new MapViewModel();

  1. Open your App.xaml page. At the top of the page, inside the Application element, add an XML namespace reference for the local assembly (MvvmApp), as shown in the following example.

    <Application x:Class="MvvmApp.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013"
                 xmlns:local="clr-namespace:MvvmApp"
                 StartupUri="MainWindow.xaml">
    You need to define this namespace to access the MapViewModel class in your XAML.

  2. Inside the Application.Resources element (below where the IncidentMap is defined), add XAML to define a new MapViewModel object (from the local namespace) with the key MapVM.

    <local:MapViewModel x:Key="MapVM"/>
    This object serves as the data context for the main page. You can refer to it using its key, MapVM. By defining it in the App, you can be assured that the object is created before any of the pages that use it as their data context.

  3. Open the MainWindow.xaml page. Set the data context for the entire page to the MapVM object, as shown in bold in the following example.

    <Window x:Class="MvvmApp.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013"
            Title="MainWindow" Height="350" Width="525"
            DataContext="{Binding Source={StaticResource MapVM}}">

    Since the view model is set as the data context for the entire page, any control on the page can bind to properties exposed by the view model class. You will bind the IncidentMap property to the Map property of the MapView control.

  4. Change the binding statement for the MapView to point to the IncidentMap property. Because the page's data context is set to a MapViewModel instance, it's implied that the binding comes from one of the properties of that object.

    <esri:MapView x:Name="MyMapView" Map="{Binding IncidentMap}">           
    </esri:MapView>

  5. Run your code. Again, the map should appear as it did when it was defined directly on the page.

What is the advantage of using such a scheme to display a map? The app looks the same regardless of where you define the map, yet using a view model seems to add a lot of complexity. For a basic app like this, there really is no advantage to using the MVVM pattern. As your app becomes more complex, however, you'll find that using an MVVM architecture makes your app much easier to maintain and promotes sharing of code between apps.

Handle a button click in the view model

Keeping data in a view model and binding it to the UI is straightforward, but what about view functionality?

To properly implement the MVVM pattern, all code logic should be contained in a view model. The code behind for UI classes should not contain event handling code for controls in the page. Fortunately, data binding can also be used to bind control events in the view to code in the view model.

Implement a command

Some controls, such as Button, CheckBox, RadioButton, and MenuItem provide a Command property. Commands are custom classes that implement the ICommand interface and define what happens when a control is clicked (Execute method), and determine when it should be enabled (CanExecute method). Commands can be created in your view model, and bound to the Command property of the appropriate control.

Tip:

There are several MVVM frameworks available that provide an implementation for ICommand. When using these frameworks, you can instantiate command objects in your view model without the intermediate step of creating your own command class, as described in this section. If you plan to use MVVM extensively, consider using a framework when developing your apps, such as MVVM Light.

  1. Add a new class to your project. Name it DelegateCommand.cs.
  2. The ICommand interface is in the System.Windows.Input namespace. Add a using statement at the top of the class for this namespace.

    using System.Windows.Input;

  3. Implement the System.Windows.Input.ICommand interface in your class. The complete implementation for the class is provided in the following example for you to paste into your class.

    class DelegateCommand : System.Windows.Input.ICommand
    {
        // a var to store the command's execute logic (button click, for example)
        private readonly Action<object> execute;
    
        // a var to store the command's logic for enabling/disabling
        private readonly Func<object, bool> canExecute;
    
        // an event for when the value of "CanExecute" changes (not implemented)
        public event EventHandler CanExecuteChanged;
    
        // constructor: store the logic for executing and enabling the command
        public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecuteFunc = null)
        {
            this.canExecute = canExecuteFunc;
            this.execute = executeAction;
        }
    
        // if it was passed in, execute the enabling logic for the command
        public bool CanExecute(object parameter)
        {
            if (this.canExecute == null) { return true; }
    
            return this.canExecute(parameter);
        }
    
        // execute the command logic 
        public void Execute(object parameter)
        {
            this.execute(parameter);
        }
    }

    When you need to bind a button to a command, create an instance of your DelegateCommand and pass in the behavior for the command execution and for enabling the control to the constructor. The parameter for the execute action is of type object to give maximum flexibility to the command.

  4. Save and close DelegateCommand.cs, since you no longer need to work in this class.

Create a command property in the view model

Anything you need to bind in your view must be defined as a public property in your view model. In this step, you'll create a new property in the MapViewModel that returns a DelegateCommand object. The command is defined with execution and enabling logic so it can be bound to a button in your view.

  1. Open your MapViewModel class. Define a public property called ToggleLayerCommand that returns a DelegateCommand object, as shown in the following example.

    public DelegateCommand ToggleLayerCommand { get; set; }

  2. Create a new function to handle command execution, called ToggleLayer. This function toggles the visibility of a layer in the map. The input parameter specifies the name of the layer to toggle.

    private void ToggleLayer(object parameter)
    {
        var lyr = this.map.Layers[parameter.ToString()];
        lyr.IsVisible = !(lyr.IsVisible);
        
    }

  3. Create another new function to determine the CanExecute state of the command. Since the command toggles a specific layer, it should only execute (be enabled, in other words) if that layer exists in the current map. The same parameter, the layer's name, is passed to this function.

    private bool OkToExecute(object parameter)
    {
        var lyr = this.map.Layers[parameter.ToString()] as FeatureLayer;
        return (lyr != null);
    }

    If a feature layer with the specified name does not exist in the map, OkToExecute returns false, which disables the associated control.

  4. In the MapViewModel constructor, add the following line of code to instantiate the ToggleLayerCommand. Pass in theToggleLayer function as the command's execution logic and OkToExecute as the enabling logic.

    public MapViewModel()
    {
        // when the view model initializes, read the map from the App.xaml resources
        this.map = MvvmApp.App.Current.Resources["IncidentMap"] as Map;
        ToggleLayerCommand = new DelegateCommand(ToggleLayer, OkToExecute);
    }

    Note:

    The CanExecute parameter for the DelegateCommand constructor was defined as optional. You don't need to provide a value if you want the command to always be enabled.

Bind a button to the view model command

Buttons provide a Click event that you can handle to execute code. Assigning a Command defines code for a button click, but has the advanatage of also containing logic to indicate when the button should be enabled or disabled. A Button object's Command property can be bound to an object that implements the ICommand interface.

In this section, you'll create a new button and bind the DelegateCommand object you created to its Command property.

  1. Add a new button to your MainWindow.xaml page below the existing XAML for the MapView control.

    <Button Height="30" Width="70" 
            HorizontalAlignment="Left" VerticalAlignment="Bottom" 
            Content="Toggle" />

  2. Set the new button's Command property by binding it to the ToggleLayerCommand property of the view model.

    <Button Height="30" Width="70" 
            HorizontalAlignment="Left" VerticalAlignment="Bottom" 
            Content="Toggle" 
            Command="{Binding ToggleLayerCommand}"/>

  3. Provide the incident layer's name as the command parameter by setting a value for the button's CommandParameter property.

    <Button Height="30" Width="70" 
            HorizontalAlignment="Left" VerticalAlignment="Bottom" 
            Content="Toggle" 
            Command="{Binding ToggleLayerCommand}"
            CommandParameter="Incidents"/>

  4. Run your app. Click the Toggle button to verify that the code in the view model executes to turn the incidents layer on and off.

    Incidents map with the points layer toggled off

Commands work well for binding functionality in your view model to certain controls in your view, such as buttons and menu choices. But what if you need to handle other events, such as a selection change in a combo box, or mouse and touch events on the map view? If you're interested in binding other event handlers from your view model, continue to the following section.

Handle other events in the view model

The process of binding to commands in the view model described previously works well for controls that provide the required Command property. What if you need to handle other events that cannot be directly bound using a command property? Fortunately, .NET provides additional classes that enable you to bind an event in the view to a command or function in your view model.

In the following steps, you will handle the ExtentChanged event of the MapView control using classes in the System.Windows.Interactivity assembly.

  1. Choose Project > Add Reference. In the Reference Manager dialog box, on the Extensions tab, check the listing for System.Windows.Interactivity. You'll find it under Assemblies > Extensions.
    Note:

    If this assembly is not available, you'll need to install the Microsoft Expression Blend SDK. You can also find a NuGet package with these assemblies by searching the Visual Studio NuGet package manager for "blend".

    Visual Studio Reference Manager dialog box

    After updating the project references, you must add an XML namespace reference to your MainWindow.xaml page so those classes can be used in your XAML.

  2. Inside your page's Window element, add the XML namespace reference shown in the following example.

    xmlns:interactivity="http://schemas.microsoft.com/expression/2010/interactivity"

  3. Add the following XAML inside the MapView element to define an EventTrigger for the map view's ExtentChanged event.

    <esri:MapView x:Name="MyMapView" Map="{Binding IncidentMap}">
        <interactivity:Interaction.Triggers>
            <interactivity:EventTrigger EventName="ExtentChanged">
    
            </interactivity:EventTrigger>
        </interactivity:Interaction.Triggers>
    </esri:MapView>

    You can respond to the EventTrigger using a function (method) or with a Command object. Because you need a parameter (the MapView), use a Command and provide a CommandParameter to pass the current map view to the view model code.

  4. Add the XAML in the following example to define an InvokeCommandAction in response to the event. The ExtentChangedCommand command does not yet exist in your view model; however, you will create it soon.

    <interactivity:InvokeCommandAction 
        Command="{Binding ExtentChangedCommand}"
        CommandParameter="{Binding ElementName=MyMapView}"/>

    The binding syntax shown in the previous code provides an example of binding to a XAML element. The command parameter is being set with an element on the page called MyMapView, which is your map view control. The map view object is needed to read current extent values.

    Next, you will create the ExtentChangedCommand to handle the event.

  5. Open MapViewModel.cs and add the following code to define a new DelegateCommand object called ExtentChangedCommand.

    public DelegateCommand ExtentChangedCommand { get; set; }

  6. Create the function shown in the following example to respond to an extent change. For now, verify that you can get the extent object from the map view.

    public void MyMapViewExtentChanged(object parameter)
    {
        var mv = parameter as MapView;
        var extent = mv.Extent;
    
    }

  7. In the constructor for MapViewModel, add the code shown in the following example to create the ExtentChangedCommand.

    public MapViewModel()
    {
        // when the view model initializes, read the map from the App.xaml resources
        this.map = MvvmApp.App.Current.Resources["IncidentMap"] as Map;
        ToggleLayerCommand = new DelegateCommand(ToggleLayer, OkToExecute);
        ExtentChangedCommand = new DelegateCommand(MyMapViewExtentChanged);
    }

    The CanExecute logic for DelegateCommand is optional, which is why you didn't need to specify it.

  8. Set a breakpoint on the last line of the MyMapViewExtentChanged function and run your app. You hit the breakpoint as soon as the app starts.

    Breakpoint in MapViewModel.cs when the extent changes

  9. When you are done testing, remove the breakpoint.

The binding successfully handles the extent changed event in the view model. The process described here could be used to handle any event raised by UI controls, including those that don't provide a Command property.

More work is required to show the extent values in the UI. If you're interested in completing this functionality, proceed to the next section.

Bind extent values to the view

To show the current extent coordinates in the app, you need to create a new public property on the view model to expose that information. Your property can then be bound to a UI element, such as a TextBox.

  1. Open MapViewModel.cs and add the following code to define a CurrentExtentString property.

    private string extentString;
    public string CurrentExtentString 
    { 
        get 
        { 
            return this.extentString; 
        } 
        set 
        { 
            this.extentString = value;  
        } 
    }

  2. Add the following code to set the value of CurrentExtentString in the extent changed event handler.

    public void MyMapViewExtentChanged(object parameter)
    {
        var mv = parameter as MapView;
        var extent = mv.Extent;
        CurrentExtentString = string.Format("XMin={0:F2} YMin={1:F2} XMax={2:F2} YMax={3:F2}", 
                                                extent.XMin, extent.YMin, extent.XMax, extent.YMax);
    }

    Extent coordinates are formatted in a string that looks like this: XMin=-2598746.47 YMin=4253523.55 XMax=5130888.16 YMax=8976345.50.

  3. Open your view, MainWindow.xaml, and add the following XAML to define a new TextBlock to display the extent string. Place this XAML below the XAML that defines your map view.

    <TextBlock Height="30" Width="Auto" 
                FontSize="16" Foreground="AliceBlue"
                HorizontalAlignment="Center" VerticalAlignment="Bottom"
                Text="{Binding CurrentExtentString}"/>

    The text block appears along the bottom center of the application and is bound to the property containing the extent values.

  4. Run your app. The extent string does not appear as expected.

    Extent information is not shown in the app

    For data binding to work as expected, you must raise a notification event when bound properties change. In this case, the extent string is being bound to the text block before it is given a value (it contains an empty string). When the value updates in the extent changed handler, the view is never notified that it should get an updated value. If you provided a default value for CurrentExtentString, you would see that value display when the app starts, but the value would not change.

    If that's the case, why does the binding for the map work? The IncidentMap property of the view model is set in the class constructor, which executes before the view model is set as the page's data context.

    To raise the required notification when a property changes, you must implement the INotifyPropertyChanged interface in the System.ComponentModel namespace.

  5. Add the following using statements to the top of your MapViewModel class

    using System.ComponentModel;
    using System.Runtime.CompilerServices;

  6. Implement System.ComponentModel.INotifyPropertyChanged in your MapViewModel class, as shown in the following example.

    class MapViewModel : INotifyPropertyChanged
        {
            ...

  7. The INotifyPropertyChanged interface requires the implementation of a single event: PropertyChangedEventHandler.
  8. Implement PropertyChangedEventHandler by adding the code shown in the following example.

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaiseNotifyPropertyChanged([CallerMemberName]string propertyName = null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

  9. Raise the change notification in your CurrentExtentString property's setter by calling the RaiseNotifyPropertyChanged function.

    private string extentString;
    public string CurrentExtentString 
    { 
        get 
        { 
            return this.extentString; 
        } 
        set 
        { 
            this.extentString = value; 
            this.RaiseNotifyPropertyChanged(); 
        } 
    }

  10. Run your app again. The extent information appears at the bottom of the map. Zoom and pan the display to see the information update.

    Current extent coordinates display at the bottom of the map

You've completed the tutorial, nice work. You now have an understanding of how to construct an app using the MVVM design pattern, including: data binding, commands, event triggers, and property change notification. To appreciate the usefulness of the MVVM pattern, create a new project (perhaps for another .NET platform) and reuse your ViewModel and Command classes for a different UI (View).

To learn more about these topics, consult the following resources:

Related topics