Select to view content in your preferred language

populating sublayers on a listbox along with the symbols

3068
23
02-09-2011 05:02 AM
SangamLama
Emerging Contributor
Hi all,
I'm following this tutorial to display and populate sublayers out of a dynamic map layer.
http://resources.esri.com/help/9.3/arcgisserver/apis/silverlight/samples/start.htm#SubLayerList

I figured it'd be cool to display the symbols representing those sublayers on the listbox, including the color fills symbols, line symbols etc. I was wondering how I could populate them?

The only time I've ever accessed low level details tied to every sublayer was when I carried out an IdentifyTask on certain coordinates (on the map). Then I used IdentifyResult to access the feature attributes. Would you say carrying out similar IdentifyTask is the only way? But again, the listbox is generated on application load, so I dont know how that's going to be possible..

Thanks for the ideas 🙂
0 Kudos
23 Replies
DominiqueBroux
Esri Frequent Contributor
You might consider to use the legend control to get the symbols representing the sublayers. The legend control provides between 0 and many symbols for a sublayer (depending on the renderer). So the first question is 'which symbol do you want to associate to a sublayer?'

If you decide to associate the first symbol and if you use a legend control in your application, you could initialize the sublayer symbol in the refreshed event:

 
private void MyLegend_Refreshed(object sender, ESRI.ArcGIS.Client.Toolkit.Legend.RefreshedEventArgs e)
{
    if (e.LayerItem.LayerItems != null)
    {
        foreach (var sublayerItem in e.LayerItem.LayerItems)
        {
            if (sublayerItem.LegendItems != null && sublayerItem.LegendItems.Any()) // if there is a legend item
                sublayerItem.ImageSource = sublayerItem.LegendItems.First().ImageSource; // set the image of the sublayer with the image of the first legenditem
        }
    }
}


Then you can display a listbox having its ItemsSource binded to a layer item of the legend ([0] = first map layer in this sample):
<ListBox ItemsSource="{Binding LayerItems[0].LayerItems, ElementName=MyLegend}">
 <ListBox.ItemTemplate>
  <DataTemplate>
    <StackPanel Orientation="Horizontal">
      <Image Source="{Binding ImageSource}"/>
      <TextBlock Text="{Binding Label}" VerticalAlignment="Center" Margin="2,0"/>
    </StackPanel>
  </DataTemplate>
 </ListBox.ItemTemplate>
</ListBox>


Likely there are many other ways to get this result, just my 2cts.
0 Kudos
SangamLama
Emerging Contributor
Dominique,
it seems to be worth a shot. One slight snag though -- I dont have Legend control in ESRI.ArcGIS.Client.Toolkit !?

You might consider to use the legend control to get the symbols representing the sublayers. The legend control provides between 0 and many symbols for a sublayer (depending on the renderer). So the first question is 'which symbol do you want to associate to a sublayer?'

If you decide to associate the first symbol and if you use a legend control in your application, you could initialize the sublayer symbol in the refreshed event:

 
private void MyLegend_Refreshed(object sender, ESRI.ArcGIS.Client.Toolkit.Legend.RefreshedEventArgs e)
{
    if (e.LayerItem.LayerItems != null)
    {
        foreach (var sublayerItem in e.LayerItem.LayerItems)
        {
            if (sublayerItem.LegendItems != null && sublayerItem.LegendItems.Any()) // if there is a legend item
                sublayerItem.ImageSource = sublayerItem.LegendItems.First().ImageSource; // set the image of the sublayer with the image of the first legenditem
        }
    }
}


Then you can display a listbox having its ItemsSource binded to a layer item of the legend ([0] = first map layer in this sample):
<ListBox ItemsSource="{Binding LayerItems[0].LayerItems, ElementName=MyLegend}">
 <ListBox.ItemTemplate>
  <DataTemplate>
    <StackPanel Orientation="Horizontal">
      <Image Source="{Binding ImageSource}"/>
      <TextBlock Text="{Binding Label}" VerticalAlignment="Center" Margin="2,0"/>
    </StackPanel>
  </DataTemplate>
 </ListBox.ItemTemplate>
</ListBox>


Likely there are many other ways to get this result, just my 2cts.
0 Kudos
DominiqueBroux
Esri Frequent Contributor

I dont have Legend control in ESRI.ArcGIS.Client.Toolkit

Legend control is new with ArcGIS SL 2.1. Which version are you working with?
0 Kudos
SangamLama
Emerging Contributor
Legend control is new with ArcGIS SL 2.1. Which version are you working with?


I'm using 2.0
I guess I'll need the new one to try it out..
btw, are these SDKs backward compatible?
0 Kudos
JenniferNery
Esri Regular Contributor
Yes, the API is backwards compatible. If there were any breaking change, they will be noted in this section of our SDK http://help.arcgis.com/en/webapi/silverlight/help/index.html#/What_s_new_in_2_1/016600000025000000/
0 Kudos
SangamLama
Emerging Contributor
I've tested the xaml code on the sublayer list of california map server and it worked fine. But its not working on my sublayer. The symbols wont display. The sublayer's a bit different because it has sub categories as well. Here's how its laid out

SubLayer1
-Sublayer11
-Sublayer12
-Sublayer13
Sublayer2
-Sublayer21
-Sublayer22
-Sublayer23
.....
as opposed to

SubLayer1
Sublayer2
Sublayer3

this is the xaml I'm using:

<esri2:Legend Map="{Binding ElementName=MyMap}"
                       
                         LayerItemsMode="Tree"
                         ShowOnlyVisibleLayers="False"
                         Refreshed="Legend_Refreshed">
                                <esri2:Legend.MapLayerTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal">
                                            <CheckBox Content="{Binding Label}"
                  IsChecked="{Binding IsEnabled, Mode=TwoWay}"
                  IsEnabled="{Binding IsInScaleRange}" >
                                            </CheckBox>
                                            <Image Source="{Binding ImageSource}"/>
                                        </StackPanel>
                                    </DataTemplate>
                                </esri2:Legend.MapLayerTemplate>
                                <esri2:Legend.LayerTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal">
                                        <CheckBox Content="{Binding Label}"
                   IsChecked="{Binding IsEnabled, Mode=TwoWay}"
                IsEnabled="{Binding IsInScaleRange}" >
                                        </CheckBox>                                       
                                        <Image Source="{Binding ImageSource}"/>
                                        </StackPanel>
                                    </DataTemplate>
                                </esri2:Legend.LayerTemplate>                               
                            </esri2:Legend>
                    
Do you think the sublayer having it's own divisions is causing this? Any workaround anyone can think of?






Yes, the API is backwards compatible. If there were any breaking change, they will be noted in this section of our SDK http://help.arcgis.com/en/webapi/silverlight/help/index.html#/What_s_new_in_2_1/016600000025000000/
0 Kudos
DominiqueBroux
Esri Frequent Contributor
You have to set the layerItemsMode to 'Flat' in order not to get any group layers in your listbox.
With this change, your listbox should work because the binding <ListBox ItemsSource="{Binding LayerItems[0].LayerItems, ElementName=MyLegend}"> will return SubLayer11, SubLayer12, SubLayer13, SubLayer21, SubLayer22, ....
0 Kudos
SangamLama
Emerging Contributor
Hi Dominique,
this example didn't really work for me. It didn't generate the listbox. So I decided to initialize the Legend control in the xaml side as in the sample. Doing so worked for the california's map as I have mentioned in the responses above. Here's my complete implementation. I've also attached the screenshots of legend generated for california's map and my map. The former shows the images and colors, while the latter doesn't. What could be missing?

xaml:
<esri2:Legend Map="{Binding ElementName=MyMap}"
                        
                         LayerItemsMode="Flat"
                         ShowOnlyVisibleLayers="False"
                         LayerIDs = "TownMapLayer"
                         BorderThickness="0"
                         Background="White"
                         Refreshed="Legend_Refreshed">
                                <esri2:Legend.MapLayerTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal">
                                            <CheckBox Content="{Binding Label}"
                  IsChecked="{Binding IsEnabled, Mode=TwoWay}"
                  IsEnabled="{Binding IsInScaleRange}" >
                                            </CheckBox>
                                            <Image Source="{Binding ImageSource}"/>
                                        </StackPanel>
                                    </DataTemplate>
                                </esri2:Legend.MapLayerTemplate>
                                <esri2:Legend.LayerTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal">
                                        <CheckBox Content="{Binding Label}"
                   IsChecked="{Binding IsEnabled, Mode=TwoWay}"
                IsEnabled="{Binding IsInScaleRange}" >
                                        </CheckBox>                                       
                                      
                                        </StackPanel>
                                    </DataTemplate>
                                </esri2:Legend.LayerTemplate>                               
                            </esri2:Legend>
      
Legend refreshed eventhandler

void Legend_Refreshed(object sender, Legend.RefreshedEventArgs e)
        {
            if (e.LayerItem.LayerItems != null)
            {
                foreach (var sublayerItem in e.LayerItem.LayerItems)
                {
                    if (sublayerItem.LegendItems != null && sublayerItem.LegendItems.Any()) // if there is a legend item
                        sublayerItem.ImageSource = sublayerItem.LegendItems.First().ImageSource; // set the image of the sublayer with the image of the first legenditem
                }
            }

        }                    


You might consider to use the legend control to get the symbols representing the sublayers. The legend control provides between 0 and many symbols for a sublayer (depending on the renderer). So the first question is 'which symbol do you want to associate to a sublayer?'

If you decide to associate the first symbol and if you use a legend control in your application, you could initialize the sublayer symbol in the refreshed event:

 
private void MyLegend_Refreshed(object sender, ESRI.ArcGIS.Client.Toolkit.Legend.RefreshedEventArgs e)
{
    if (e.LayerItem.LayerItems != null)
    {
        foreach (var sublayerItem in e.LayerItem.LayerItems)
        {
            if (sublayerItem.LegendItems != null && sublayerItem.LegendItems.Any()) // if there is a legend item
                sublayerItem.ImageSource = sublayerItem.LegendItems.First().ImageSource; // set the image of the sublayer with the image of the first legenditem
        }
    }
}


Then you can display a listbox having its ItemsSource binded to a layer item of the legend ([0] = first map layer in this sample):
<ListBox ItemsSource="{Binding LayerItems[0].LayerItems, ElementName=MyLegend}">
 <ListBox.ItemTemplate>
  <DataTemplate>
    <StackPanel Orientation="Horizontal">
      <Image Source="{Binding ImageSource}"/>
      <TextBlock Text="{Binding Label}" VerticalAlignment="Center" Margin="2,0"/>
    </StackPanel>
  </DataTemplate>
 </ListBox.ItemTemplate>
</ListBox>


Likely there are many other ways to get this result, just my 2cts.
0 Kudos
DominiqueBroux
Esri Frequent Contributor
Sorry I forgot to mention that if you have a hierarchy of group layers, you have also to adapt the C# code to take into account this hierarchy.

Here is the code which should work whatever the number of group levels:
void Legend_Refreshed(object sender, ESRI.ArcGIS.Client.Toolkit.Legend.RefreshedEventArgs e)
{
    SetLayerItemImageSource(e.LayerItem);
} 
 
private void SetLayerItemImageSource(LayerItemViewModel layerItem)
{
    if (layerItem.LegendItems != null && layerItem.LegendItems.Any()) // if there is a legend item
        layerItem.ImageSource = layerItem.LegendItems.First().ImageSource; // set the image of the sublayer with the image of the first legenditem
 
    // Call recursively SetLayerItemImageSource
    if (layerItem.LayerItems != null)
    {
        foreach(var sublayerItem in layerItem.LayerItems)
            SetLayerItemImageSource(sublayerItem);
    }
}
Note that instead of using your own listbox and a binding to a legend control, you can also retemplate the legend control to use a listbox.

For example with this template:
<esri:Legend Map="{Binding ElementName=MyMap}" LayerItemsMode="Flat" ShowOnlyVisibleLayers="False" LayerIDs="California" Refreshed="Legend_Refreshed">
<esri:Legend.Template>
 <ControlTemplate TargetType="esri:Legend">
  <ListBox ItemsSource="{TemplateBinding LayerItemsSource}" >
   <ListBox.ItemTemplate>
    <DataTemplate>
     <StackPanel Orientation="Horizontal">
      <CheckBox IsChecked="{Binding IsEnabled, Mode=TwoWay}" IsEnabled="{Binding IsInScaleRange}" VerticalAlignment="Center"/>
      <TextBlock Text="{Binding Label}" VerticalAlignment="Center"/>
      <Image Source="{Binding ImageSource}" Margin="3,0"/>
     </StackPanel>
    </DataTemplate>
   </ListBox.ItemTemplate>
  </ListBox>
 </ControlTemplate>
</esri:Legend.Template>
<esri:Legend>
you get this result:
0 Kudos