Click or drag to resize
Code Example - GraphicsLayer_Labeling

Demonstrates labeling city names where two AttributeLabelClass'es are used (one for smaller cities and one for larger ones).

Code Example
Graphics Layer Labeling

This section contains selected code files from a Visual Studio project that emphasize specific ArcGIS Runtime SDK (Windows Desktop) features. For example: some code examples may accomplish the bulk of the work as a configuration property in the .xaml file and hence only the .xaml file will be shown in detail below. In other code examples, the .xaml is used to define the configuration of graphical elements for the application but the application logic is performed in the code behind, hence you may see both the .xaml and .cs/.vb files shown in detail below.

XAML
<Window x:Class="GraphicsLayer_Labeling.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="600" Width="800" 
    xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013">

    <Grid>

        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Vertical">

                <!-- TextBlock to provide the instructions on how to use the sample code. It will be 
                populated with instructions in the code-behind when the application loads. -->
                <TextBlock Height="58" HorizontalAlignment="Left" Name="TextBlock1" VerticalAlignment="Top" 
                           Width="770" TextWrapping="Wrap"  Margin="10,2,0,0" />

            </StackPanel>
            <StackPanel Orientation="Vertical">

                <!-- Button to perform labeling of cities via a GraphicsLayer via code-behind. -->
                <Button Content="Label Cities" x:Name="Button1" Click="Button1_Click" Width="780" HorizontalAlignment="Left"/>

            </StackPanel>

            <StackPanel Orientation="Horizontal">

                <!-- A MapView Control to display various GIS layers. -->
                <esri:MapView x:Name="MapView1" Width="780" Height="480" VerticalAlignment="Top" Margin="2,2,2,2">
                    <!-- Add a Map. -->
                    <esri:Map x:Name="Map1">

                        <!-- Add a backdrop ArcGISTiledMapServiceLayer. -->
                        <esri:ArcGISTiledMapServiceLayer ID="BaseLayer" ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer"/>

                        <!-- Add a GraphicsLayer to hold the results of the Labeling operation. -->
                        <esri:GraphicsLayer ID="GraphicsLayer_Labeling"/>
                    </esri:Map>

                </esri:MapView>

            </StackPanel>
        </StackPanel>
    </Grid>

</Window>

SPECIAL NOTE: The XAML displayed above comes from a C# project. If you are a VB.NET developer, you will need to modify the text for the x:Class namespace from "GraphicsLayer_Labeling.MainWindow" to be just "MainWindow".

namespace GraphicsLayer_Labeling
{
    public partial class MainWindow : System.Windows.Window
    {
        public MainWindow()
        {
            // This call is required by the designer.
            InitializeComponent();

            // Add any initialization after the InitializeComponent() call.


            // Add the instructions on how to use this example code to the TextBlock.
            TextBlock1.Text = "When the application loads, click the 'Label Cities' button to label cites in Florida. Zoom in/out and pan around " + 
                "Florida to see how the labeling engine adjust the labels for the city names. Two different labeling AttributeLabelClasses are used " + 
                "to differentiate smaller and larger cities.";

            // Create a SpatialReference that matches that of the MapView.
            Esri.ArcGISRuntime.Geometry.SpatialReference mySpatialReference = new Esri.ArcGISRuntime.Geometry.SpatialReference(102100);

            // Create a new Envelope based up the SpatialReference.   
            Esri.ArcGISRuntime.Geometry.Envelope myEnvelope = new Esri.ArcGISRuntime.Geometry.Envelope(-9023741.9, 3038412.8, -8727940.3, 3173434.5, mySpatialReference);

            // Set the initial map's startup extent  zoomed into the east-south-central Florida coast.
            MapView1.Map.InitialViewpoint = new Esri.ArcGISRuntime.Controls.Viewpoint(myEnvelope);
        }

        private async void Button1_Click(object sender, System.Windows.RoutedEventArgs e)
        {

            // Define the Url to an ArcGIS Server MapServer that has FindTask capabilities enabled.
            var myUrl = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer";

            // Create a Uri based upon the Url.
            System.Uri myUri = new System.Uri(myUrl);

            // Create a new FindTask based upon the Uri.  
            Esri.ArcGISRuntime.Tasks.Query.FindTask myFindTask = new Esri.ArcGISRuntime.Tasks.Query.FindTask(myUri);

            // Create a FindParameters object. This will hold the instructions on how to execute the FindTask.
            var myFindParameters = new Esri.ArcGISRuntime.Tasks.Query.FindParameters();

            // Set properties of the FindParameters to define the search.
            myFindParameters.LayerIDs.Add(0); // The Cities sub-layer of the MapServer.
            myFindParameters.SearchFields.Add("st"); // This field holds two character state abbreviations.
            myFindParameters.ReturnGeometry = true; // Get the geometry from the search.
            myFindParameters.SpatialReference = MapView1.SpatialReference; // Ensure the SpatialReferencere for the returned geometry is the same as the MapView.
            myFindParameters.SearchText = "FL"; // Only select cities that are in Florida.
            myFindParameters.Contains = true; // Do an exact match.

            // Asynchronously execute the task; await the result.
            Esri.ArcGISRuntime.Tasks.Query.FindResult myFindResult = await myFindTask.ExecuteAsync(myFindParameters);

            // Get GraphicsLayer for labeling that was defined in XAML.
            var myGraphicsLayer = Map1.Layers["GraphicsLayer_Labeling"] as Esri.ArcGISRuntime.Layers.GraphicsLayer;

            // Get the results of the FindTask.
            System.Collections.Generic.IReadOnlyList<Esri.ArcGISRuntime.Tasks.Query.FindItem> myFindItems = myFindResult.Results;

            // Only proceed with doing labeling if we have at least one FindItem. 
            if (myFindItems.Count > 0)
            {

                // Loop through each FindItem. We will get the geometry for the cities and their population. Depending on the 
                // population size of the city we will define a different SimpleMarkerSymbol and add it to the GraphicsLayer.
                foreach (Esri.ArcGISRuntime.Tasks.Query.FindItem myFindItem in myFindItems)
                {

                    // Get the Feature from the FindItem.
                    Esri.ArcGISRuntime.Data.Feature myFeature = myFindItem.Feature;

                    // Create a MapPoint from the Geometry of the Feature.
                    Esri.ArcGISRuntime.Geometry.MapPoint myMapPoint = (Esri.ArcGISRuntime.Geometry.MapPoint)myFeature.Geometry;

                    // Get the Attributes (i.e. Key/Value pairs of a field and it's attribute text) from the Feature. 
                    System.Collections.Generic.IDictionary<string, object> myFeatureAttributes = myFeature.Attributes;

                    // Get the population for each city in the Cities sub-layer of the MapServer.
                    int myPopulation = System.Convert.ToInt32(myFeatureAttributes["POP2000"]);

                    // Create a new SimpleMarkerSymbol to display next to the attribute labeling.
                    Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol mySimpleMarkerSymbol = new Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol();

                    if (myPopulation < 25000)
                    {

                        // This will define the SimpleMarkerSymbol Properties for a smaller city.
                        mySimpleMarkerSymbol.Size = 8;
                        mySimpleMarkerSymbol.Color = System.Windows.Media.Colors.Red;
                        mySimpleMarkerSymbol.Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.Triangle;

                    }
                    else if (myPopulation >= 25000)
                    {

                        // This will define the SimpleMarkerSymbol Properties for a larger city.
                        mySimpleMarkerSymbol.Size = 16;
                        mySimpleMarkerSymbol.Color = System.Windows.Media.Colors.LightGreen;
                        mySimpleMarkerSymbol.Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.Circle;

                    }

                    // Create a new Graphic and set it's Geometry and Symbol to that just defined for either a smaller or larger city.
                    Esri.ArcGISRuntime.Layers.Graphic myPointGraphic = new Esri.ArcGISRuntime.Layers.Graphic();
                    myPointGraphic.Geometry = myMapPoint;
                    myPointGraphic.Symbol = mySimpleMarkerSymbol;

                    // Add all of the Attributes from the FindTask operation to each Graphic being created for labeling.
                    // NOTE: All Attributes from the FindTask operation come back as Strings even though some may have
                    // defined as numeric. You could have used a QueryTask rather that a FindTask and the Attribute Types
                    // would have been preserved.
                    foreach (System.Collections.Generic.KeyValuePair<string, object> keyValue in myFeatureAttributes)
                    {
                        myPointGraphic.Attributes.Add(keyValue);
                    }

                    // Because the 'POP2000' Attribute comes back as a string, we will add another Attribute to the Graphic that is the 
                    // CInt version of the string which gives us a numeric value. This is useful for labeling later since we will want
                    // to use the AttributeLabelClass.WhereClause Property to differentiate the labeling based on a smaller or larger
                    // city.
                    myPointGraphic.Attributes.Add("POP2000_CInt", myPopulation);

                    // Add the new Graphic to the GraphicsLayer.
                    myGraphicsLayer.Graphics.Add(myPointGraphic);

                }

                // -------------------------------------------------------------------------
                // Set up the Classes and Properties useful for labeling the smaller cities.
                // -------------------------------------------------------------------------

                // Create an AttributeLabelClass. This contains the meat of the instructions for doing labeling. 
                Esri.ArcGISRuntime.Layers.AttributeLabelClass myAttributeLabelClass_SmallerCities = new Esri.ArcGISRuntime.Layers.AttributeLabelClass();

                // This option is more useful for labeling PolyLine networks (i.e. roads, railroads, etc.). We don't mind having duplicate cities if they exist.
                // By default this value is set to .PreserveDuplicates.
                myAttributeLabelClass_SmallerCities.DuplicateLabels = Esri.ArcGISRuntime.Layers.DuplicateLabels.PreserveDuplicates;

                // Allow the labeling to show in the map; so set this Property to True.
                // By default this value is set to True.
                myAttributeLabelClass_SmallerCities.IsVisible = true;

                // Not interested in wrapping the text of the city name on a second line. 
                // NOTE: If this option were set to True, use the other .WordWrapLength Property to determine when to wrap the text on the 2nd line.  
                // By default this value is set to False.
                myAttributeLabelClass_SmallerCities.IsWordWrapEnabled = false;

                // Define the placement of the Attribute text relative to the SimpleMarkerSymbol defined earlier for the smaller and larger cities. 
                // By default this value is set to .PointAboveCenter.
                myAttributeLabelClass_SmallerCities.LabelPlacement = Esri.ArcGISRuntime.Layers.LabelPlacement.PointAboveRight;

                // If multiple labels conflict for placement (i.e. they overlap), this defines how to handle displaying the conflicts.
                // By default this value is set to .FixedPositionOrRemove.
                myAttributeLabelClass_SmallerCities.LabelPosition = Esri.ArcGISRuntime.Layers.LabelPosition.FixedPositionOrRemove;

                // Prioritizes which label appears in one AttributeLabelClass -vs- another AttributeLabelClass. Since this is the labeling for the 
                // smaller cities we will give this AttributeLabelClass the lower priority.
                // By default this value is set to .Medium.
                myAttributeLabelClass_SmallerCities.LabelPriority = Esri.ArcGISRuntime.Layers.LabelPriority.Lowest;

                // Define the MaxScale at which the Attribute labels appear. The closer you zoom in on the map then they appear.
                // By default this value is 0.
                myAttributeLabelClass_SmallerCities.MaxScale = 0;

                // Define the MinScale at which the Attribute labels appear. The father you zoom out on the map then they disappear. 
                // By default this value is 0.
                myAttributeLabelClass_SmallerCities.MinScale = 5000000;

                // Define the text that will appear for the labeling. In this case we want the name of the city to display as the labeling text.
                // So the "[AREANAME]" is a field in the Attributes of the GraphicLayer.
                // This value must be provided or else no labeling will occur.
                myAttributeLabelClass_SmallerCities.TextExpression = "[AREANAME]";

                // NOTE: There are numerous ways to define how text that appears via the labeling engine. It is best to review the REST documentation
                // for your MapServer to know that exact syntax. For this code example review the REST doc:
                // http://sampleserver6.arcgisonline.com/arcgis/sdk/rest/index.html#/Labeling_objects/02ss00000014000000/
                // Here are some other labeling .TextEpressions you could try:
                //myAttributeLabelClass_SmallerCities.TextExpression = "\"" + "City: " + "\"" + "CONCAT [AREANAME]";
                //myAttributeLabelClass_SmallerCities.TextExpression = "[AREANAME] CONCAT " + "\"" + " - Pop:" + "\"" + " CONCAT [POP2000]";

                // Only do labeling on smaller cities; so restrict the data using a where clause on the POP2000_CInt numeric Attribute.
                // By default all records are returned (i.e. 1=1, True=True, etc.) and are only restricted when this value is set.
                myAttributeLabelClass_SmallerCities.WhereClause = "POP2000_CInt < 25000";

                // If we were going wrap text on two lines; define that the 2nd line would begin on any word after the 10th character in the 1st line.
                // NOTE: You would need to set the .IsWordWrapEnabled = True.
                // By default this value is not set (meaning the entire string will be on one line).
                myAttributeLabelClass_SmallerCities.WordWrapLength = 10;

                // Create a new TextSymbol to define the appearance of the text that is displayed.
                Esri.ArcGISRuntime.Symbology.TextSymbol myTextSymbol_SmallerCities = new Esri.ArcGISRuntime.Symbology.TextSymbol();
                myTextSymbol_SmallerCities.Color = System.Windows.Media.Colors.White; // The color of the labeling text.
                myTextSymbol_SmallerCities.BorderLineColor = System.Windows.Media.Colors.Red; // If you want a outline glow surrounding the labeling text.
                myTextSymbol_SmallerCities.BorderLineSize = 5; // How big you want the outline glow around the labeling text.

                // Create a new SymbolFont to define the appearance of the text that is displayed.
                Esri.ArcGISRuntime.Symbology.SymbolFont mySymbolFont_SmallerCities = new Esri.ArcGISRuntime.Symbology.SymbolFont();
                mySymbolFont_SmallerCities.FontFamily = "Courier New"; // Use whatever FontFamily you have on your system. Ex: "Arial" "Verdana" "Times New Roman" "Courier New" "Cooper Black"
                mySymbolFont_SmallerCities.FontSize = 12; // Define the point size of the labeling.
                mySymbolFont_SmallerCities.FontStyle = Esri.ArcGISRuntime.Symbology.SymbolFontStyle.Normal; // Define the FontStyle. Others include: .Italics
                mySymbolFont_SmallerCities.TextDecoration = Esri.ArcGISRuntime.Symbology.SymbolTextDecoration.None; // Supply a TextDecoration if desired. Others include: .LineThrough, .Underline.
                mySymbolFont_SmallerCities.FontWeight = Esri.ArcGISRuntime.Symbology.SymbolFontWeight.Bold; // Supply a SymbolFontWeight if desired. Others include: .Normal.
                myTextSymbol_SmallerCities.Font = mySymbolFont_SmallerCities; // Apply the SymbolFont to the TextSymbol.Font Property.

                // Apply the TextSymbol to the AttributeLabelClass.Symbol Property.
                // This value must be provided or else no labeling will occur.
                myAttributeLabelClass_SmallerCities.Symbol = myTextSymbol_SmallerCities;


                // -------------------------------------------------------------------------
                // Set up the Classes and Properties useful for labeling the larger cities.
                // -------------------------------------------------------------------------

                // Create an AttributeLabelClass. This contains the meat of the instructions for doing labeling. 
                Esri.ArcGISRuntime.Layers.AttributeLabelClass myAttributeLabelClass_LargerCities = new Esri.ArcGISRuntime.Layers.AttributeLabelClass();

                // This option is more useful for labeling PolyLine networks (i.e. roads, railroads, etc.). We don't mind having duplicate cities if they exist.
                // By default this value is set to .PreserveDuplicates.
                myAttributeLabelClass_LargerCities.DuplicateLabels = Esri.ArcGISRuntime.Layers.DuplicateLabels.PreserveDuplicates;

                // Allow the labeling to show in the map; so set this Property to True.
                // By default this value is set to True.
                myAttributeLabelClass_LargerCities.IsVisible = true;

                // Not interested in wrapping the text of the city name on a second line. 
                // NOTE: If this option were set to True, use the other .WordWrapLength Property to determine when to wrap the text on the 2nd line.  
                // By default this value is set to False.
                myAttributeLabelClass_LargerCities.IsWordWrapEnabled = false;

                // Define the placement of the Attribute text relative to the SimpleMarkerSymbol defined earlier for the smaller and larger cities. 
                // By default this value is set to .PointAboveCenter.
                myAttributeLabelClass_LargerCities.LabelPlacement = Esri.ArcGISRuntime.Layers.LabelPlacement.PointAboveRight;

                // If multiple labels conflict for placement (i.e. they overlap), this defines how to handle displaying the conflicts.
                // By default this value is set to .FixedPositionOrRemove.
                myAttributeLabelClass_LargerCities.LabelPosition = Esri.ArcGISRuntime.Layers.LabelPosition.FixedPositionOrRemove;

                // Prioritizes which label appears in one AttributeLabelClass -vs- another AttributeLabelClass. Since this is the labeling for the 
                // larger cities we will give this AttributeLabelClass the lower priority.
                // By default this value is set to .Medium.
                myAttributeLabelClass_LargerCities.LabelPriority = Esri.ArcGISRuntime.Layers.LabelPriority.Highest;

                // Define the MaxScale at which the Attribute labels appear. The closer you zoom in on the map then they appear.
                // By default this value is 0.
                myAttributeLabelClass_LargerCities.MaxScale = 0;

                // Define the MinScale at which the Attribute labels appear. The father you zoom out on the map then they disappear. 
                // By default this value is 0.
                myAttributeLabelClass_LargerCities.MinScale = 5000000;

                // Define the text that will appear for the labeling. In this case we want the name of the city to display as the labeling text.
                // So the "[AREANAME]" is a field in the Attributes of the GraphicLayer.
                // This value must be provided or else no labeling will occur.
                myAttributeLabelClass_LargerCities.TextExpression = "[AREANAME]";

                // NOTE: There are numerous ways to define how text that appears via the labeling engine. It is best to review the REST documentation
                // for your MapServer to know that exact syntax. For this code example review the REST doc:
                // http://sampleserver6.arcgisonline.com/arcgis/sdk/rest/index.html#/Labeling_objects/02ss00000014000000/
                // Here are some other labeling .TextEpressions you could try:
                //myAttributeLabelClass_LargerCities.TextExpression = "\"" + "City: " + "\"" + "CONCAT [AREANAME]";
                //myAttributeLabelClass_LargerCities.TextExpression = "[AREANAME] CONCAT " + "\"" + " - Pop:" + "\"" + " CONCAT [POP2000]";

                // Only do labeling on larger cities; so restrict the data using a where clause on the POP2000_CInt numeric Attribute.
                // By default all records are returned (i.e. 1=1, True=True, etc.) and are only restricted when this value is set.
                myAttributeLabelClass_LargerCities.WhereClause = "[POP2000_CInt] >= 25000 ";

                // If we were going wrap text on two lines; define that the 2nd line would begin on any word after the 10th character in the 1st line.
                // NOTE: You would need to set the .IsWordWrapEnabled = True.
                // By default this value is not set (meaning the entire string will be on one line).
                myAttributeLabelClass_LargerCities.WordWrapLength = 10;

                // Create a new TextSymbol to define the appearance of the text that is displayed.
                Esri.ArcGISRuntime.Symbology.TextSymbol myTextSymbol_LargerCities = new Esri.ArcGISRuntime.Symbology.TextSymbol();
                myTextSymbol_LargerCities.Color = System.Windows.Media.Colors.Black; // The color of the labeling text.
                myTextSymbol_LargerCities.BorderLineColor = System.Windows.Media.Colors.LightGreen; // If you want a outline glow surrounding the labeling text.
                myTextSymbol_LargerCities.BorderLineSize = 5; // How big you want the outline glow around the labeling text.

                // Create a new SymbolFont to define the appearance of the text that is displayed.
                Esri.ArcGISRuntime.Symbology.SymbolFont mySymbolFont_LargerCities = new Esri.ArcGISRuntime.Symbology.SymbolFont();
                mySymbolFont_LargerCities.FontFamily = "Arial"; // Use whatever FontFamily you have on your system. Ex: "Arial" "Verdana" "Times New Roman" "Courier New" "Cooper Black"
                mySymbolFont_LargerCities.FontSize = 24; // Define the point size of the labeling.
                mySymbolFont_LargerCities.FontStyle = Esri.ArcGISRuntime.Symbology.SymbolFontStyle.Normal; // Define the FontStyle. Others include: .Italics
                mySymbolFont_LargerCities.TextDecoration = Esri.ArcGISRuntime.Symbology.SymbolTextDecoration.None; // Supply a TextDecoration if desired. Others include: .LineThrough, .Underline.
                mySymbolFont_LargerCities.FontWeight = Esri.ArcGISRuntime.Symbology.SymbolFontWeight.Bold; // Supply a SymbolFontWeight if desired. Others include: .Normal.
                myTextSymbol_LargerCities.Font = mySymbolFont_LargerCities; // Apply the SymbolFont to the TextSymbol.Font Property.

                // Apply the TextSymbol to the AttributeLabelClass.Symbol Property.
                // This value must be provided or else no labeling will occur.
                myAttributeLabelClass_LargerCities.Symbol = myTextSymbol_LargerCities;

                // -------------------------------------------------------------------------

                // Create a new AttributeLabelClassCollection to hold one or more AttributeLabelClass'es (in this case one for smaller cities and one for larger cities).
                Esri.ArcGISRuntime.Layers.AttributeLabelClassCollection myAttributeLabelClassCollection = new Esri.ArcGISRuntime.Layers.AttributeLabelClassCollection();
                myAttributeLabelClassCollection.Add(myAttributeLabelClass_SmallerCities);
                myAttributeLabelClassCollection.Add(myAttributeLabelClass_LargerCities);

                // Create a new LabelProperties to hold the AttributeLabelClassCollection. Make sure it is enabled (i.e. Visible).
                Esri.ArcGISRuntime.Layers.LabelProperties myLabelProperties = new Esri.ArcGISRuntime.Layers.LabelProperties();
                myLabelProperties.IsEnabled = true;
                myLabelProperties.LabelClasses = myAttributeLabelClassCollection;

                // Apply the LabelProperties to the GraphicsLayer.Labeling Property.
                myGraphicsLayer.Labeling = myLabelProperties;

                // Enable labeling on the GraphicsLayer as well.
                myGraphicsLayer.Labeling.IsEnabled = true;

            }

        }
    }
}