[blogpost] Navigating the MapView from a ViewModel

6974
6
01-30-2015 10:00 AM
Labels (1)
dotMorten_esri
Esri Notable Contributor
5 6 6,974

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-...

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

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.

6 Comments
BrianHennessey
New Contributor II

It does complicate things a little. I'm looking through the linked code and it seems to be fairly complex for just some basic map functionality. I'm failing to see the benefits of the MVVM approach. It seems like there are a number or workarounds like this trying to fit a square peg in a round whole.

dotMorten_esri
Esri Notable Contributor

The benefits of MVVM really becomes apparent when you start dealing with very large projects, when dealing with design vs code, unit testing, and code sharing.

For small simple apps, it might be overkill, but it is the #1 promoted pattern when it comes to XAML development.

I can't even begin to tell you how many 10,000+ lines of code-behind apps I've seen that are completely unmaintainable. MVVM forces you in to designing your app in a maintainable way. So it's an investment that will pay back down the line.

BikeshMaharjan1
New Contributor III

Hello Morten,

This seems pretty old post but I am trying to call identifygraphicsoverlaysasync from viewmodel to identify and get graphics on certain mouse events. I tried to follow the links you provided but it seems to be broken. Is there any example of similar kind?

Thanks!

BikeshMaharjan1
New Contributor III

Thank you for the links. It is helpful. Is there any sample code where mapview methods like "identifygraphicsoverlaysasync " is used from viewmodel? or if there is a way to identify graphics in certain layer from viewmodel. I am not sure if identifying graphics should only be done in codebehind? or it can/should be done in viewmodel.

Thank you again!

RichZwaap
Occasional Contributor III

FYI for anyone that might come across this, I've shared a way to handle this in another thread: https://community.esri.com/message/762894-re-accessing-mapview-methods-like-identifygraphicsoverlays...