Not nice, but works. Also seems pretty smooth. Probably good enough for production.
Define an envelope:
private Envelope _bounds=
new Envelope(
new MapPoint(MAP_BOX_WEST, MAP_BOX_NORTH, SpatialReferences.WebMercator),
new MapPoint(MAP_BOX_EAST, MAP_BOX_SOUTH, SpatialReferences.WebMercator));
Now make a polygon as well, because some GeometryEngine operations don't work with Envelopes for some reason:
private Polygon _boundsPolygon = EnvelopeToPolygon(_envelope);
private static Polygon EnvelopeToPolygon(Envelope envelope)
{
return new Polygon(new MapPoint[]
{
new MapPoint(envelope.XMin, envelope.YMin, SpatialReferences.WebMercator),
new MapPoint(envelope.XMax, envelope.YMin, SpatialReferences.WebMercator),
new MapPoint(envelope.XMax, envelope.YMax, SpatialReferences.WebMercator),
new MapPoint(envelope.XMin, envelope.YMax, SpatialReferences.WebMercator)
});
}
Finally add a ViewpointChanged event:
private void MapView_ViewpointChanged(object sender, EventArgs e)
{
var selected = (MapPoint)MapView.GetCurrentViewpoint(ViewpointType.CenterAndScale).TargetGeometry;
bool legal = GeometryEngine.Contains(_bounds, selected);
if (!legal)
{
SetViewpoint(GeometryEngine.NearestCoordinate(_boundsPolygon, selected).Coordinate);
return;
}
}
This method changes the viewpoint back to a legal state. Also prevents user interaction during the animation.
private async void SetViewpoint(MapPoint point)
{
MapView.InteractionOptions.IsEnabled = false; //Make sure to initialize MapView.InteractionOptions to avoid NullReferenceException
await MapView.SetViewpointCenterAsync(point);
MapView.InteractionOptions.IsEnabled = true;
}