Select to view content in your preferred language

2.1 LegendItems Always Null

1793
10
11-18-2010 11:45 AM
RyanCoodey
Frequent Contributor
- In the Legend.Loaded event, LayerItems is set but inside each of the items, it's LegendItems is always null.

- In the LayerItem.PropertyChanged event, e.PropertyName is never equal to "LegendItems"

- Even if I pause the application after I have viewed some legend items in tree view, the LegendItems are still null (for all LayerItems layers)

Since Raster Catalogs classified renderers do not come through the REST legend, I am trying to load custom images into LegendItems... but since they are always null, I'm not sure when I can do this.

Thanks a lot for any help!
0 Kudos
10 Replies
JenniferNery
Esri Regular Contributor
I think the best event to subscribe to is Map.Layers.LayersInitialized but make sure that you only check this once because the LayerCollection change will trigger this event again.

LegendItems will not be null for the case when the layer comes from a service created by ArcGIS Server 10 SP1 http://help.arcgis.com/en/arcgisserver/10.0/apis/rest/index.html

To load your custom image for a legend item, you can do the following:
  public MainPage()
  {
   InitializeComponent();
   this.MyMap.Layers.LayersInitialized += Layers_LayersInitialized;
  }
  bool allLayersInitialized;
  void Layers_LayersInitialized(object sender, EventArgs args)
  {
   if (!allLayersInitialized)
   {
    foreach (var l in this.MyLegend.LayerItems)
    {
     if (l.LegendItems == null)
     {
      l.LegendItems = new ObservableCollection<LegendItemViewModel>();
      l.LegendItems.Add(new LegendItemViewModel() { ImageSource = new BitmapImage(new Uri("/image/car-blue-32x32.png", UriKind.Relative)), Description = "test" });
     }

    }
    allLayersInitialized = true;
   }   
  }
0 Kudos
RyanCoodey
Frequent Contributor
Thanks Jennifer, this gets me closer but still having some issues...

If I set:
Legend.LayerItems.LegendItems = newLegendItems;
It works but the legend is created at the service level and is drawn there, it needs to be at a sub-layer...

So I try to go one more level deeper at try:
Legend.LayerItems.LayerItems.LegendItems = newLegendItems;
but the second LayerItems collection is null... this should be the first row of actual layers in the service right?

Legend.LayerItems is the Service (aka, MapLayer)
Legend.LayerItems.LayerItems is the first set of Layers
right?

Also, a bit of a side question, I am using ArcGIS Server 10 SP1, but all the Legend.LayerItems are null... does this mean the legend is going out and using ESRI's legend REST service?  All my services were published in 10 before SP1, do I need to publish them again?  I tried publishing one from Desktop 10 SP1 and it still is null in the API...

Thanks again Jennifer!!!
0 Kudos
DominiqueBroux
Esri Frequent Contributor
Legend.LayerItems.LayerItems.LegendItems = newLegendItems;
but the second LayerItems collection is null... this should be the first row of actual layers in the service right?

Right.
Perhaps the items are not yet initialized when you ran your code.
The best is to use the 'Legend.Refreshed' event for adding/removing/modifying any item you want.



Legend.LayerItems is the Service (aka, MapLayer)
Legend.LayerItems.LayerItems is the first set of Layers
right?

Right



Also, a bit of a side question, I am using ArcGIS Server 10 SP1, but all the Legend.LayerItems are null... does this mean the legend is going out and using ESRI's legend REST service? All my services were published in 10 before SP1, do I need to publish them again? I tried publishing one from Desktop 10 SP1 and it still is null in the API...

No, the usage of 10SP1 or of the arcgis.com is transparent. The same legend item tree is created.
More likely you tested before the legend tree was populated. Use the legend.refreshed event for that.
0 Kudos
RyanCoodey
Frequent Contributor
Bingo, that did it... Thanks a lot!!!

Legend.Refreshed is called a bunch of times, so I just check for when
Legend.LayerItems.LayerItems != null
and then set it at that point.

Thanks a again!
0 Kudos
DominiqueBroux
Esri Frequent Contributor
Great!


Legend.Refreshed is called a bunch of times


It's fired each time the legend tree associated to a maplayer changes.

So at initialization, it is called once by map layer when the legend tree is ready to be rendered (and the eventargs e.LayerItem allows to retrieve which maplayer legend is just initialized).
Then it is fired when the legend tree changes, i.e. when some legend items or legend layers are added/removed/changed.
For example when a layer is added/removed , or when a renderer for a feature layer changes.

So instead of testing 'Legend.LayerItems.LayerItems != null', you could test 'if (e.LayerItem.Layer.ID == "MyRasterCatalogID") { ... }' and your code should be executed only once.

But it's OK as well as you did. It's only for info:)
0 Kudos
RyanCoodey
Frequent Contributor
Ah, very cool, great tip... that should make my code a little more efficent.  Thanks Dom!

In the hopes to maybe help someone else out, here is what I did:

I have a wrapped template control around the ESRI legend control and it has its own LegendRefreshed which can be used by its consuming application.  That consuming application can then subsicribe to this event and do as Dom said to get the Service layer and then call this method:

        public void SetCustomLegend(LayerItemViewModel serviceLayerItemViewModel, String layerID, ObservableCollection<LegendItemViewModel> legendItems)
        {
            LayerItemViewModel layerItemViewModel = GetLegendLayer(serviceLayerItemViewModel, layerID);
            if (layerItemViewModel != null)
                layerItemViewModel.LegendItems = legendItems;
        }


GetLegendLayer() is a part recursive, part iterative method to then get a sub-layer of the Map Layer (Service), because "e.LayerItem.Layer.ID" seems to only trigger at the Map Layer level.
        protected LayerItemViewModel GetLegendLayer(LayerItemViewModel parentLayer, String layerID)
        {
            if(parentLayer.LayerItems != null)
            {
                for (Int32 i = 0; i < parentLayer.LayerItems.Count; i++)
                {
                    //If match, return it
                    if (parentLayer.LayerItems.Label == layerID)
                        return parentLayer.LayerItems;

                    //Check sub layers
                    LayerItemViewModel layerItemViewModel = GetLegendLayer(parentLayer.LayerItems, layerID);
                    if (layerItemViewModel != null)
                        return layerItemViewModel;

                    //Continue checking other layers
                }
            }
            return null;
        }


Maybe there is a better way to do this... but it is working for me currently.  Havn't tested it much yet though.

Thanks again!
0 Kudos
AlexanderAnkrah
Deactivated User
slight deviation,

I hope someone can shed some light on this for me.

I have a couple of map services (created using 9.3.1) and I was trying to use the legend widget referencing the 2.1 JS API. This is however not working right. The container to hold the legend displays "Loading Legend..." then after a few seconds says "no legend to display". This might be a daft question but is the legend widget backward compatible? is anyone else experiencing this?

Any help would be very much appreciated.

Cheers
0 Kudos
DominiqueBroux
Esri Frequent Contributor
Hi Don,

Looks like you are working with JavaScript API, not with Silverlight.
You might have more chance to get an answer by posting your question on this forum : http://forums.arcgis.com/forums/15-ArcGIS-API-for-JavaScript
0 Kudos
AlexanderAnkrah
Deactivated User
OK. I have found the course of my woes. But that presents another major problem all together!

just found out the Legend Widget does not support MapService URL with Tokens at the end for Secured Services...

Has anyone got a take on this please.

Cheers.
0 Kudos