WPF and MVVM: GeoViewTapped Event

4517
13
03-04-2019 08:30 AM
MonikaLucas
New Contributor III

Hello, 

I am trying to create binding for the GeoViewTappedAsync event so that I can place the code in my MapViewModel to follow an MVVM pattern for my WPF application, however I'm not sure how to wire this up. Is there some sample code available that demonstrates this pattern? After looking through GeoNet, I have found some suggestions but they are a few years old.

<esri:MapView x:Name="MainMap" Map="{Binding Map}"  GeoViewTapped="Binding {to what does this bind?}">

Thank you!

Jen

0 Kudos
13 Replies
RichardHughes2
Occasional Contributor III

Today I did successfully Query the map's Operational Layers using the location passed from the MapView to the View through a binding.  That is all I really needed to do since the Map and all its Operational Layers are available in the View Model.  But as I figuring out how to work with the MapView programatically my brain short-circuited.  The screen vs map points is a great point to make regarding the differences between the Map and the MapView and all the screen sizing that takes place on the client.  I do really like this new design with the MapView and appreciate all that is going into it.  I do use code behind to enable the location service on the MapView.  Eventually that will have to get put somewhere else if I integrate with an external GPS receiver, or maybe not?  That will be interesting.

0 Kudos
JoeHershman
MVP Regular Contributor

Also one thing to consider: IMHO the purist MVVM approach where absolutely no code-behind can ever exist isn't really true to what MVVM is saying. You can have code-behind, as long as that code-behind is view-specific. 

YES!.  And in a large application I think this is absolutely required (certainly with Runtime it is).

Here is how we do something like changing viewpoint.  This code is in the MapViews Code behind.  Zoom is done from anywhere in the application by firing a SetViewpointEvent

private async void OnSetViewpoint(SetViewpointEventArgs args)
{
	//First see if a viewpoint was sent, otherwise use a geometry
	try
	{
		if ( args.Viewpoint != null )
		{
			await MapView.SetViewpointAsync(args.Viewpoint, TimeSpan.FromMilliseconds(750));
			return;
		}

		var geometry = args.Geometry;

		switch (geometry)
		{
			case MapPoint mapPoint:
				if (MapView.MapScale < args.Scale)
				{
					await MapView.SetViewpointCenterAsync(mapPoint);
				}
				else
				{
					await MapView.SetViewpointCenterAsync(mapPoint, args.Scale);
				}

				break;
			case Polyline polyline:
			{
				var envelope = polyline.Extent;
				var buffer = GeometryEngine.Buffer(envelope, 1000);
				var viewpoint = new Viewpoint(buffer);

				await MapView.SetViewpointAsync(viewpoint, TimeSpan.FromMilliseconds(750));

				break;
			}
			case Polygon polygon:
				await MapView.SetViewpointGeometryAsync(polygon.Extent, args.Padding);
				break;
			case Envelope envelope:
				await MapView.SetViewpointGeometryAsync(envelope);
				break;
		}
	}
	catch (Exception e)
	{
		_log.Error(e.Message, e);
	}
}

We do similar stuff with displaying popups, saving screen images, and functions that are exposed by the MapView object

Thanks,
-Joe
RichardHughes2
Occasional Contributor III

Update from me on using a Controller for the MapView.   I like how I can now both listen to events and call methods on the view model.  Thanks to the samples from esri folks I was able to get this together for another productive day tomorrow.  I'll be studying this code more... Thanks for you help.  What I did was combine a 10.2.x sample on navigating with the view model Navigate from ViewModel | ArcGIS for Developers, and a more recent sample of listening to the GeoView Tap Events via a ControllerAccessing MapView methods like IdentifyGraphicsOverlaysAsync from viewmodel.  I don't see a button for code formatting otherwise I would post what I have.  It is basically relies on the classes and stuff in C# that I don't know yet, so I will be busy with that.  Meanwhile getting over this hurdle will make everything soo much brighter!!

0 Kudos
JoeHershman
MVP Regular Contributor

I won't get into a philosophical discussion, but I don't consider the Controller approach as MVVM, it is simply a clean way to expose MapView outside the view that contains it.  There is an old discussion about this Accessing MapView methods like IdentifyGraphicsOverlaysAsync from viewmodel.  In there is a way that I have used a TriggerAction to attach Identify behavior to the MapView.  It then uses eventing to send results to the rest of the application.

I have written a very large scale enterprise application consisting of over a dozen separate modules and been almost completely able to avoid having to share the MapView.  The one issue is with a module that uses the TOC toolbox control which requires the MapView and in there the controller approach was used to pass the MapView.  Everything else can be done using event publish/subscribe from the code behind of the view containing the MapView.

I agree with your initial statement, to me the MapView provides too much functionality and really hampers building a nice MVVM structure.  It (literally) took me years to work through all the various places I required MapView methods and organize them in what I consider a clean MVVM manner where the remainder of the application has no knowledge of the MapView (excluding the TOC issue)

Thanks,
-Joe
0 Kudos