Displaying web map pop-up windows

Pop-up windows can be defined on a web map to show information about something in the map, such as hiking trails, land values, or unemployment rates. The definition of the pop-up window, which tells what fields to display, is saved in the web map. When a web map is read into an application with the ArcGIS API for Silverlight's WebMap.Document class, the pop-up window information is included and can be displayed. The following are the three different types of data that can have pop-up windows associated with them:

  1. Editable layers you create on a map (termed map notes)—These are authored by adding features directly to a web map. See Creating editable layers. When the features are added, a pop-up window can be created to show information about the feature.
  2. Feature layers hosted in ArcGIS feature services—These services are added to the web map and pop-ups can be configured on the layer. See Configuring pop-up windows.
  3. Layers hosted in ArcGIS map services—These services contain one or more layers. Each of those layers can have pop-ups configured the same way they can be configured for a feature layer.

Map notes and feature layers each support a single pop-up definition, and their pop-ups are accessed through either MapTips or the WebMap.Document.PopupTemplateProperty. Map services, on the other hand, are composed of one or more layers, each of which can have a pop-up definition. These are accessed through the WebMap.Document.PopupTemplatesProperty. Both the PopupTemplateProperty and the PopupTemplatesProperty ultimately provide access to a data template to use to display the pop-up. Silverlight data templates specify how to show information and can be associated with any content control, such as a ContentPresenter or an InfoWindow.

This topic includes the following sections:

The code sections in this topic assume that you have already read a web map into your application using WebMap.Document.GetMapAsync. See Adding a web map.

Tip:

The web map with the ID db600ea7e08347ed864617e14854af14 contains both feature and map services with pop-ups and can be used with the event handlers shown in this topic.

Showing pop-ups as MapTips

MapTips are automatically used to display the pop-up windows on any map notes or feature layer. No code is required to achieve this functionality.

However, you might need to customize the MapTip so that it matches your application's look and feel. You can do so by customizing the MapTip as a Border as part of the GetMapCompleted event, called when the map has been retrieved. See the following code:

void webMap_GetMapCompleted(object sender, GetMapCompletedEventArgs e)
{
    if (e.Error == null)
    {
        foreach (Layer layer in e.Map.Layers)
        {
            // Map notes are stored in graphics layers.
            // Feature layers are a type of graphics layer.
            if (layer is GraphicsLayer)
            {
                GraphicsLayer glayer = layer as GraphicsLayer;
                Border border = glayer.MapTip as Border;
                if (border != null)
                {
                    border.Background = new SolidColorBrush(Color.FromArgb(200, 102, 150, 255));
                    border.CornerRadius = new CornerRadius(4);
                }
            }
        }

        // Add in any other steps required once the map is read, such as adding the map  
        // to your application's main grid (named LayoutRoot), shown on the next line.
        LayoutRoot.Children.Add(e.Map);
    }
}

Using the PopupTemplateProperty

You can also display the information contained in pop-up windows associated with both map notes and feature layers by retrieving and displaying the layer's pop-up template. The WebMap.Document.PopupTemplateProperty is a dependency property and contains a data template for the pop-up window which can be displayed in any content presenter. In the following example, an InfoWindow is used to display the pop-up window's information.

Note:

The following code assumes there is an InfoWindow named MyInfoWindow defined in the application, as well as a map named MyMap. The code belongs in the MouseClick event on the map, defined as follows:

private void MyMap_MouseClick(object sender, ESRI.ArcGIS.Client.Map.MouseEventArgs e)
{
    // Code from the following steps is placed here to show the pop-up window.
}
For details on hooking those events to a web map, see Adding a web map.

  1. Close the InfoWindow in case one is already displayed.
    MyInfoWindow.IsOpen = false;
  2. Loop through the layers in the map, finding a graphics layer. Since map notes are stored in a graphics layer, and feature layers are a type of graphics layer, both map notes with pop-ups and feature layers with pop-ups can be displayed following this workflow.
    MyInfoWindow.IsOpen = false;
    
    foreach (Layer layer in MyMap.Layers)
    {
        if (layer is GraphicsLayer)
        {
        }
    }
  3. From that layer, retrieve the PopupTemplateProperty, which is DataTemplate for the layer. Since the PopupTemplateProperty is a dependency property, the value can be retrieved using GetValue. If the layer has a data template, stop processing the layers and the next step shows how the pop-up information is displayed. If the layer has no data template, the PopupTemplateProperty will be null, and the next graphics layer found.
    MyInfoWindow.IsOpen = false;
    
    foreach (Layer layer in MyMap.Layers)
    {
        if (layer is GraphicsLayer)
        {
            GraphicsLayer glayer = layer as GraphicsLayer;
            DataTemplate dt = layer.GetValue(Document.PopupTemplateProperty) as DataTemplate;
    
            if (dt != null)
            {
                break;
            } 
        }
    }
  4. When a layer with a data template is found, find any graphics in that layer at the location clicked.
    MyInfoWindow.IsOpen = false;
    
    foreach (Layer layer in MyMap.Layers)
    {
        if (layer is GraphicsLayer)
        {
            GraphicsLayer glayer = layer as GraphicsLayer;
            DataTemplate dt = layer.GetValue(Document.PopupTemplateProperty) as DataTemplate;
    
            if (dt != null)
            {
                System.Windows.Point screenPnt = MyMap.MapToScreen(e.MapPoint);
                // Account for difference between map and application origin.
                GeneralTransform generalTransform = MyMap.TransformToVisual(Application.Current.RootVisual);
                System.Windows.Point transformScreenPnt = generalTransform.Transform(screenPnt);
                IEnumerable<Graphic> selected = glayer.FindGraphicsInHostCoordinates(transformScreenPnt);
    
                break;
            }
        }
    }
  5. Use the first of the returned features to set up an InfoWindow to display the pop-up window. Set the InfoWindow's anchor to the location on the map that was clicked. Set the InfoWindow's content template to the data template found on the layer, and set the content of the InfoWindow to the attributes of the first feature. Show the InfoWindow, which contains the pop-up information. In the following code, only the first graphic's InfoWindow is shown:
    MyInfoWindow.IsOpen = false;
    
    foreach (Layer layer in MyMap.Layers)
    {
        if (layer is GraphicsLayer)
        {
            GraphicsLayer glayer = layer as GraphicsLayer;
            DataTemplate dt = layer.GetValue(Document.PopupTemplateProperty) as DataTemplate;
    
            if (dt != null)
            {
                System.Windows.Point screenPnt = MyMap.MapToScreen(e.MapPoint);
                // Account for difference between map and application origin.
                GeneralTransform generalTransform = MyMap.TransformToVisual(Application.Current.RootVisual);
                System.Windows.Point transformScreenPnt = generalTransform.Transform(screenPnt);
                IEnumerable<Graphic> selected = glayer.FindGraphicsInHostCoordinates(transformScreenPnt);
    
                foreach (Graphic g in selected)
                {
                    MyInfoWindow.Anchor = e.MapPoint;   
                    MyInfoWindow.ContentTemplate = dt;
                    MyInfoWindow.Content = g.Attributes;
                    MyInfoWindow.IsOpen = true;
    
                    break; // Only show the InfoWindow for the first feature found.
                }
            }
        }
    }
    Caution:

    MyInfoWindow, used in the previous code section, already had the Map property of the InfoWindow set to the map returned from reading the web map. Without the Map property set, the InfoWindow will not display.

    Tip:

    If you do not clear the MapTip property on the layer, both the InfoWindow and the MapTip show the pop-up information. You should clear the MapTip property when the web map is read, in the Document.WebMap.GetMapCompleted event.

Using the PopupTemplatesProperty

A web map containing an ArcGIS map service can have pop-ups configured on the individual layers within the map service. The WebMap.Document.PopupTemplatesProperty is a dependency property and contains a dictionary that maps each layer's ID to a data template for its pop-up window, if a pop-up window was defined on that layer. The dictionary of data templates for the layers can be retrieved, then the individual data templates can be displayed in any content presenter. Since a map service is an image on the client, a query must be done to retrieve information about the features that will have their information displayed in pop-ups.

The following steps build an event so that when clicked, the map displays the pop-up window of a feature at that location.

Note:

The following code assumes there is an InfoWindow named MyInfoWindow defined in the application, as well as a map named MyMap. The code belongs in the MouseClick event on the map, defined as follows:

private void MyMap_MouseClick(object sender, ESRI.ArcGIS.Client.Map.MouseEventArgs e)
{
    // Code from the following steps is placed here to show the pop-up window.
}
For details on hooking those events to a web map, see Adding a web map.

  1. Close the InfoWindow in case one is already displayed, and define some variables to reference the map service layer that you are working with, its data template, and its layer ID.
    MyInfoWindow.IsOpen = false;
    
    Layer popupLayer = null;
    DataTemplate dt = null;
    int layid = 0;
  2. Loop through the layers in the map, finding the first layer with the PopupTemplatesProperty set.
    MyInfoWindow.IsOpen = false;
    
    Layer popupLayer = null;
    DataTemplate dt = null;
    int layid = 0;
    
    foreach (Layer layer in MyMap.Layers)
    {
        if (layer.GetValue(Document.PopupTemplatesProperty) != null)
        {
        }
    }
  3. To later query for the features at the location, store a reference to the service layer that uses the PopupTemplatesProperty field.
    MyInfoWindow.IsOpen = false;
    
    Layer popupLayer = null;
    DataTemplate dt = null;
    int layid = 0;
    
    foreach (Layer layer in MyMap.Layers)
    {
        if (layer.GetValue(Document.PopupTemplatesProperty) != null)
        {
            popupLayer = layer;
        }
    }
  4. From that layer, retrieve the PopupTemplatesProperty, which is an IDictionary of the layer IDs and their pop-up data templates. Since the PopupTemplatesProperty is a dependency property, the value can be retrieved using GetValue. Once the dictionary is retrieved, it can be converted to a list. This provides access to the DataTemplates that were found, along with the corresponding layer ID. For this example, only a single layer's ID and data template are stored so that it can be displayed in the following steps.
    MyInfoWindow.IsOpen = false;
    
    Layer popupLayer = null;
    DataTemplate dt = null;
    int layid = 0;
    
    foreach (Layer layer in MyMap.Layers)
    {
        if (layer.GetValue(Document.PopupTemplatesProperty) != null)
        {
            popupLayer = layer;
            IDictionary<int, DataTemplate> idict = layer.GetValue(Document.PopupTemplatesProperty) as IDictionary<int, DataTemplate>;
            layid = idict.ToList()[0].Key;
            dt = idict.ToList()[0].Value;
            break;
        }
    }
  5. If there is a data template, perform a query on the layer with the data template to get features at the location that was clicked. To query, first determine the type of layer so that the URL can be retrieved. In this example, pop-ups on ArcGIS dynamic and tiled map service layers are displayed.
    MyInfoWindow.IsOpen = false;
    
    Layer popupLayer = null;
    DataTemplate dt = null;
    int layid = 0;
    
    foreach (Layer layer in MyMap.Layers)
    {
        if (layer.GetValue(Document.PopupTemplatesProperty) != null)
        {
            popupLayer = layer;
            IDictionary<int, DataTemplate> idict = layer.GetValue(Document.PopupTemplatesProperty) as IDictionary<int, DataTemplate>;
            layid = idict.ToList()[0].Key;
            dt = idict.ToList()[0].Value;
            break;
        }
    }
    
    if (dt != null)
    {
        QueryTask qt;
        if (popupLayer is ArcGISDynamicMapServiceLayer)
            qt = new QueryTask(string.Format("{0}/{1}", (popupLayer as ArcGISDynamicMapServiceLayer).Url, layid));
        else if (popupLayer is ArcGISTiledMapServiceLayer)
            qt = new QueryTask(string.Format("{0}/{1}", (popupLayer as ArcGISTiledMapServiceLayer).Url, layid));
        else
            return;    
    
        ESRI.ArcGIS.Client.Tasks.Query query = new ESRI.ArcGIS.Client.Tasks.Query();
        query.Geometry = e.MapPoint;
        query.OutSpatialReference = MyMap.SpatialReference;
        query.OutFields.Add("*");
    
        qt.ExecuteAsync(query);
    }
  6. Add an event handler so that the first of the returned features is used to set up an InfoWindow to display the pop-up window. Set the InfoWindow's anchor to the location on the map that was clicked. Set the InfoWindows's content template to the data template found on the layer, and set the content of the InfoWindow to the attributes of the first feature. Show the InfoWindow, which contains the pop-up information.
    MyInfoWindow.IsOpen = false;
    
    Layer popupLayer = null;
    DataTemplate dt = null;
    int layid = 0;
    
    foreach (Layer layer in MyMap.Layers)
    {
        if (layer.GetValue(Document.PopupTemplatesProperty) != null)
        {
            popupLayer = layer;
            IDictionary<int, DataTemplate> idict = layer.GetValue(Document.PopupTemplatesProperty) as IDictionary<int, DataTemplate>;
            layid = idict.ToList()[0].Key;
            dt = idict.ToList()[0].Value;
            break;
        }
    }
    
    if (dt != null)
    {
        QueryTask qt;
        if (popupLayer is ArcGISDynamicMapServiceLayer)
            qt = new QueryTask(string.Format("{0}/{1}", (popupLayer as ArcGISDynamicMapServiceLayer).Url, layid));
        else if (popupLayer is ArcGISTiledMapServiceLayer)
            qt = new QueryTask(string.Format("{0}/{1}", (popupLayer as ArcGISTiledMapServiceLayer).Url, layid));
        else
            return;
    
        qt.ExecuteCompleted += (s, qe) =>
        {
            if (qe.FeatureSet.Features.Count > 0)
            {
                Graphic g = qe.FeatureSet.Features[0];
                MyInfoWindow.Anchor = e.MapPoint;
                MyInfoWindow.ContentTemplate = dt;
                MyInfoWindow.Content = g.Attributes;
                MyInfoWindow.IsOpen = true;
            }
        };
    
        ESRI.ArcGIS.Client.Tasks.Query query = new ESRI.ArcGIS.Client.Tasks.Query();
        query.Geometry = e.MapPoint;
        query.OutSpatialReference = MyMap.SpatialReference;
        query.OutFields.Add("*");
    
        qt.ExecuteAsync(query);
    }
    Caution:

    MyInfoWindow, used in the previous code section, already had the Map property of the InfoWindow set to the map returned from reading the web map. Without the Map property set, the InfoWindow will not display.