Change map based on runtime with Silverlight API

2900
3
07-12-2011 07:42 AM
DJONATASTENFEN
New Contributor
Hello gentlemen, my name is Djonatas, I am developing a portal using ESRI Silverlight API, I'm trying to change the BaseMap at runtime, or want to have the option to change the base map of Bing by ESRI or otherwise but in time exeução of the logic I'm using now is to remove the layer and create another layer. Below code snippet that I'm implementing.


C#
        private void esriBtn_Click(object sender, RoutedEventArgs e)
        {
            Map001.Layers.Remove(Map001.Layers["bing_map"]);
            var esriLayer = new ESRI.ArcGIS.Client.ArcGISTiledMapServiceLayer();
            esriLayer.Url = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";
            esriLayer.ID = "esri_layer";
            Map001.Layers.Add(esriLayer);
        }

        private void bingBtn_Click(object sender, RoutedEventArgs e)
        {
            Map001.Layers.Remove(Map001.Layers["esri_layer"]);
            var bingLayer = new ESRI.ArcGIS.Client.Bing.TileLayer();
            bingLayer.Token = "My Bing Key";
            bingLayer.ID = "bing_map";
            Map001.Layers.Add(bingLayer);
        }


XAML:
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Grid.Row="0" HorizontalAlignment="Center">
            <Button Content="ESRI" x:Name="esriBtn" Click="esriBtn_Click" />
            <Button Content="BING" x:Name="bingBtn" Margin="10,0,0,0" Click="bingBtn_Click" />
        </StackPanel>
        <esri:Map Name="Map001" Grid.Row="1"/>
    </Grid>



My problem is:
If I click ESRI first it loads normally but can not switch to BING.

If I click on BING first it loads normally but can not switch to the ESRI.

I saw an example that works perfectly that it is in ArcGIS Viewer for Silverlight when it creates the project have the option of choosing the base map, during this process I can switch between them, I do the same thing but in a normal application.


I hope you can help me solve my problem

Sorry for my poor English

graciously
Djonatas Tenfen
0 Kudos
3 Replies
IgressT
New Contributor II
Because

http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer is in Spatial Reference: 4326

and Bing layer is in Spatial Reference: 102100
0 Kudos
HugoCardenas
New Contributor
First, load the Bing tile layer.  To avoid any VS2010 design crash errors with the Bing key, load it with code-behind at "MainPage()" main method:

private ESRI.ArcGIS.Client.Bing.TileLayer _bingMap = new ESRI.ArcGIS.Client.Bing.TileLayer();

      // "Token" must be added here (code-behind) and not in .XAML.  Visual Studio 2010 crashes.
      this._bingMap.ID = this._bingMapName;
      this._bingMap.Token = BingToken; // your Bing maps key
      this._bingMap.ServerType = ServerType.Production;
      this._bingMap.Visible = true;
      this._bingMap.LayerStyle = TileLayer.LayerType.AerialWithLabels;

      // Insert bing base map at markers, if any, map position (to keep markers on top)
      int index = MyMap.Layers.IndexOf(MyMap.Layers["MyMarkers"]);
      MyMap.Layers.Insert(index, _bingMap);

Add additional(s) radio button(s) to your MainPage.XAML (notice the last one):

<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="5" >
                   <RadioButton x:Name="RoadRadioButton" Tag="Road" Margin="5,0,0,0" Foreground="White" GroupName="Layers" Content="Road" Click="RadioButton_Click"/>

                   <RadioButton x:Name="AerialRadioButton" Tag="Aerial" Margin="5,0,0,0" Foreground="White" GroupName="Layers" Content="Aerial" Click="RadioButton_Click"/>

                   <RadioButton x:Name="AerialWithLabelsRadioButton" Tag="AerialWithLabels" IsChecked="true" Margin="5,0,0,0" Foreground="White" GroupName="Layers" Content="Aerial+Labels" Click="RadioButton_Click"/>

                   <RadioButton x:Name="USTopographic" Tag="USTopographic" Margin="5,0,0,0" Foreground="White" GroupName="Layers" Content="US Topography" Click="RadioButton_Click"/>
                 </StackPanel>

Finally, respond to the click event of the radio buttons (DO NOT remove the Bing map, just hide it.  Do remove the ESRI base map layers from the layers collection):

    private void RadioButton_Click(object sender, RoutedEventArgs e)
    {
      // Retrieve what the user clicked at the radio button.
      string layerTypeTag = (string)((RadioButton)sender).Tag;

      // Retrieve bing map 0-based index in esri map layers collection
      int indexBing = MyMap.Layers.IndexOf(MyMap.Layers[_bingMap.ID]);

      // User requested to draw an esri base map
      if (EsriBaseMaps.ContainsKey(layerTypeTag))
      {
        _esriBaseMap = layerTypeTag;

        if (_bingMap.Visible) _bingMap.Visible = false;  // hide bing map
        if (MyMap.Layers.Contains(MyMap.Layers[layerTypeTag])) return; // user clicked the already clicked esri base map.

        string url = string.Empty;
        EsriBaseMaps.TryGetValue(layerTypeTag, out url);  // retrieve url of esri base map service

        if (!string.IsNullOrWhiteSpace(url))
        {
          ESRI.ArcGIS.Client.ArcGISTiledMapServiceLayer newTiledLayer = new ESRI.ArcGIS.Client.ArcGISTiledMapServiceLayer();

          newTiledLayer.Url = url;
          newTiledLayer.ID = layerTypeTag;

          // Retrieve 0-based index of meters map in the layers collection
          int index = MyMap.Layers.IndexOf(MyMap.Layers[MetersMap]);

          // Insert new esri base map at meters map position (to keep meters on top)
          newTiledLayer.Visible = true;
          MyMap.Layers.Insert(index, newTiledLayer);
        }
      }
      else /* User requested to draw a bing base map */
      {
        // Do not change to what is already set. User clicked the already selected button.
        if (_layerStyle.Equals(layerTypeTag, StringComparison.CurrentCultureIgnoreCase)) return;

        _bingMap.Visible = true;

        // Change layer style to what the user specified with radio button.
        _bingMap.LayerStyle = (TileLayer.LayerType)System.Enum.Parse(typeof(TileLayer.LayerType), layerTypeTag, true);

        if (MyMap.Layers.Contains(MyMap.Layers[_esriBaseMap])) MyMap.Layers.Remove(MyMap.Layers[_esriBaseMap]);
      }
      _layerStyle = layerTypeTag;
    }


Note:
The "EsriBaseMaps" is a Dictionary storing layer name/id and url as value.  I store all the urls of ESRI base maps or others in this collection.  I fill this collection on page load from a web.config file:

    /// <summary>
    /// Gets or sets a paired dictionary of Esri base map layers.  <c>Key</c>=layer id/name, <c>Value</c>=Url
    /// </summary>
    public Dictionary<string, string> EsriBaseMaps
    {
      get { return _esriBaseMaps; }
      set { _esriBaseMaps = value; }
    }

Web.config file entry:

<add key="USTopographic" value="http://services.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer"/>
    <add key="Hydrants" value="http://hydrants layer REST url"/>
    <add key="WaterPipes" value="http://water pipes layer REST url"/>
    <add key="Parcels" value="http://parcels layer REST url"/>
    <add key="Zoning" value="http://zoning layer REST url"/>

Hope this helps!
Hugo Cardenas
hcardenas@muellersystems.com
0 Kudos
JenniferNery
Esri Regular Contributor
When switching base layers of different SpatialReference, you would want to update also the Map.SpatialReference by updating Map.Extent. You can set this with baseLayer.FullExtent or simply set to null before adding the first layer.

You can place other layers in a temporary layer collection and them after the first layer has been replaced.
private void ReplaceBaseLayer(Layer baseLayer)
{
 Envelope oldExtent = MyMap.Extent;
 var layers = new LayerCollection();   
 MyMap.Layers.RemoveAt(0);
 foreach (var l in MyMap.Layers)
  layers.Add(l);
 MyMap.Layers.Clear();
 MyMap.Extent = null;
 MyMap.Layers.Add(baseLayer);
 foreach (var l in layers)
  MyMap.Layers.Add(l);
}
0 Kudos