Select to view content in your preferred language

Map.ZoomTo() not working in Initialized event handler for OpenStreetMapLayer

1077
8
12-14-2010 02:24 PM
MarkusHjärne
Deactivated User
Hi,

when I try to zoom to a given extent in the event handler for the Initailized event of an OpenStreetMapLayer, the XMax of the map's extent becomes Infinity and YMin becomes -Infinity.

In XAML I have a Map control with a single OpenStreetMapLayer:

<esri:Map Background="White"
  HorizontalAlignment="Left"
  Margin="12,12,0,0"
  Name="map1"
  VerticalAlignment="Top"
  Height="308"
  Width="471" >
            <esri:OpenStreetMapLayer ID="OSM"
                Style="Mapnik"
                Initialized="OpenStreetMapLayer_Initialized"/>
</esri:Map>

and in the code behind I have this event handler:

private void OpenStreetMapLayer_Initialized(object sender, EventArgs e)
{
  Envelope extent = new Envelope(1400000, 7420000, 1470000, 7450000)
  {
    SpatialReference = map1.SpatialReference
  };
  map1.ZoomTo(extent);
}

This works for ArcGISDynamicMapServiceLayer and Bing TileLayer. I'm using the Silverlight/WPF API version 2.0.

Does anybody know if this is a correct way of using ZoomTo() or why it doesn't work for OpenStreetMapLayer?
0 Kudos
8 Replies
dotMorten_esri
Esri Notable Contributor
You should not be calling ZoomTo or PanTo until the map has its extent property set. There is no guarantee this is set when a layer initializes. Either wait for the first ExtentChanged event to fire, or set the extent instead of zooming to it (since this is at startup you are really better of just setting the extent). You can set the extent whenever you want, and don't have to wait for any other properties to be set, or layers to be ready.
0 Kudos
MarkusHjärne
Deactivated User
It was not so easy to tell from the documentation exactly when the Extent of the Map is guaranteed to be properly initialized. I actually got the idea with the Initialized event from the SDK documentation of Map.ZoomTo().

I should have mentioned that the code I presented here was just a test for this problem. What I really try to achieve in my app is to keep the extent while changing the map's spatial reference (which can only be done by creating a new Map control and manually projecting the old extent with a Geometry Service, right?), so setting an initial extent does not solve my real problem.

But I will try the ExtentChanged event instead, although it feels a bit scary to change the extent in that handler (risk of recursion), but I guess ZoomTo() is an asynchronous operation. Can I also thrust that the SpatialReference property of the Map is initialized in that event? I'll post by my results here.

Thanks for the help.
0 Kudos
JenniferNery
Esri Regular Contributor
You can also listen to Map.Layers.LayersInitialized event http://help.arcgis.com/en/webapi/silverlight/apiref/ESRI.ArcGIS.Client~ESRI.ArcGIS.Client.LayerColle....

Note however, that this event will fire every time a new layer is added to your map.

public MainPage()
{
             InitializeComponent();
 MyMap.Layers.LayersInitialized += Layers_LayersInitialized;
}
bool performedInitialZoom = false;
private void Layers_LayersInitialized(object sender, EventArgs args)
{
 if (!performedInitialZoom)
 {
  MyMap.ZoomTo(someExtent);
  performedInitialZoom = true;
 }   
}
0 Kudos
MarkusHjärne
Deactivated User
Thanks for the tip with the LayersInitialized event, I didn't know about it before.

My app worked when I used the ExtentChanged event instead...kind of. The problem now is that first the map draws in full extent and then my code changes to the previous extent, this causes a lot of flickering in the map.

I'm thinking of a new approach that will be to first initialize the new base map layer the user wants to change to, project the map's current extent using the spatial reference of the base map layer with a geometry service, create a new map and set its extent before adding the base map layer and the rest of the (projectable) layers to it, and finally replace the old map in the object tree with the new map.

But before I try that it would be good to know if a layer's SpatialReference property is guaranteed to be set when its Initialized event is raised.
0 Kudos
JenniferNery
Esri Regular Contributor
Yes, the layer's SpatialReference is set on Initialize() and will be available when Initialized event is raised. Check for layer.IsInitialized property and layer.SpatialReference != null.

For Map's SpatialReference, kindly look at this help document: http://help.arcgis.com/en/webapi/silverlight/apiref/ESRI.ArcGIS.Client~ESRI.ArcGIS.Client.Map~Spatia...
0 Kudos
MarkusHjärne
Deactivated User
My new approach works really fine, although it was a bit tricky chaining all the asynchronous calls needed to make it work.

Thanks for all your help!
0 Kudos
dotMorten_esri
Esri Notable Contributor
MyMap.ExtentChanged += OnMapExtentChanged;
...
void OnMapExtentChanged(object sender, ExtentEventArgs e)
{
    MyMap.ExtentChanged -= OnMapExtentChanged; //unhook so we only listen the first time.
    //TODO...
}

But again I don't see why you want to do a ZoomTo at startup, since there won't really be anything loaded yet to zoom from. Just simply set the extent on the map, which you can do at any time:
myMap.Extent = new Extent(x1,y1,x2,y2);
If you want to set the extent of a specific layer, just do this when that layer initializes:
myMap.Extent = myLayerThatJustInitialized.FullExtent;
0 Kudos
MarkusHjärne
Deactivated User
In this new approach I don't do a ZoomTo() at startup, I just initialize the empty map with an extent and then add the layers just as you suggested. But in my original approach I had layers in the map in XAML, so then I hadn't much choice but to do a ZoomTo() if I wanted to change the extent.

Although it would have been much easier if it had been possible to just remove all the layers from the map, change the map's extent to an extent with another spatial reference (causing the map spatial reference to change too) and then add the layers back.
0 Kudos