Select to view content in your preferred language

Binding the map control in MVVM?

3243
3
09-30-2013 01:42 AM
Labels (1)
TomHutchinson
Deactivated User
Hi all.

I have written a simple app with code behind which I now want to convert to MVVM. I had a double mouseclick event on my map which got the position and returned the mapPoint to a text box which worked fine:

I then created a View Model class and wrote my own DoubleClick method. Any ideas on how to bind the map to this method in the XAML?

public void DoubleClick(object sender, GraphicMouseEventArgs e)
        {

            MainWindow main = new MainWindow();

            Point screenPoint = e.GetPosition (main.MapWindow);
            MapPoint mapPoint = main.MapWindow.ScreenToMap(screenPoint);

            GEOMText = mapPoint.ToString();
        }
0 Kudos
3 Replies
AnttiKajanus1
Deactivated User
Hi,

This is an interesting topic.

Lately I haven't bound any commands directly to map. I have created normal event handler to code-behind and then directed map point or other intended parameters for methods that are published from ViewModel. I don't want to have any mouse event args etc in my ViewModels so taking the actual point / points is better solution in this case. When I work with MVVM style, I have an interface that exposes needed methods from the ViewModel and I use that as contract from View.

so idea is something like this:


 <esri:Map MapGesture="OnGesture" /> <-- your event handler 


 private void OnGesture(object sender, Map.MapGestureEventArgs e)
        {
            if (e.Gesture == GestureType.Tap)
            {
                var vm = DataContext as IMyContractThatIsImplementedInViewModel;
                if (vm == null) // Check if current datacontext supports it.
                    throw new UnsupportedDataContextException();


                vm.DoMyViewModelStuff(e.MapPoint); // Call your VM without any external information.
            }
        }


For me this is ok solution. I know that some of the people wants to leave CodeBehind empty, but I don't think that its needed. To follow the idea of the MVVM, keep logic that is related on the View (ie. mouse events) in the View and implement ViewModel so that you can easily test those without any reference to the View or it's behavior.

If you want to bind whole method to ViewModel, then there are ways but I won't go to that now. If you really want to know how to do that, let me know and I will go through couple ways to do it.
0 Kudos
TomHutchinson
Deactivated User
Yes thanks. Looks like it is impossible to completely avoid code behind in the view.cs file as I don't see how you would call a method from the ViewModel which has to reference an object in the view when the whole basis of mvvm is that the view model is de-coupled entirely from the view?
0 Kudos
AnttiKajanus1
Deactivated User
There are ways to do that but I'm not sure if those are any cleaner solutions.

Another solution that you might want to think is to abstract the interaction with a map into MapService class that encapsulates behavior from the map that it is bound. This way you can also quite easily manage the click events from the view models and provide same action executed in several handlers. This is an approach that I have used when I have had to support both mouse and touch actions. Basically the MapService class manages the event handler jungle and makes sure that only one action is enabled at one time when user interacts with a map. This solution also works when you have modular application that doesn't have direct reference to the module where map is run. It also enables you to mock the behavior of the map if you are using automated tests. If you make sure that the reference is not published from the MapService and it is for example inject as a IMapService through Dependency Injection, you can retour your actions without working directly with map. Another way to hook your Map to MapService is to provide binding extension as a attached property.

If the description wasn't good enough, I blame the beer.
0 Kudos