mnielsen-esristaff

[blogpost] Navigating the MapView from a ViewModel

Blog Post created by mnielsen-esristaff Employee on Jan 30, 2015

When using the MVVM style pattern to build your XAML-based app, you don't want to include references to your View objects from within your ViewModel. This means that the ViewModel won't be able to for instance call "Zoom" on the MapView, because this operation is on the MapView, and the ViewModel is not allowed to have a reference to anything on the View. You'll find similar common challenge with ScrollViewer, where you want to scroll to a certain item in a list, but again the scroll operation is on the view, since this is a view operation.

 

The pattern to handle this is to create a controller your ViewModel owns, and you bind this to the view object, using an attached property. The ViewModel can then 'request' zoom operations on the controller, and if that controller is bound to a map view, it will handle executing the SetView call on the MapView.

 

I've added an example of this to the WPF Desktop Sample App:

arcgis-runtime-samples-dotnet/NavigateFromViewModel.xaml.cs at master · Esri/arcgis-runtime-samples-dotnet · GitHub

arcgis-runtime-samples-dotnet/NavigateFromViewModel.xaml at master · Esri/arcgis-runtime-samples-dotnet · GitHub

 

The attached property is shown here on line 1:

 

<esri:MapView local:MapViewController.Controller="{Binding Controller}">
     <esri:Map>
          <esri:ArcGISTiledMapServiceLayer
                ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer" />
     </esri:Map>
</esri:MapView>

 

The ViewModel class defines an instance of MapViewController, and exposes it in the property "Controller", which is what is being bound above.

 

Inside the controller, code is triggered when it is bound to the MapView and will keep an internal weak reference* to the map view, so that it can perform the operation if it is bound. The Controller can also expose properties from the MapView back out, like in this example where the current 'Extent' property is available for use to add bookmarks. You could add more properties like the current Scale or Rotation, or add more commands to perform on the view.

 

Using this pattern, the ViewModel never knows anything about the MapView, but is still able to perform zoom operations.

 

This pattern works just as well with Windows Store and Windows Phone as well, and you can copy the MapViewController class over to use the as well.

 

*We're using weak references to the MapView and it's events. It complicates the sample a little, but it ensure that if the ViewModel stays around for a long time, but you close the page/window that the MapView is on, the MapView control won't stay around in memory, but can be garbage collected.

Outcomes