/
Legend.cs
2388 lines (2318 loc) · 145 KB
/
Legend.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// (c) Copyright ESRI.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see https://opensource.org/licenses/ms-pl for details.
// All other rights reserved.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using ESRI.ArcGIS.Client.Toolkit.Primitives;
namespace ESRI.ArcGIS.Client.Toolkit
{
/// <summary>
/// The Legend is a utility control that displays the symbology of Layers and their description for map
/// interpretation. By altering its various DataTemplates, the Legend Control functionality can be altered
/// to behave like an interactive Table of Contents (TOC).
/// </summary>
/// <remarks>
/// <para>
/// The Legend Control is a User Interface (UI) control which provides useful narrative and graphic descriptions for
/// understanding what is being viewed in the Map. It displays the
/// <see cref="ESRI.ArcGIS.Client.Layer.ID">Layer.ID</see> name, sub-layer name(s) (via the
/// <see cref="ESRI.ArcGIS.Client.LayerInfo.Name">LayerInfo.Name</see> Property), and any associated graphical
/// symbols with their Label(s) (using the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel.LegendItems">LayerItemViewModel.LegendItems</see>
/// Collection). Additionally,
/// ToolTip information can obtained revealing detailed Layer information (such as:
/// <see cref="ESRI.ArcGIS.Client.Layer.ID">Layer.ID</see>,
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel.SubLayerID">LayerItemViewModel.SubLayerID</see>,
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LegendItemViewModel.Label">LegendItemViewModel.Label</see>,
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LegendItemViewModel.Description">LegendItemViewModel.Description</see>,
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel.MinimumResolution">LayerItemViewModel.MinimumResolution</see>,
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel.MaximumResolution">LayerItemViewModel.MaximumResolution</see>,
/// etc.) when the user hovers the cursor over a Layer/sub-Layer name in the Legend. In its default mode of operation,
/// end-users interact with the Legend Control to expand and collapse the nodes to view as much information as desired
/// about a particular Layer.
/// </para>
/// <para>
/// In most use cases, developers typically only need to set a few core Properties in order to have a Legend that
/// displays useful information about the Layers in the Map. The core properties are:
/// </para>
/// <list type="bullet">
/// <item>
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.Map">Legend.Map</see> - This Property binds the Legend to the Map
/// Control. It is required that this Property be set or else there will be no communication between the Map and the
/// Legend.
/// </item>
/// <item>
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.LayerItemsMode">Legend.LayerItemsMode</see> - This Property
/// controls whether the Legend displays information in an expanded <b>Tree</b> hierarchy for all Legend items or
/// in a <b>Flat</b> structure which shows only the lowest Layer item leaves (The Layer.ID,
/// LayerItemViewModel.SubLayerID, and group-layer labels hierarchy information will not be displayed). The
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.Mode">Legend.Mode</see> Enumeration is used to define the
/// <b>Tree</b> or <b>Flat</b> options. The default Enumeration value for the Legend.LayerItemsMode is
/// <b>Flat</b>.
/// </item>
/// <item>
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.ShowOnlyVisibleLayers">Legend.ShowOnlyVisibleLayers</see> - This
/// Property controls the display of items in the Legend if they are visible in the Map. It accepts a
/// Boolean. The default is <b>True</b>, meaning that only visible layers in the Map will display in the Legend. A Layer
/// may have scale dependency rendering (i.e. the
/// <see cref="ESRI.ArcGIS.Client.Layer.MinimumResolution">Layer.MinimumResolution</see> and/or
/// <see cref="ESRI.ArcGIS.Client.Layer.MaximumResolution">Layer.MaximumResolution</see>) values which
/// set which limits when a Layer can be viewed in the Map at a particular zoom level. A Legend.ShowOnlyVisibleLayers
/// value of <b>False</b> means that even if the Layer is not currently displaying in the Map it will still be listed in
/// the Legend.
/// </item>
/// <item>
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.LayerIDs">Legend.LayerIDs</see> - This Property defines which Layers
/// are participating in the Legend Control. By default this value is set to null/Nothing; which means that all Layers
/// in the Map Control participate in the Legend Control. Developers can limit which Layers are listed in the Legend
/// Control (even though they are still viewable in the Map Control) by specifying a comma-delimmited string using
/// <see cref="ESRI.ArcGIS.Client.Layer.ID">Layer.ID</see> values. <b>Note:</b> Do not use Layer.ID values that
/// contain embedded commas as this will cause problems tokenizing in the Legend.LayerIDs Property.
/// </item>
/// </list>
/// <para>
/// The Legend Control is highly customizable such that developers can override the default behavior of the
/// various DataTemplates to alter the behavior of the control to make it behave like a TOC. A TOC provides the
/// same useful narrative and graphical information as a Legend but adds the extra functionality of allowing users
/// to turn on/off the visibility of individual Layers (and their sub-Layers where applicable). Depending on the
/// developers creativity even other specialized functions can be programmed into the DataTemplates to perform
/// functions like: controlling the opacity of individual Layers (and their sub-Layers where applicable), setting
/// thresholds at which scale a particular Layer is visible, allowing for a specific Layer to be selected and
/// highlighted in the Map, and more. Additional details on what parts of the Legend Control can be customized
/// by the various DataTemplate Properties will be discussed later in this document.
/// </para>
/// <para>
/// The Legend Control can be created at design time in XAML or dynamically at runtime in the code-behind.
/// <ESRISILVERLIGHT>The Legend Control is one of several controls available in the Toolbox in Visual Studio when the ArcGIS API for Silverlight is installed, </ESRISILVERLIGHT>
/// <ESRIWPF>The Legend Control is one of several controls available in the Toolbox in Visual Studio when the ArcGIS Runtime SDK for WPF is installed, </ESRIWPF>
/// <ESRIWINPHONE>There are no controls that can be dragged into the XAML design surface from the Toolbox as part of the ArcGIS Runtime SDK for Windows Phone installation. Developers need to type the correct syntax in the XAML to have the controls appear in the visual designer, </ESRIWINPHONE>
/// see the following screen shot:
/// </para>
/// <ESRISILVERLIGHT><para><img border="0" alt="Example of the Legend Control on the XAML design surface of a Silverlight application." src="C:\ArcGIS\dotNET\API SDK\Main\ArcGISSilverlightSDK\LibraryReference\images\Client.Toolkit.Legend1.png"/></para></ESRISILVERLIGHT>
/// <ESRIWPF><para><img border="0" alt="Example of the Legend Control on the XAML design surface of a WPF application." src="C:\ArcGIS\dotNET\API SDK\Main\ArcGISSilverlightSDK\LibraryReference\images\Client.Toolkit.Legend_VS_WPF.png"/></para></ESRIWPF>
/// <ESRIWINPHONE><para><img border="0" alt="Example of the Legend Control on the XAML design surface of a Windows Phone application." src="C:\ArcGIS\dotNET\API SDK\Main\ArcGISSilverlightSDK\LibraryReference\images\Client.Toolkit.Legend_VS_WinPhone.png"/></para></ESRIWINPHONE>
/// <para>
/// The default appearance of the Legend Control can be modified using numerous inherited Properties from
/// System.Windows.FrameworkElement, System.Windows.UIElement, and System.Windows.Controls. An example of some of
/// these Properties include: .Height, .Width, .BackGround, .BorderBrush, .BorderThickness, .Foreground,
/// .HorizontalAlignment, .VerticalAlignment, .Margin, .Opacity, .Visibility, etc.
/// </para>
/// <para>
/// <b>Note:</b> You cannot change the core behavior of the sub-components (i.e. Image, ToolTipService, StackPanel,
/// TextBlock, DataTemplate, Grid, ContentControl, ContentPresenter,
/// ESRI.ArcGIS.Client.Toolkit.Primitives.TreeViewExtended, etc.) of the Legend Control using standard Properties
/// or Methods alone. To change the core behavior of the sub-components and their appearance of the Control,
/// developers can modify the Control Template in XAML and the associated code-behind file. The easiest way to
/// modify the UI sub-components is using Microsoft Expression Blend. Then developers can delete/modify existing
/// or add new sub-components in Visual Studio to create a truly customized experience. A general approach to
/// customizing a Control Template is discussed in the ESRI blog entitled:
/// <a href="http://blogs.esri.com/Dev/blogs/silverlightwpf/archive/2010/05/20/Use-control-templates-to-customize-the-look-and-feel-of-ArcGIS-controls.aspx" target="_blank">Use control templates to customize the look and feel of ArcGIS controls</a>.
/// A specific code example of modifying the Control Template of the Legend Control to can be found in the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.Map">Legend.Map</see> Property document.
/// </para>
/// <para>
/// Rather than edit the full Control Template of the Legend Control, ESRI has exposed three DataTemplates
/// Properties where developers can target the UI customization to a more limited scope. Each DataTemplate
/// and a description of what part of the Legend Control it has bearing over is listed here:
/// </para>
/// <list type="bullet">
/// <item>
/// <para>
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.MapLayerTemplate">Legend.MapLayerTemplate</see>
/// </para>
/// <para>
/// This DataTemplate controls what is viewed in the Legend for the highest level of information about a
/// particular Layer. It presents each Layer name (via the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LegendItemViewModel.Label">LegendItemViewModel.Label</see> Property)
/// shown in the Map in a ContentControl with a node to expand any sub-Layer information. When a user hovers the
/// cursor over the Legend.MapLayerTemplate section, a ToolTip appears displaying the additional information about the
/// Layer including: Layer.Copyright, LegendItemViewModel.Description, LayerItemViewModel.MinimumResolution,
/// and LayerItemViewModel.MaximumResolution. The MapLayerTemplate value is optional; by default the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.LayerTemplate">Legend.LayerTemplate</see> is used.
/// </para>
/// <para>
/// <b>Note:</b> The <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.LayerItemsMode">Legend.LayerItemsMode</see>
/// Property has great impact on what is displayed in the Legend. For
/// users who want to see the most information available in the Legend, developers should set the LayerItemsMode
/// to <b>Tree</b>. If customizations are made to the MapLayerTemplate and they seem to be overridden at
/// runtime back to a default setting, it is most likely that the LayerItemsMode is set to the default of
/// <b>Flat</b> and it should be set to <b>Tree</b>.
/// </para>
/// <para>
/// The objects that have Binding occur in the MapLayerTemplate are implied to be the Properties of the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel">LayerItemViewModel</see> Class.
/// </para>
/// <para>
/// At the MapLayerTemplate level, one common customization technique would be add a TOC style of interaction.
/// Developers could add a CheckBox to manage the visibility of a Layer (including its sub-Layers) or add a
/// Slider to control the Opacity of the Layer (including its sub-Layers). Code examples of modifying the
/// MapLayerTemplate can be found in the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.MapLayerTemplate">Legend.MapLayerTemplate</see> and
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.LayerTemplate">Legend.LayerTemplate</see> documents.
/// </para>
/// </item>
/// <item>
/// <para>
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.LayerTemplate">Legend.LayerTemplate</see>
/// </para>
/// <para>
/// This DataTemplate controls what is viewed in the Legend for the middle level of information about a
/// particular Layer. It presents each sub-Layer name (via the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LegendItemViewModel.Label">LegendItemViewModel.Label</see>
/// Property) in a ContentControl with a node to expand any LegendItem information or any other nested
/// sub-Layer (aka. group layer) information. When a user hovers the cursor over the Legend.LayerTemplate
/// section, a ToolTip appears displaying the additional information about the sub-layer including: Layer.ID,
/// LegendItemViewModel.Label, LegendItemViewModel.Description, LayerItemViewModel.SubLayerID,
/// LayerItemViewModel.MinimumResolution, and LayerItemViewModel.MaximumResolution. This template is used
/// by default for all Layers except the LegendItems as the lowest level.
/// </para>
/// <para>
/// The objects that have Binding occur in the LayerTemplate are implied to be the Properties of the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel">LayerItemViewModel</see> Class.
/// </para>
/// <para>
/// At the Legend.LayerTemplate level, one common customization technique would be to add TOC style of interaction.
/// Developers could add a CheckBox to manage the visibility of sub-Layer elements. You could add a Slider
/// similar to the Legend.MapLayerTemplate and you will get Sliders appearing for each sub-Layer but the behavior
/// may not be as you would expect. Adjusting a Slider on one sub-Layer would also control the Opacity of
/// the other sub-Layers simultaneously. <b>Note:</b> FeatureLayers do not have the ability to control the
/// visibility or opacity of sub-Layer elements. A code examples of modifying the Legend.LayerTemplate can be
/// found in the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.LayerTemplate">Legend.LayerTemplate</see> document.
/// </para>
/// </item>
/// <item>
/// <para>
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.LegendItemTemplate">Legend.LegendItemTemplate</see>
/// </para>
/// <para>
/// This DataTemplate controls what is viewed in the Legend for the lowest level of information about a
/// particular Layer. It presents each LegendItem via its image
/// (<see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LegendItemViewModel.ImageSource">LegendItemViewModel.ImageSource</see>)
/// and label description
/// (<see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LegendItemViewModel.Label">LegendItemViewModel.Label</see>).
/// No ToolTip information is provided for an individual LegendItem by default.
/// </para>
/// <para>
/// The objects that have Binding occur in the LegendItemTemplate are implied to be the Properties of the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LegendItemViewModel">LegendItemViewModel</see> Class.
/// </para>
/// <para>
/// At the Legend.LegendItemTemplate level, the customization options become more limited due to the map service
/// information being passed back from the ArcGIS Server REST end point. The LegendItemViewModel class
/// contains the most atomic level of information about a particular LegendItem. Turning on/off individual
/// LegendItems or changing their opacity is not possible on any Layer type. It is possible to get creative
/// and perform TOC style user interactions at the Legend.LegendItemtemplate level by discovering the parent objects
/// of individual LegendItems; see the code example in the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.LegendItemTemplate">Legend.LegendItemTemplate</see>
/// for one such customization.
/// </para>
/// </item>
/// </list>
/// <para>
/// It should be noted that it is possible to customize one or more of the Legend Control DataTemplates at the
/// same time. There are established default values for each DataTemplate, so setting one will not necessarily
/// override the others that have been set by default. Significant testing should be done on all of the Layers
/// in the customized application to ensure that the desired behavior has been achieved. Some Layers have
/// different behavior in rendering items in the Legend and should be tested thoroughly.
/// </para>
/// <para>
/// The following screen shot demonstrates which part of the Legend Control corresponds to the three
/// DataTemplates. The Layer (ID = "United States") that is being displayed is an ArcGISDynamicMapServiceLayer
/// with three sub-Layers (ushigh, states, and counties). The information found in the ArcGIS Services Directory
/// about the ArcGISDynamicMapServiceLayer corresponds to what is shown in the Map and Legend Controls.
/// </para>
/// <para>
/// <img border="0" alt="Using the ArcGIS Services Directory to view information about an ArcGISDynamicMapServiceLayer and how that corresponds to what is displayed in the Map and Legend Control. The DataTemplate parts of the Legend Control are specified." src="C:\ArcGIS\dotNET\API SDK\Main\ArcGISSilverlightSDK\LibraryReference\images\Client.Toolkit.Legend.png"/>
/// </para>
/// <para>
/// <b>TIP:</b> It is typically necessary for developers to specify the
/// <see cref="ESRI.ArcGIS.Client.Layer.ID">Layer.ID</see> name for Layers in the Map Control. This can be done
/// in XAML or code-behind. If a Layer.ID value is not specified, then a default Layer.ID value is provided
/// based upon the URL of the ArcGIS Server map service.
/// </para>
/// </remarks>
/// <example>
/// <para>
/// <b>How to use:</b>
/// </para>
/// <para>
/// Click the 'Initialize the Legend' button to wire up the Legend Control with the Map Control. The core Legend
/// Control Properties of LayerItemsMode and ShowOnlyVisibleLayers will also have values set. Note: these same
/// functions could also be performed in XAML (see the XAML for details) rather than in code-behind.
/// </para>
/// <para>
/// The XAML code in this example is used in conjunction with the code-behind (C# or VB.NET) to demonstrate
/// the functionality.
/// </para>
/// <para>
/// The following screen shot corresponds to the code example in this page.
/// </para>
/// <para>
/// <img border="0" alt="Example of binding a Map Control to the Legend Control." src="C:\ArcGIS\dotNET\API SDK\Main\ArcGISSilverlightSDK\LibraryReference\images\Client.Toolkit.Legend2.png"/>
/// </para>
/// <code title="Example XAML1" description="" lang="XAML">
/// <Grid x:Name="LayoutRoot">
///
/// <!-- Add a Map Control. -->
/// <esri:Map Background="White" HorizontalAlignment="Left" Margin="12,188,0,0" Name="Map1"
/// VerticalAlignment="Top" Height="400" Width="400"
/// Extent="-13874971,5811127,-13383551,6302547">
///
/// <!-- Add an ArcGISTiledMapServiceLayer. -->
/// <esri:ArcGISTiledMapServiceLayer ID="Topo"
/// Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>
///
/// <!-- Add a FeatureLayer. -->
/// <esri:FeatureLayer ID="Congressional Districts" Opacity="0.4"
/// Url="http://maps1.arcgisonline.com/ArcGIS/rest/services/USA_Congressional_Districts/MapServer/1"
/// OutFields="*"/>
///
/// <!-- Add an ArcGISDynamicMapServiceLayer. -->
/// <esri:ArcGISDynamicMapServiceLayer ID="Amtrack"
/// Url="http://maps1.arcgisonline.com/ArcGIS/rest/services/FRA_Amtrak_Stations/MapServer"/>
///
/// </esri:Map>
///
/// <!--
/// Add a Legend Control to the application. Only the basic Properties have been set to place the
/// control on the page. The Properties to hook up the Legend with the Map, along with setting the
/// behavior of the control are done in code-behind when the user clicks Button1.
/// -->
/// <esri:Legend Name="Legend1" HorizontalAlignment="Left" VerticalAlignment="Top"
/// Margin="418,188,0,0" Width="350" Height="400" />
///
/// <!--
/// Rather than use code-behind to set up the remainder of the core Properties on the Legend Control,
/// the Properties could have been specified at design-time in XAML. To see this, comment out the above
/// Legend Control (Legend1) and uncomment the below Legend Control (Legend2).
/// -->
/// <!--
/// <esri:Legend Name="Legend2" HorizontalAlignment="Left" VerticalAlignment="Top"
/// Margin="418,188,0,0" Width="350" Height="400"
/// Map="{Binding ElementName=Map1}" LayerItemsMode="Tree" ShowOnlyVisibleLayers="False" />
/// -->
///
/// <!--
/// This Button initializes the remainder of the core Propeties on the Legend Control.
/// -->
/// <Button Content="Initialize the Legend" Height="23" HorizontalAlignment="Left" Margin="12,159,0,0"
/// Name="Button1" VerticalAlignment="Top" Width="756"
/// Click="Button1_Click"/>
///
/// <!-- Provide the instructions on how to use the sample code. -->
/// <TextBlock Height="95" HorizontalAlignment="Left" Name="TextBlock1" VerticalAlignment="Top" Width="756"
/// TextWrapping="Wrap" Margin="12,12,0,0"
/// Text="Click the 'Initialize the Legend' button to wire up the Legend Control with the Map Control.
/// The core Legend Control Properties of LayerItemsMode and ShowOnlyVisibleLayers will also
/// have values set. Note: these same functions could also be performed in XAML (see the XAML
/// for details) rather than in code-behind." />
///
/// </Grid>
/// </code>
/// <code title="Example CS1" description="" lang="CS">
/// private void Button1_Click(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // Bind the Map to the Legend.
/// Legend1.Map = Map1;
///
/// // Show the complete layer/item hierarchy.
/// Legend1.LayerItemsMode = ESRI.ArcGIS.Client.Toolkit.Legend.Mode.Tree;
///
/// // All layers regardless of their visibility wil be shown in the Legend.
/// Legend1.ShowOnlyVisibleLayers = false;
/// }
/// </code>
/// <code title="Example VB1" description="" lang="VB.NET">
/// Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' Bind the Map to the Legend.
/// Legend1.Map = Map1
///
/// ' Show the complete layer/item hierarchy.
/// Legend1.LayerItemsMode = ESRI.ArcGIS.Client.Toolkit.Legend.Mode.Tree
///
/// ' All layers regardless of their visibility wil be shown in the Legend.
/// Legend1.ShowOnlyVisibleLayers = False
///
/// End Sub
/// </code>
/// </example>
public partial class Legend : Control
{
#region Constructor
private bool _isLoaded = false;
private LegendTree _legendTree;
/// <summary>
/// Initializes a new instance of the <see cref="Legend"/> class.
/// </summary>
public Legend()
{
#if SILVERLIGHT
DefaultStyleKey = typeof(Legend);
#endif
_legendTree = new LegendTree();
_legendTree.Refreshed += new EventHandler<RefreshedEventArgs>(OnRefreshed);
_legendTree.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(LegendTree_PropertyChanged);
}
void LegendTree_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "LayerItemsSource")
LayerItemsSource = _legendTree.LayerItemsSource;
else if (e.PropertyName == "LayerItems")
LayerItems = _legendTree.LayerItems;
}
/// <summary>
/// Static initialization for the <see cref="Legend"/> control.
/// </summary>
static Legend()
{
#if !SILVERLIGHT
DefaultStyleKeyProperty.OverrideMetadata(typeof(Legend),
new FrameworkPropertyMetadata(typeof(Legend)));
#endif
}
#endregion
#region Map
/// <summary>
/// Gets or sets the Map that the Legend Control is buddied to.
/// </summary>
/// <remarks>
/// <para>
/// Setting this Property is required to have the Legend Control display information about the Layers in the Map.
/// </para>
/// <para>
/// In the following XAML example, Binding is used to associate a Map Control named 'Map1' to the Legend Control’s
/// Map Property:<br/>
/// <code lang="XAML">
/// <esri:Legend Name="Legend1" Map="{Binding ElementName=Map1}" />
/// </code>
/// </para>
/// </remarks>
/// <example>
/// <para>
/// <b>How to use:</b>
/// </para>
/// <para>
/// A customized Control Template is used to override the default Style of the Legend Control. Click the
/// 'Customized Layer info' button to see various pieces of information about a Layer. The ToolTip for
/// the Layer that is normally displayed in the Legend in the MapLayerTemplate was disabled.
/// </para>
/// <para>
/// The XAML code in this example is used in conjunction with the code-behind (C# or VB.NET) to demonstrate
/// the functionality.
/// </para>
/// <para>
/// The following screen shot corresponds to the code example in this page.
/// </para>
/// <para>
/// <img border="0" alt="Example of a customized Control Template for the Legend Control." src="C:\ArcGIS\dotNET\API SDK\Main\ArcGISSilverlightSDK\LibraryReference\images\Client.Toolkit.Legend.Map.png"/>
/// </para>
/// <para>
/// <b>SPECIAL INSTRUCTIONS: </b>This code example uses two
/// <ESRISILVERLIGHT>Silverlight</ESRISILVERLIGHT>
/// <ESRIWPF>WPF</ESRIWPF>
/// <ESRIWINPHONE>Windows Phone</ESRIWINPHONE>
/// pages. The first page
/// should be named 'TheInfo.xaml' (with corresponding .vb and .cs code-behind files). The second page can use
/// whatever name you choose. Follow these instructions:
/// </para>
/// <para>
/// <b>First: </b>Add the
/// <ESRISILVERLIGHT>Silverlight</ESRISILVERLIGHT>
/// <ESRIWPF>WPF</ESRIWPF>
/// <ESRIWINPHONE>Windows Phone</ESRIWINPHONE>
/// page named 'TheInfo.xaml' into your Visual Studio
/// project. Replace the full contents of the code-behind with the provided example code (depending on your
/// programming language). Note: there is no need to modify the .xaml file.
/// </para>
/// <code title="Example CS1" description="TheInfo.xaml.cs" lang="CS">
/// // This file is the 'TheInfo.xaml.cs' file!
/// using System;
/// public partial class TheInfo : Page
/// {
/// public TheInfo()
/// {
/// InitializeComponent();
/// }
///
/// // Create several Properties (with Dependency Properties) that will be used to hold information about a Layer.
/// // The purpose of this Class is to store information via Binding in XAML to an Object. Then pass that Object
/// // to the code-behind so that you can get access to all of the information.
///
/// public string MyCopyrightText
/// {
/// get { return (string)GetValue(MyCopyrightTextProperty); }
/// set { SetValue(MyCopyrightTextProperty, value); }
/// }
/// public static readonly DependencyProperty MyCopyrightTextProperty = DependencyProperty.Register("MyCopyrightText", typeof(string), typeof(TheInfo), new PropertyMetadata(null));
///
/// public string MyUrl
/// {
/// get { return (string)GetValue(MyUrlProperty); }
/// set { SetValue(MyUrlProperty, value); }
/// }
/// public static readonly DependencyProperty MyUrlProperty = DependencyProperty.Register("MyUrl", typeof(string), typeof(TheInfo), new PropertyMetadata(null));
///
/// public string MyIsVisible
/// {
/// get { return (string)GetValue(MyIsVisibleProperty); }
/// set { SetValue(MyIsVisibleProperty, value); }
/// }
/// public static readonly DependencyProperty MyIsVisibleProperty = DependencyProperty.Register("MyIsVisible", typeof(string), typeof(TheInfo), new PropertyMetadata(null));
///
/// public Collections.ObjectModel.ObservableCollection<ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel> MyLayerItems
/// {
/// get { return GetValue(MyLayerItemsProperty); }
/// set { SetValue(MyLayerItemsProperty, value); }
/// }
/// public static readonly DependencyProperty MyLayerItemsProperty = DependencyProperty.Register("MyLayerItems", typeof(Collections.ObjectModel.ObservableCollection<ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel>), typeof(TheInfo), new PropertyMetadata(null));
/// }
/// </code>
/// <code title="Example VB1" description="TheInfo.xaml.vb" lang="VB.NET">
/// ' This file is the 'TheInfo.xaml.vb' file!
///
/// Partial Public Class TheInfo
/// Inherits Page
///
/// Public Sub New()
/// InitializeComponent()
/// End Sub
///
/// ' Create several Properties (with Dependency Properties) that will be used to hold information about a Layer.
/// ' The purpose of this Class is to store information via Binding in XAML to an Object. Then pass that Object
/// ' to the code-behind so that you can get access to all of the information.
///
/// Public Property MyCopyrightText() As String
/// Get
/// Return CStr(GetValue(MyCopyrightTextProperty))
/// End Get
/// Set(ByVal value As String)
/// SetValue(MyCopyrightTextProperty, value)
/// End Set
/// End Property
/// Public Shared ReadOnly MyCopyrightTextProperty As DependencyProperty = DependencyProperty.Register("MyCopyrightText", GetType(String), GetType(TheInfo), New PropertyMetadata(Nothing))
///
/// Public Property MyUrl() As String
/// Get
/// Return CStr(GetValue(MyUrlProperty))
/// End Get
/// Set(ByVal value As String)
/// SetValue(MyUrlProperty, value)
/// End Set
/// End Property
/// Public Shared ReadOnly MyUrlProperty As DependencyProperty = DependencyProperty.Register("MyUrl", GetType(String), GetType(TheInfo), New PropertyMetadata(Nothing))
///
/// Public Property MyIsVisible() As String
/// Get
/// Return CStr(GetValue(MyIsVisibleProperty))
/// End Get
/// Set(ByVal value As String)
/// SetValue(MyIsVisibleProperty, value)
/// End Set
/// End Property
/// Public Shared ReadOnly MyIsVisibleProperty As DependencyProperty = DependencyProperty.Register("MyIsVisible", GetType(String), GetType(TheInfo), New PropertyMetadata(Nothing))
///
/// Public Property MyLayerItems() As Collections.ObjectModel.ObservableCollection(Of ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel)
/// Get
/// Return GetValue(MyLayerItemsProperty)
/// End Get
/// Set(ByVal value As Collections.ObjectModel.ObservableCollection(Of ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel))
/// SetValue(MyLayerItemsProperty, value)
/// End Set
/// End Property
/// Public Shared ReadOnly MyLayerItemsProperty As DependencyProperty = DependencyProperty.Register("MyLayerItems", GetType(Collections.ObjectModel.ObservableCollection(Of ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel)), GetType(TheInfo), New PropertyMetadata(Nothing))
///
/// End Class
/// </code>
/// <para>
/// <b>Second: </b>Add another
/// <ESRISILVERLIGHT>Silverlight</ESRISILVERLIGHT>
/// <ESRIWPF>WPF</ESRIWPF>
/// <ESRIWINPHONE>Windows Phone</ESRIWINPHONE>
/// corresponding code-behind (.cs or .vb) will be the main driver for the application sample code.
/// </para>
/// <code title="Example XAML2" description="Main driver XAML page." lang="XAML">
/// <Grid x:Name="LayoutRoot">
///
/// <!--
/// Use the Resources section to hold a Style for setting the appearance and behavior of the Legend Control.
/// Don't forget to add following XAML Namespace definitions to the correct location in your code:
/// xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
/// xmlns:esri="http://schemas.esri.com/arcgis/client/2009"
/// xmlns:esriToolkitPrimitives="clr-namespace:ESRI.ArcGIS.Client.Toolkit.Primitives;assembly=ESRI.ArcGIS.Client.Toolkit"
/// xmlns:local="clr-namespace:TestLegend"
///
/// NOTE: You will need to modify your code for the XAML Namespace definition for using local resources of
/// (xmlns:local="clr-namespace:TestLegend") to match the name of your Project file. For example if your project
/// was called 'BillyBob', the XAML Namespace definition would need to be changed to:
/// xmlns:local="clr-namespace:BillyBob"
/// -->
///
/// <Grid.Resources>
///
/// <!--
/// The majority of the XAML that defines the ControlTemplate for the Legend Control was obtained
/// by using Microsoft Blend. See the blog post entitled: 'Use control templates to customize the
/// look and feel of ArcGIS controls' at the following Url for general How-To background:
/// http://blogs.esri.com/Dev/blogs/silverlightwpf/archive/2010/05/20/Use-control-templates-to-customize-the-look-and-feel-of-ArcGIS-controls.aspx
/// -->
/// <Style x:Key="LegendStyle1" TargetType="esri:Legend">
/// <Setter Property="Foreground" Value="Black"/>
/// <Setter Property="Background">
/// <Setter.Value>
///
/// <!--
/// Change the default visual appearance of the Legend Control. Rather going from a White to
/// Gray Background (top to bottom), mix things up by going from a Green to Yellow to Magenta
/// Background.
/// -->
/// <LinearGradientBrush EndPoint=".7,1" StartPoint=".7,0">
/// <GradientStop Color="Green" Offset="0"/>
/// <GradientStop Color="GreenYellow" Offset="0.375"/>
/// <GradientStop Color="Salmon" Offset="0.625"/>
/// <GradientStop Color="Magenta" Offset="1"/>
/// </LinearGradientBrush>
///
/// </Setter.Value>
/// </Setter>
/// <Setter Property="BorderBrush">
/// <Setter.Value>
/// <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
/// <GradientStop Color="#FFA3AEB9" Offset="0"/>
/// <GradientStop Color="#FF8399A9" Offset="0.375"/>
/// <GradientStop Color="#FF718597" Offset="0.375"/>
/// <GradientStop Color="#FF617584" Offset="1"/>
/// </LinearGradientBrush>
/// </Setter.Value>
/// </Setter>
/// <Setter Property="HorizontalContentAlignment" Value="Left"/>
/// <Setter Property="VerticalContentAlignment" Value="Top"/>
/// <Setter Property="Cursor" Value="Arrow"/>
/// <Setter Property="BorderThickness" Value="1"/>
/// <Setter Property="Padding" Value="0"/>
/// <Setter Property="Margin" Value="0"/>
/// <Setter Property="IsTabStop" Value="False"/>
/// <Setter Property="TabNavigation" Value="Once"/>
/// <Setter Property="LayerItemsMode" Value="Flat"/>
/// <Setter Property="LegendItemTemplate">
/// <Setter.Value>
/// <DataTemplate>
/// <StackPanel Margin="0,-1" Orientation="Horizontal">
/// <Image HorizontalAlignment="Center" MaxWidth="55" MaxHeight="55" Margin="0,-1" MinWidth="20" Source="{Binding ImageSource}" Stretch="None" VerticalAlignment="Center"/>
/// <TextBlock Margin="5,0,0,0" Text="{Binding Label}" VerticalAlignment="Center"/>
/// </StackPanel>
/// </DataTemplate>
/// </Setter.Value>
/// </Setter>
/// <Setter Property="LayerTemplate">
/// <Setter.Value>
/// <DataTemplate>
/// <StackPanel Margin="0,-1" Orientation="Horizontal">
/// <ToolTipService.ToolTip>
/// <StackPanel MaxWidth="400">
/// <TextBlock FontWeight="Bold" TextWrapping="Wrap" Text="{Binding Layer.ID}"/>
/// <TextBlock FontWeight="Bold" TextWrapping="Wrap" Text="{Binding Label}"/>
/// <TextBlock TextWrapping="Wrap" Text="{Binding Description}"/>
/// <TextBlock Text="{Binding SubLayerID, StringFormat=SubLayer ID : \{0\}}"/>
/// <TextBlock Text="{Binding MinimumResolution, StringFormat=Minimum Resolution : \{0:F6\}}"/>
/// <TextBlock Text="{Binding MaximumResolution, StringFormat=Maximum Resolution : \{0:F6\}}"/>
/// </StackPanel>
/// </ToolTipService.ToolTip>
/// <TextBlock Text="{Binding Label}" VerticalAlignment="Center"/>
/// </StackPanel>
/// </DataTemplate>
/// </Setter.Value>
/// </Setter>
/// <Setter Property="MapLayerTemplate">
/// <Setter.Value>
/// <DataTemplate>
/// <StackPanel Margin="0,-1">
/// <StackPanel.Resources>
/// <DataTemplate x:Key="BusyIndicatorTemplate">
/// <Grid x:Name="BusyIndicator" Background="Transparent" HorizontalAlignment="Left" Margin="3,0" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center">
/// <Grid.RenderTransform>
/// <RotateTransform/>
/// </Grid.RenderTransform>
/// <Grid.Triggers>
/// <EventTrigger RoutedEvent="Canvas.Loaded">
/// <BeginStoryboard>
/// <Storyboard>
/// <DoubleAnimation Duration="0:0:1" RepeatBehavior="Forever" To="360" Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)" Storyboard.TargetName="BusyIndicator"/>
/// </Storyboard>
/// </BeginStoryboard>
/// </EventTrigger>
/// </Grid.Triggers>
/// <Ellipse Fill="#1E525252" Height="2" Margin="11,2,11,20" Width="2"/>
/// <Ellipse Fill="#3F525252" HorizontalAlignment="Right" Height="3" Margin="0,4,5,0" VerticalAlignment="Top" Width="3"/>
/// <Ellipse Fill="#7F525252" HorizontalAlignment="Right" Height="4" Margin="0,9,1,0" VerticalAlignment="Top" Width="4"/>
/// <Ellipse Fill="#BF525252" HorizontalAlignment="Right" Height="5" Margin="0,0,3,3" VerticalAlignment="Bottom" Width="5"/>
/// <Ellipse Fill="#FF525252" Height="6" Margin="9,0" VerticalAlignment="Bottom" Width="6"/>
/// </Grid>
/// </DataTemplate>
/// </StackPanel.Resources>
///
/// <!--
/// Comment out the default ability to do a ToolTip for the MapLayerTemplate. We will replace with a
/// Button that displays some customized Layer information.
/// -->
/// <!--
/// <ToolTipService.ToolTip>
/// <StackPanel MaxWidth="400">
/// <TextBlock FontWeight="Bold" TextWrapping="Wrap" Text="{Binding Layer.CopyrightText}"/>
/// <TextBlock TextWrapping="Wrap" Text="{Binding Description}"/>
/// <TextBlock Text="{Binding MinimumResolution, StringFormat=Minimum Resolution : \{0:F6\}}"/>
/// <TextBlock Text="{Binding MaximumResolution, StringFormat=Maximum Resolution : \{0:F6\}}"/>
/// </StackPanel>
/// </ToolTipService.ToolTip>
/// -->
///
/// <StackPanel Orientation="Horizontal">
/// <ContentControl ContentTemplate="{StaticResource BusyIndicatorTemplate}" Visibility="{Binding BusyIndicatorVisibility}"/>
/// <TextBlock FontWeight="Bold" Text="{Binding Label}" VerticalAlignment="Center"/>
///
///
/// <!--
/// IMPORTANT INFORMATION:
/// Add a Button that displays customized Layer information next to the Layer.Label. The key to making
/// this logic work is to add a custom .xaml page (called TheInfo.xaml with the code-behind file
/// TheInfo.xaml.vb/TheInfo.xaml.cs) that contains the ability to set/get some Properties (with
/// Dependency Properties). The 'TheInfo' object is then bound to the Button.Tag Property so that we
/// can use the 'TheInfo' object's information in the code-behind. Remember that you need to add the
/// correct XAML Namespace definition at the top of your XAML code in order to use the local
/// 'TheInfo' object.
///
/// The binding that is occuring to our custom 'TheInfo' object follows the same pattern that is
/// used in other parts of this Style. For the MapLayerTemplate is it implied that Binding is
/// occuring to the LayerItemViewModel object.
/// -->
/// <local:TheInfo x:Name="MyTheInfo"
/// MyCopyrightText="{Binding Layer.CopyrightText}"
/// MyUrl="{Binding Layer.Url}"
/// MyIsVisible="{Binding IsVisible}"
/// MyLayerItems="{Binding LayerItems}"/>
///
/// <Button x:Name="TheButton" Content="Customized Layer info" Click="TheButton_Click"
/// Tag="{Binding ElementName=MyTheInfo}"/>
///
/// </StackPanel>
/// </StackPanel>
/// </DataTemplate>
/// </Setter.Value>
/// </Setter>
/// <Setter Property="Template">
/// <Setter.Value>
/// <ControlTemplate TargetType="esri:Legend">
/// <esriToolkitPrimitives:TreeViewExtended BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" ItemsSource="{TemplateBinding LayerItemsSource}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
/// <esriToolkitPrimitives:TreeViewExtended.ItemTemplate>
/// <sdk:HierarchicalDataTemplate ItemsSource="{Binding LayerItemsSource}">
/// <ContentPresenter ContentTemplate="{Binding Template}" Content="{Binding}"/>
/// </sdk:HierarchicalDataTemplate>
/// </esriToolkitPrimitives:TreeViewExtended.ItemTemplate>
/// </esriToolkitPrimitives:TreeViewExtended>
/// </ControlTemplate>
/// </Setter.Value>
/// </Setter>
/// </Style>
/// </Grid.Resources>
///
/// <!-- Add a Map control with a couple of Layers. -->
/// <esri:Map Background="White" HorizontalAlignment="Left" Margin="12,188,0,0" Name="Map1"
/// VerticalAlignment="Top" Height="400" Width="400" >
///
/// <esri:ArcGISTiledMapServiceLayer ID="Street Map"
/// Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
///
/// <esri:ArcGISDynamicMapServiceLayer ID="United States" Opacity="0.6"
/// Url="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer"/>
///
/// </esri:Map>
///
/// <!--
/// Add a Legend Control. Bind the Legend.Map Property to a Map Control. Define the Style of the Legend to use the
/// Control Template that was generated in Blend and modified here in Visual Studio (see above).
/// -->
/// <esri:Legend HorizontalAlignment="Left" Margin="418,188,0,0" Name="Legend1"
/// VerticalAlignment="Top" Width="350" Height="400"
/// Map="{Binding ElementName=Map1}" LayerItemsMode="Tree"
/// Style="{StaticResource LegendStyle1}" />
///
/// <!-- Provide the instructions on how to use the sample code. -->
/// <TextBlock Height="70" HorizontalAlignment="Left" Name="TextBlock1" VerticalAlignment="Top" Width="616"
/// TextWrapping="Wrap" Margin="12,12,0,0"
/// Text="A customized Control Template is used to override the default Style of the Legend Control.
/// Click the 'Customized Layer info' button to see various pieces of information about a Layer.
/// The ToolTip for the Layer that is normally displayed in the Legend in the MapLayerTemplate
/// was disabled." />
///
/// </Grid>
/// </code>
/// <code title="Example CS2" description="Main driver code-behind (.cs) page." lang="CS">
/// private void TheButton_Click(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // This function occurs when the user clicks the Button with the text 'Customized Layer info' next to
/// // each Layer in the Legend. An object based on custom TheInfo Class is passed into this function via
/// // the Button.Tag Property. We extract out information from the TheInfo object to construct an
/// // informational string to display to the user via a MessageBox.
///
/// // Get the Button.Tag information (i.e. a TheInfo Class object).
/// TheInfo myTheInfo = sender.Tag;
///
/// // Construct the informational string (using the StringBuilder Class).
/// Text.StringBuilder myDisplayString = new Text.StringBuilder();
///
/// // Add information into the StringBuilder.
/// myDisplayString.Append("Selected information about the Layer:" + Environment.NewLine);
/// myDisplayString.Append("Copyright: " + myTheInfo.MyCopyrightText + Environment.NewLine);
/// myDisplayString.Append("Url: " + myTheInfo.MyUrl + Environment.NewLine);
/// myDisplayString.Append("IsVisible: " + myTheInfo.MyIsVisible + Environment.NewLine);
///
/// // The TheInfo.MyLayerItems Property is a bit more complex that a simple String. It actually contains
/// // the information from the Layer.LayerItems Property. Use this object to display how many sub-Layers
/// // are associated with this particular Layer.
/// Collections.ObjectModel.ObservableCollection<ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel> myLayerItems = null;
/// myLayerItems = myTheInfo.MyLayerItems;
/// myDisplayString.Append("Number of sub-Layers: " + myLayerItems.Count.ToString());
///
/// // Display the information to the user.
/// MessageBox.Show(myDisplayString.ToString());
/// }
/// </code>
/// <code title="Example VB2" description="Main driver code-behind (.vb) page." lang="VB.NET">
/// Private Sub TheButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' This function occurs when the user clicks the Button with the text 'Customized Layer info' next to
/// ' each Layer in the Legend. An object based on custom TheInfo Class is passed into this function via
/// ' the Button.Tag Property. We extract out information from the TheInfo object to construct an
/// ' informational string to display to the user via a MessageBox.
///
/// ' Get the Button.Tag information (i.e. a TheInfo Class object).
/// Dim myTheInfo As TheInfo = sender.Tag
///
/// ' Construct the informational string (using the StringBuilder Class).
/// Dim myDisplayString As New Text.StringBuilder
///
/// ' Add information into the StringBuilder.
/// myDisplayString.Append("Selected information about the Layer:" + vbCrLf)
/// myDisplayString.Append("Copyright: " + myTheInfo.MyCopyrightText + vbCrLf)
/// myDisplayString.Append("Url: " + myTheInfo.MyUrl + vbCrLf)
/// myDisplayString.Append("IsVisible: " + myTheInfo.MyIsVisible + vbCrLf)
///
/// ' The TheInfo.MyLayerItems Property is a bit more complex that a simple String. It actually contains
/// ' the information from the Layer.LayerItems Property. Use this object to display how many sub-Layers
/// ' are associated with this particular Layer.
/// Dim myLayerItems As Collections.ObjectModel.ObservableCollection(Of ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel)
/// myLayerItems = myTheInfo.MyLayerItems
/// myDisplayString.Append("Number of sub-Layers: " + myLayerItems.Count.ToString)
///
/// ' Display the information to the user.
/// MessageBox.Show(myDisplayString.ToString)
///
/// End Sub
/// </code>
/// </example>
public ESRI.ArcGIS.Client.Map Map
{
get { return GetValue(MapProperty) as Map; }
set { SetValue(MapProperty, value); }
}
/// /// <summary>
/// Identifies the <see cref="Map"/> dependency property.
/// </summary>
public static readonly DependencyProperty MapProperty =
DependencyProperty.Register("Map", typeof(Map), typeof(Legend), new PropertyMetadata(OnMapPropertyChanged));
private static void OnMapPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as Legend).OnMapPropertyChanged(e.OldValue as Map, e.NewValue as Map);
}
private void OnMapPropertyChanged(Map oldMap, Map newMap)
{
if (!_isLoaded)
return; // defer initialization until all parameters are well known
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)
&& (newMap == null || newMap.Layers == null || newMap.Layers.Count == 0))
{
// Keep the basic hierarchy for design
}
else
_legendTree.Map = newMap;
}
#endregion
#region LayerIDs
/// <summary>
/// Gets or sets the layer IDs of the layers participating in the legend.
/// </summary>
/// <remarks>
/// <para>
/// Specified in XAML and in Blend as a comma-delimited string: If a layer name contains a comma, please use , instead of the comma.
/// If null/empty, legend from all layers is generated. Order of the layer ids is respected in generating the legend.
/// </para>
/// <ESRISILVERLIGHT><para><b>KNOWN ISSUE:</b> Specifically in Visual Studio 10 (including SP1), properties that are based on arrays of primitives (ex: int, string, etc.) do not work as expected in XAML for Silverlight. When you try to use a property based on an array of primitives in XAML, a blue squiggly line to appears under the property and the following error will occur within the Visual Studio 2010 IDE:</para></ESRISILVERLIGHT>
/// <ESRISILVERLIGHT><para>Unable to cast object of type 'Microsoft.Expression.DesignModel.DocumentModel.DocumentPrimitiveNode' to type 'Microsoft.Expression.DesignModel.DocumentModel.DocumentCompositeNode'.</para></ESRISILVERLIGHT>
/// <ESRISILVERLIGHT><para>The following is a list of all ArcGIS Silverlight API properties based on an array of primitives for which this issue occurs:</para></ESRISILVERLIGHT>
/// <ESRISILVERLIGHT><list type="bullet"><item><see cref="P:ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer.VisibleLayers">ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer.VisibleLayers</see> Property</item><item><see cref="P:ESRI.ArcGIS.Client.ArcGISImageServiceLayer.BandIds">ESRI.ArcGIS.Client.ArcGISImageServiceLayer.BandIds</see> Property</item><item><see cref="P:ESRI.ArcGIS.Client.Editor.LayerIDs">ESRI.ArcGIS.Client.Editor.LayerIDs</see> Property</item><item><see cref="P:ESRI.ArcGIS.Client.QueryDataSource.OIDFields">ESRI.ArcGIS.Client.QueryDataSource.OIDFields</see> Property</item><item><see cref="P:ESRI.ArcGIS.Client.Toolkit.DataSources.WmsLayer.Layers">ESRI.ArcGIS.Client.Toolkit.DataSources.WmsLayer.Layers</see> Property</item><item><see cref="P:ESRI.ArcGIS.Client.Toolkit.EditorWidget.LayerIDs">ESRI.ArcGIS.Client.Toolkit.EditorWidget.LayerIDs</see> Property</item><item><see cref="P:ESRI.ArcGIS.Client.Toolkit.Legend.LayerIDs">ESRI.ArcGIS.Client.Toolkit.Legend.LayerIDs</see> Property</item><item><see cref="P:ESRI.ArcGIS.Client.Toolkit.TemplatePicker.LayerIDs">ESRI.ArcGIS.Client.Toolkit.TemplatePicker.LayerIDs</see> Property</item></list></ESRISILVERLIGHT>
/// <ESRISILVERLIGHT><para>Although you can run the application, this error locks up the Visual Studio 2010 Design tab for the .xaml page. It is recommended that developers use properties based on an array of primitives only in the code-behind.</para></ESRISILVERLIGHT>
/// <ESRISILVERLIGHT><para>Performing a re-build of the application which causes a refresh of the Design view results in a similar error message (NOTE: This error message and screen shot are for the ArcGISDynamicMapServiceLayer.VisibleLayers property; it will look slightly different for the properties based upon an array of primitives):<br/>InvalidCastException was thrown on "ArcGISDynamicMapServiceLayer": Unable to cast object of type 'Microsoft.Expression.DesignModel.DocumentModel.DocumentPrimitiveNode' to type 'Microsoft.Expression.DesignModel.DocumentModel.DocumentCompositeNode'.<br/>at Microsoft.Expression.DesignModel.InstanceBuilders.ArrayInstanceBuilder.InstantiateTargetType(IInstanceBuilderContext context, ViewNode viewNode)<br/>at Microsoft.Expression.DesignModel.InstanceBuilders.ClrObjectInstanceBuilder.Instantiate(IInstanceBuilderContext context, ViewNode viewNode)<br/>at Microsoft.Expression.DesignModel.Core.ViewNodeManager.Instantiate(ViewNode viewNode)<br/></para></ESRISILVERLIGHT>
/// <ESRISILVERLIGHT><para><img border="0" alt="Visual Studio interger array XAML limitation issue." src="C:\ArcGIS\dotNET\API SDK\Main\ArcGISSilverlightSDK\LibraryReference\images\Client.ArcGISDynamicMapServiceLayer.VisibleLayers3.png"/></para></ESRISILVERLIGHT>
/// <ESRISILVERLIGHT><para><b>This issue of using properties based on an array of primitives (ex: int, string, etc.) in XAML was corrected by Microsoft in Visual Studio version 2012 and higher.</b></para></ESRISILVERLIGHT>
/// </remarks>
/// <value>The layer IDs.</value>
[System.ComponentModel.TypeConverter(typeof(StringToStringArrayConverter))]
public string[] LayerIDs
{
get { return (string[])GetValue(LayerIDsProperty); }
set { SetValue(LayerIDsProperty, value); }
}
/// <summary>
/// Identifies the <see cref="LayerIDs"/> dependency property.
/// </summary>
public static readonly DependencyProperty LayerIDsProperty =
DependencyProperty.Register("LayerIDs", typeof(string[]), typeof(Legend), new PropertyMetadata(OnLayerIDsPropertyChanged));
private static void OnLayerIDsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as Legend).OnLayerIDsPropertyChanged((string[])e.OldValue, (string[])e.NewValue);
}
private void OnLayerIDsPropertyChanged(string[] oldLayerIDs, string[] newLayerIDs)
{
_legendTree.LayerIDs = newLayerIDs;
}
#endregion
#region LayerItemsMode
#region Mode
/// <summary>
/// LayerItems mode enumeration defines the structure of the legend : Flat or Tree.
/// </summary>
public enum Mode
{
/// <summary>
/// Flat structure : LayerItemsSource returns the LayerItems leaves (i.e not the group layers nor the map layers with sub layers) and the LegendItems.
/// <remarks>This is the default value.</remarks>
/// </summary>
Flat,
/// <summary>
/// Tree structure : LayerItemsSource returns a hierarchy of legend items taking care of the map layers and of the group layers.
/// </summary>
Tree
};
#endregion
/// <summary>
/// Gets or sets the mode of display that defines the structure of the Legend Control: <b>Flat</b> or <b>Tree</b>.
/// </summary>
/// <remarks>
/// <para>
/// This Property controls whether the Legend displays information in an expanded <b>Tree</b> hierarchy for all
/// Legend items or in a <b>Flat</b> structure which shows only the lowest LayerItem leaves (The Layer.ID,
/// LayerItemViewModel.SubLayerID, and group-layer labels hierarchy information will not be displayed). The
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.Mode">Legend.Mode</see> Enumeration is used to define the
/// <b>Tree</b> or <b>Flat</b> options. The default Enumeration value for the Legend.LayerItemsMode is <b>Flat</b>.
/// </para>
/// <para>
/// The following is a visual depiction of the two different Legend.LayerItemsMode Enumerations for an
/// ArcGISDynamicMapServiceLayer:
/// </para>
/// <para>
/// <img border="0" alt="Legend.LayerItemsMode comparison of 'Tree' and 'Flat' options." src="C:\ArcGIS\dotNET\API SDK\Main\ArcGISSilverlightSDK\LibraryReference\images\Client.Toolkit.Legend.LayerItemsMode.png"/>
/// </para>
/// <para>
/// Depending on the Legend.LayerItemsMode value, the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.LayerItemsSource">Legend.LayerItemsSource</see> and
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Primitives.LayerItemViewModel.LayerItemsSource">LayerItemViewModel.LayerItemsSource</see>
/// will return either only the Layer items leaves (i.e. <b>Flat</b>) or a complete Layer item hierarchy taking
/// care of the Map Layers and of the group layers (i.e. <b>Tree</b>).
/// </para>
/// <para>
/// <b>Note:</b> The Legend.LayerItemsMode Property has great impact on what is displayed in the Legend. For users
/// who want to see the most information available in the Legend, developers should set the LayerItemsMode to
/// <b>Tree</b>. If customizations are made to the
/// <see cref="ESRI.ArcGIS.Client.Toolkit.Legend.MapLayerTemplate">Legend.MapLayerTemplate</see> and they seem to be
/// overridden at runtime back to a default setting, it is most likely that the LayerItemsMode is set to the default of
/// <b>Flat</b> and it should be set to <b>Tree</b>.
/// </para>
/// </remarks>
/// <example>
/// <para>
/// <b>How to use:</b>
/// </para>
/// <para>
/// Click the two buttons 'LayerItemsMode: Tree' and 'LayerItemsMode: Flat' to see how the Legend has different
/// appearances. The Legend_Refreshed Event is overridden to collapse the individual LegendItems (i.e. the map symbol
/// images) so that differences in the LayerItemsMode settings can more readily be seen.
/// </para>
/// <para>
/// The XAML code in this example is used in conjunction with the code-behind (C# or VB.NET) to demonstrate
/// the functionality.
/// </para>
/// <para>
/// The following screen shot corresponds to the code example in this page.
/// </para>
/// <para>
/// <img border="0" alt="Demonstrating the different Legend.LayerItemsMode settings." src="C:\ArcGIS\dotNET\API SDK\Main\ArcGISSilverlightSDK\LibraryReference\images\Client.Toolkit.Legend.LayerItemsMode1.png"/>
/// </para>
/// <code title="Example XAML1" description="" lang="XAML">
/// <Grid x:Name="LayoutRoot" >
///
/// <!-- Add a Map Control. -->
/// <esri:Map Background="White" HorizontalAlignment="Left" Margin="12,188,0,0" Name="Map1"
/// VerticalAlignment="Top" Height="350" Width="350" >
///
/// <!-- Add an ArcGISDynamicMapServiceLayer. -->
/// <esri:ArcGISDynamicMapServiceLayer
/// Url="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer"/>
///
/// </esri:Map>
///
/// <!--
/// Add a Legend Control to the application. The Legend is bound to Map1. Set the ShowOnlyVisibleLayers=False
/// to display all available sub-Layers and group-Layers from the ArcGISDynamicMapServiceLayer in the Legend
/// even though some scale dependency thresholds have been set in the map service.
/// -->
/// <esri:Legend Name="Legend1" HorizontalAlignment="Left" VerticalAlignment="Top"
/// Margin="368,188,0,0" Width="350" Height="350"
/// Map="{Binding ElementName=Map1}"
/// ShowOnlyVisibleLayers="False"/>
///