Adding a legend
When looking at a map, it is often helpful to have a legend that provides information about the symbology used. A Legend control is included in the ESRI.ArcGIS.Client.Toolkit assembly for you to use in your ArcGIS Runtime SDK for Windows Phone applications. The Legend control displays information about all or select layers in your map, and honors the visible extent of the layers included. See the following screen shot:
The symbology associated with a GraphicsLayer only displays in the legend if a renderer is applied on the GraphicsLayer.
Using the Legend control
To create a legend for your map, add the Legend control in the XAML, binding it to the map and specifying which layers it should display. The following code shows an example of a simple legend created in XAML:
<esriToolkit:Legend x:Name="Legend" Map="{Binding ElementName=MyMap}"
LayerIDs="Points of Interest, United States" />
The preceding code assumes that your application has the following:
- A map named MyMap
- Two layers with the IDs "Points of Interest" and "United States"
- References to the ESRI.ArcGIS.Client and ESRI.ArcGIS.Client.Toolkit assemblies
- An XML namespace reference, named esriToolkit, to the ESRI.ArcGIS.Client.Toolkit namespace, contained in the assembly of the same name
You can modify the Legend control in XAML using the following properties; default values are listed:
Legend properties | Description |
---|---|
Map | The map the legend is bound to and displays information about. A Legend control must be bound to a map or it will be empty. |
LayerIDs | The layer IDs of the layers participating in the legend. It is specified in XAML and in Blend as a comma-delimited string. The order of the layer IDs in the comma-delimited string is used in generating the order the layers are listed in the legend. Tip: If a layer ID contains a comma, use , in place of the comma. Default: Include all layers in the map. |
LayerItemsMode | Specify the structure of the legend: either Flat or Tree. A Flat legend is a list of all the leaves of the layers; a Tree view maintains hierarchical structure of the layers and group layers. Default: Flat. Caution: In Windows Phone, there is no built in TreeView control. When a LayerItemsMode of Tree is used, the Legend control entries are processed as a tree. However, since the default template doesn't know how to display a tree, only the root-level items of the tree display. To create a true Tree in the Legend control, a custom LayerTemplate needs to be provided that contains instructions for displaying content in a tree structure. This is shown in Creating a tree display. |
ShowOnlyVisibleLayers | A Boolean value to specify if only layers visible in the map should participate in the legend. Default: true. |
Creating a tree display
As previously mentioned, Windows Phone doesn't have a built in TreeView control, so to create a true tree in the Legend control, a control template needs to be provided that contains instructions for displaying content in a tree structure. Since Windows Phone is based on Silverlight 3, one way to do this is to include the TreeView Microsoft provided as part of the Silverlight 3 Toolkit, and to use that to create a template for the Legend control. See the following code:
<esriToolkit:Legend Map="{Binding ElementName=MyMap}" LayerItemsMode="Tree"
ShowOnlyVisibleLayers="False"
LayerIDs="Points of Interest, United States" >
<esriToolkit:Legend.Template>
<ControlTemplate TargetType="esriToolkit:Legend">
<msSL3Toolkit:TreeView
ItemsSource="{TemplateBinding LayerItemsSource}"
Background="{StaticResource PhoneBackgroundBrush}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Foreground="{StaticResource PhoneForegroundBrush}"
ItemContainerStyle="{StaticResource TreeViewItemCustomStyle}">
<msSL3Toolkit:TreeView.ItemTemplate>
<msSL3ToolkitCommon:HierarchicalDataTemplate
ItemsSource="{Binding LayerItemsSource}">
<ContentPresenter Content="{Binding}"
ContentTemplate="{Binding Template}" />
</msSL3ToolkitCommon:HierarchicalDataTemplate>
</msSL3Toolkit:TreeView.ItemTemplate>
</msSL3Toolkit:TreeView>
</ControlTemplate>
</esriToolkit:Legend.Template>
</esriToolkit:Legend>
The preceding code assumes that your application has the following:
- A map named MyMap
- Two layers with the IDs "Points of Interest" and "United States"
- References to the ESRI.ArcGIS.Client and ESRI.ArcGIS.Client.Toolkit assemblies
- An XML namespace reference, named esriToolkit, to the ESRI.ArcGIS.Client.Toolkit namespace, contained in the assembly of the same name
- A reference to the System.Windows.Controls assembly that is a part of the Silverlight 3 Toolkit from Microsoft
- An XML namespace reference, named msSL3Toolkit, to the System.Windows.Controls namespace, contained in the assembly of the same name.
- An XML namespace reference, named msSL3ToolkitCommon, to the System.Windows namespace, in the System.Windows.Controls assembly.
- A custom ItemContainerStyle, named TreeViewItemCustomStyle. The style used in this code is based on the default style provided in the toolkit, but is customized to use the phone's brushes, along with larger ToggleButtons. Without these style changes, the TreeView doesn't display well against both the light and dark themes, and the ToggleButtons are hard to select.
See the following screen shot of the legend created with a TreeView:
Formatting the Legend control display
Using the previous XAML code to add a legend to your application results in a legend that fills the screen. One way to give the legend a better size, along with a nice border (as shown in the previous screen shot), is to wrap it in a Border control as shown in the following example:
<Border x:Name="LegendBorder" Background="#77919191" BorderThickness="1"
CornerRadius="5" HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="20" Padding="5" BorderBrush="Black" >
<esriToolkit:Legend x:Name="Legend" Map="{Binding ElementName=MyMap}"
LayerIDs="Points of Interest, United States"
LayerItemsMode="Tree" >
</esriToolkit:Legend>
</Border>
On a Windows Phone screen, a legend may be too long to fit. By default, only the part that fits onto the screen will be visible. Wrapping the control in a ScrollViewer enables the user to view the entire contents. See the following code:
<Border x:Name="LegendBorder" Background="#77919191" BorderThickness="1" CornerRadius="5"
HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="20" Padding="5" BorderBrush="Black" >
<ScrollViewer>
<esriToolkit:Legend x:Name="Legend" Map="{Binding ElementName=MyMap}"
LayerIDs="Points of Interest, United States" >
</esriToolkit:Legend>
</ScrollViewer>
</Border>
If you have added a Silverlight 3 TreeView control to your Legend, it scrolls automatically and you do not need to add a ScrollViewer.
Visibility of the legend
Since a Windows Phone has limited screen space, the legend should be easy to turn on and off. Using a button on the ApplicationBar is one way to do so. In the XAML, add the ApplicationBar, including a single button to toggle the LegendBorder's visibility. See the following code:
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="List.png" Text="legend"
Click="ApplicationBarIconButton_Click"/>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
if (LegendBorder.Visibility == System.Windows.Visibility.Visible)
LegendBorder.Visibility = System.Windows.Visibility.Collapsed;
else
LegendBorder.Visibility = System.Windows.Visibility.Visible;
}
Understanding the Legend control's components
The Legend control displays information about data that is shown in the map. As a developer, you add layers to your application's map, and the legend displays information about those layers, including any sub-layers within the service layers if there are any, and the symbology used. To understand the Legend control, these can be thought of as a hierarchy. See the following:
- Map layers—Map layers include map service layers, feature layers, and graphics layers. These are the pieces you specify for inclusion in the Map control through the XAML, using the Map.Layers property. This level is not always displayed in your legend: if you are using a LayerItemsMode of Flat, dynamic map services that contain multiple sub-layers will not display, and instead, their sub-layers will be the root-level entries in the legend. In the image at the beginning of this topic, the Points of interest node in the legend is a map layer.
- Sub-layers (optional, and multiple levels supported)—Dynamic map services can contain layers within themselves, and these can be nested. These sub-layers are included in the map when they are part of the map layer that you included. If you are using a LayerItemsMode of Tree, these display as sub-items on your map layer, and can have multiple levels if nested in the service. If you are using a LayerItemsMode of Flat, these display as the root-level items in your Legend, and you won't see an entry for the map layer containing them. In the image at the beginning of this topic, the ushigh, states, and counties nodes in the legend are sub-layers of the United States dynamic map service layer. The United States map layer is not visible as a node in the legend since LayerItemsMode is set to Flat.
- Items on the map—This is the lowest level in the Legend, and each item is a feature that is in the layer or sub-layer. By default, these are shown as the symbol and the name of the feature. In the image at the beginning of this topic, Campground and Alabama are items included in the Points of Interest map layer and the counties sub-layer, respectively.
- Sub-layers (optional, and multiple levels supported)—Dynamic map services can contain layers within themselves, and these can be nested. These sub-layers are included in the map when they are part of the map layer that you included. If you are using a LayerItemsMode of Tree, these display as sub-items on your map layer, and can have multiple levels if nested in the service. If you are using a LayerItemsMode of Flat, these display as the root-level items in your Legend, and you won't see an entry for the map layer containing them. In the image at the beginning of this topic, the ushigh, states, and counties nodes in the legend are sub-layers of the United States dynamic map service layer. The United States map layer is not visible as a node in the legend since LayerItemsMode is set to Flat.
Internally, each of the items in the Legend is a LegendItemViewModel. However, map layers and sub-layers are of type LayerItemViewModel, which is a particular type of LegendItemViewModel, and know whether or not they are a map layer.
Providing a custom LegendItemTemplate, LayerTemplate, or MapLayerTemplate
The legend created in Using the Legend control is basic: it provides a list of the layers and their symbology. If instead you want a legend that is more interactive, or otherwise has a customized look and feel, you need to template the legend. Three templates are supported by the Legend control: LegendItemTemplate, LayerTemplate, and MapLayerTemplate.
The LegendItemTemplate is used at the lowest level in the legend hierarchy, formatting the display of the items on the map. The default template includes an image and a label, providing the symbol and name of a feature in the map.
The LayerTemplate is used for all layer items, including map layers and sub-layers, as defined in the previous section. However, it only applies to map layers if there is no MapLayerTemplate provided. Since there is a default MapLayerTemplate, you must set the MapLayerTemplate to null if you want your LayerTemplate to apply to both map layers and sub-layers. For example, if you wanted to allow users to toggle the visibility of all layers, you could overwrite the default LayerTemplate to provide the visiblity toggle, and set the MapLayerTemplate to null. This is shown in Creating an interactive table of contents. Sub-layers are only present if your Legend includes display of a dynamic map service, so if you have both a MapLayerTemplate and a LayerTemplate, the LayerTemplate will only be used on sub-layers in the dynamic map service.
The MapLayerTemplate is used to customize the map layer items in the Legend, and is an optional template. These templates can be used to interact with the map layers: for example, they can be set up to toggle the map layers on and off, or change the layer opacity. This is shown in detail in the topic Creating an interactive table of contents. In Flat LayerItemsMode, this template won't be applied to dynamic map services since their map layer won't be visible. If you want to use your LayerTemplate for all map layers as well as sublayers, this template must explicitly be set to null: the default is to use the LayerTemplate if there is no MapLayerTemplate, but a default MapLayerTemplate is provided.
Behind the scenes, the Legend contains a list of LegendItemViewModel type, some of which are more specifically of type LayerItemViewModel. If the item is of type LayerItemViewModel, it also knows if it is a map layer or if instead, it is just a sub-layer. When templates are applied, the Legend applies a template to each of the LegendItemViewModels that it contains, and selects the template to apply based on additional information about the legend item: if it is a LayerItemViewModel that is a map layer, and there is a MapLayerTemplate, the MapLayerTemplate is applied. If it is a LayerItemViewModel but not a map layer, or if there is no MapLayerTemplate, the LayerTemplate is applied. If it is a LegendItemViewModel, then the LegendItemTemplate is applied. As a result, the available properties to bind to within the template are inherited from the type to which the template is being applied.