Search code examples
windows-runtimewinrt-xamlwindows-phone-8.1winrt-component

MapControl differentiate between user or programmatic center change


In the WinRt/WP 8.1 MapControl, how do I differentiate between when the user changed the center of the screen by swiping vs a programmatic change?

The WinRt/WP 8.1 MapControl has a CenterChanged event ( http://msdn.microsoft.com/en-us/library/windows.ui.xaml.controls.maps.mapcontrol.centerchanged.aspx ), but this does not provide any info about what caused the center change.

Is there any other way of knowing whether or not the user changed the map center?


/* To give some more context, my specific scenario is as follows:
Given an app which shows a map, I want to track the gps position of a user.

  • If a gps position is found, I want to put a dot on the map and center the map to that point.
  • If a gps position change is found, I want to center the map to that point.
  • If the user changes the position of the map by touch/swipe, I no longer want to center the map when the gps position changes.

I could hack this by comparing gps position and center, but he gps position latLng is a different type & precision as the Map.Center latLng. I'd prefer a simpler, less hacky solution. */


Solution

  • I solved this by setting a bool ignoreNextViewportChanges to true before calling the awaitable TrySetViewAsync and reset it to false after the async action is done.

    In the event handler, I immediately break the Routine then ignoreNextViewportChanges still is true.

    So in the end, it looks like:

    bool ignoreNextViewportChanges;
    
    public void HandleMapCenterChanged() {
        Map.CenterChanged += (sender, args) => {
            if(ignoreNextViewportChanges)
                return;
            //if you came here, the user has changed the location
            //store this information somewhere and skip SetCenter next time
        }
    }
    
    public async void SetCenter(BasicGeoposition center) {
        ignoreNextViewportChanges = true;
        await Map.TrySetViewAsync(new Geopoint(Center));
        ignoreNextViewportChanges = false;
    }
    

    If you have the case that SetCenter might be called twice in parallel (so that the last call of SetCenter is not yet finished, but SetCenter is called again), you might need to use a counter:

    int viewportChangesInProgressCounter;
    
    public void HandleMapCenterChanged() {
        Map.CenterChanged += (sender, args) => {
            if(viewportChangesInProgressCounter > 0)
                return;
            //if you came here, the user has changed the location
            //store this information somewhere and skip SetCenter next time
        }
    }
    
    public async void SetCenter(BasicGeoposition center) {
        viewportChangesInProgressCounter++;
        await Map.TrySetViewAsync(new Geopoint(Center));
        viewportChangesInProgressCounter--;
    }