Dynamically add layer to map and populating sublayers on a list/check box.

2374
6
06-01-2012 12:09 PM
BlueRace
New Contributor II
Hi All,
This thread subLayers, Listbox and symbology does half of what I'm looking to accomplish.
The other half is I am looking not to have the layers hard coded in the XAML I�??m looking to (1) have users enter the URL like here #AddLayerDynamically   then  (2)the Sublayers (including any hierarchy) would be listed with checkboxs somwhat like here #SubLayerList.

This probably means most of the code will be done in codebehind c# then bound to respective elements in the XAML

I�??m very new to Silverlight. I�??ve been trying to do this for ages but no joy. Any help would be very much appreciated.
6 Replies
JoeHershman
MVP Regular Contributor
I think you want to look at HierachicalDataTemplate.  Here is an example I used for a similar type of purpose that is a Checkbox, TextBox, ItemsSource is a Hierachical collection object (each MapGroup object has a MapGroups property)


            <Windows:HierarchicalDataTemplate x:Key="GroupTemplate" ItemTemplate="{StaticResource LayerTemplate}" ItemsSource="{Binding Path=MapGroups}">
                <StackPanel Orientation="Vertical">
                    <StackPanel Orientation="Horizontal" MouseRightButtonDown="StackPanelMouseRightButtonDown" Margin="10,0,10,0" >
                        <CheckBox IsTabStop="False" IsThreeState="False" IsChecked="{Binding IsVisible, Mode=TwoWay}"
                                      Commands:Click.Command="{Binding TreeNodeClickCommand}" Margin="5,0,5,0"
                                      Commands:Click.CommandParameter="{Binding ElementName=TreeViewControl, Path=SelectedItem}"
                                      Click="CheckBoxClick" VerticalAlignment="Center"/>
                        <TextBlock Text="{Binding Path=Name}" Width="120" Margin="0" VerticalAlignment="Center"/>
                        <Slider Minimum="0" Maximum="1" Width="100" Margin="10,0,10,0" Value="{Binding Opacity, Mode=TwoWay}"
                                Infrastructure:SliderValueChange.Command="{Binding OpacityChangeCommand}"/>

                    </StackPanel>

                </StackPanel>
            </Windows:HierarchicalDataTemplate>


Then my Treeview is setup like below

        <Controls:TreeView  x:Name="TreeViewControl" Background="{StaticResource MainPageBackgroundBrush}" 
                            ItemTemplate="{StaticResource GroupTemplate}" ItemsSource="{Binding MapServiceLayers, Mode=TwoWay}"
                           FlowDirection="{Binding FlowDirection, Mode=TwoWay}"   />



Hope that helps
-Joe
Thanks,
-Joe
0 Kudos
BlueRace
New Contributor II
Many thanks for the reply Joe. However I'm still lost. How is this implemented? When a users enters a URL how would and it's initialized and added to the map in the code behind, how is this then passed to the various elements in the XAML? Really struglling with getting the concept of linking elements from the C# code behind and the XAML elements.

Any further help would be very much appreciated.
0 Kudos
JoeHershman
MVP Regular Contributor
Many thanks for the reply Joe. However I'm still lost. How is this implemented? When a users enters a URL how would and it's initialized and added to the map in the code behind, how is this then passed to the various elements in the XAML? Really struglling with getting the concept of linking elements from the C# code behind and the XAML elements.

Any further help would be very much appreciated.


I think you could really just do what you want using the Legend control in the toolkit just like in the sample http://help.arcgis.com/en/webapi/silverlight/samples/start.htm#LegendWithTemplates.  The legend is bound to the Map so anytime a layer is added or removed from the Map the legend will reflect those changes.

As far as actually adding the layer itself you just create a Layer object and add to the Layers collections so in the code behind


    string url = theUserUrl;
    
    ArcGISDynamicMapServiceLayer layer = new ArcGISDynamicMapServiceLayer {Url = the UserUrl };  // this might be ArcGISTiledMapServiceLayer depending on the service type

    MyMap.Layers.Add(layer);


<esri:Legend Map="{Binding ElementName=MyMap}" 


That part of the xaml is what binds the Map to the Legend, so any changes to the Layers collection will be reflected in the Legend.

Just be sure that in setting up the Legend control you do not give anything for LayerIDs property like they do in the sample.  Setting LayerIDs causes some odd behavior (in my opinion) and when you add the new Layer it won't show up if this is set.

It takes a bit for it to finally click, but data binding really is one of the key concepts to being successful with Silverlight, so it is worth spending some time to really understand how it works


Hope that helps
-Joe
Thanks,
-Joe
0 Kudos
BlueRace
New Contributor II
Many thanks Joe for the tips, code and advice. I really appreciate it. I thought by picking a "project" I would grasp the concepts quicker but this is proving elusive with silverlight for me. Any way will keep at it.

Just so we are on the same page, and for the benefits of other who may or may not be in the same predicament as me this is what I am looking to do

1. User enters a URL to a Map service, (see link above) - Currently this sample works for Tiled services - Looking to eventually extend this so service type doesn't matter.

2. With no map displayed on the map canvas yet, the sub-layers, if any, would be listed - in a folder or tree fashion.

3. User selects a sub-layer, and can at this point add it to or display it on the map canvas. And at this point it can be added to the legend control.
0 Kudos
JoeHershman
MVP Regular Contributor
Many thanks Joe for the tips, code and advice. I really appreciate it. I thought by picking a "project" I would grasp the concepts quicker but this is proving elusive with silverlight for me. Any way will keep at it.

Just so we are on the same page, and for the benefits of other who may or may not be in the same predicament as me this is what I am looking to do

1. User enters a URL to a Map service, (see link above) - Currently this sample works for Tiled services - Looking to eventually extend this so service type doesn't matter.

2. With no map displayed on the map canvas yet, the sub-layers, if any, would be listed - in a folder or tree fashion.

3. User selects a sub-layer, and can at this point add it to or display it on the map canvas. And at this point it can be added to the legend control.


A few things that impact what it seems like you want to do.

  • Only Services can be added to a Map, the closest you could come to what you propose would be to add the service and have only the selected sublayer visible.

  • Only ArcGISDynamicMapServiceLayer object can have visibility of sub layers changed.  Tiled services can be added as ArcGISDynamicMapServiceLayer, but the performance benefits of tiled service would be lost.  That only makes sense if you think about it, at the most basic level a Tiled service is a set of pre-created images served up when requested, so they cannot be changed.

  • You can build the tree as you want but it is a bit convoluted in how it is done.  A map service contains a LayerInfo collection which includes info about all the layers in the map that the service is created from (the object naming is terrible, imo).  The LayerInfo object has a collection of SublayerIds.  You have to go through and figure what is a sublayer of what

The attached does pretty much what it seems you want as far as building the tree, there is too much there to try and just put code snippets.  The TocViewModel contains code that builds a MapServiceLayer objects collection, Each MapServiceLayer represents a service and the layers/sublayers are then in its ObservableCollection<MapGroup>.  I broke it out into two object type a MapGroup an MapServiceLayer, a MapServiceLayer is a MapGroup but defines the actual service.  A MapGroup has its own MapGroup collection which has 0 or more elements.  This works on the layers in an existing map but the principle would be the same.  I bound the ObservableCollection<MapServiceLayer> to a treeview using HierarchicalDataTemplate like in my earlier post.




Hope that helps
-Joe

Thanks,
-Joe
0 Kudos
BlueRace
New Contributor II
Many thanks Joe. I'll give it a bash and let you know how I get on.

Just looking at the code you've provided, it is apparent it does what I want.

It's just my inability to grasp the silverlight concept that is making me unable to do what I want to do...

In this light I shall mark your answer as the right answer.



If I manage to put something that works together I shall post that here as well for the benefit of others.

Many thanks
blueRace
0 Kudos