Default to collapsed legend items

2263
4
Jump to solution
04-10-2012 01:56 PM
CorySchinkel
New Contributor II
Hi,

Is there a property I can set so that items in the legend default to collapsed?  I am using the legend in tree mode and consuming a map service that has 30 layers in it.  When the layer loads the tree node expands and I can't find a way to prevent this (short of using control templates). 

Thanks,
Cory
0 Kudos
1 Solution

Accepted Solutions
CorySchinkel
New Contributor II
A colleague and I came up with a solution to this problem. I wanted to use EventTriggers to handle the Legend Refresh event in my ViewModel, the problem is that EventTriggers do not support passing EventArgs. That is another topic all together, why event args are not passed with the EventTrigger. Anyway, my colleague extended the EventTrigger so that it supports passing the event args and it works great.

I will attempt to explain how it all comes together. In the view, a trigger is added to the legend control:
<esri:Legend Map="{Binding ElementName=MyMap}"[INDENT]LayerItemsMode="Tree"> <i:Interaction.Triggers>[/INDENT] [INDENT=2]<i:EventTrigger EventName="Refreshed" >[/INDENT] [INDENT=3]<Commands:InvokeCommandActionWithArgs Command="{Binding LegendRefreshedCommand}" />[/INDENT] [INDENT=2]</i:EventTrigger>[/INDENT] [INDENT]</i:Interaction.Triggers>[/INDENT] </esri:Legend>


The key thing to notice here is Commands:InvokeCommandActionWithArgs. This is an extended version of TriggerAction and looks like:
public class InvokeCommandActionWithArgs : TriggerAction<DependencyObject>     {         public static DependencyProperty CommandProperty =         DependencyProperty.Register("Command", typeof(ICommand),                                     typeof(InvokeCommandActionWithArgs));          public ICommand Command         {             get { return GetValue(CommandProperty) as ICommand; }             set { SetValue(CommandProperty, value); }         }                   protected override void Invoke(object parameter)         {             if (Command == null) return;             Command.Execute(parameter);         }     }


Also notice in the view that the command binding for the Triggeraction is Command="{Binding LegendRefreshedCommand}" . LegendRefreshedCommand is defined in our ViewModel which looks something like:

public class MainWindowViewModel    {          public ICommand LegendRefreshedCommand { get; private set; }          public MainWindowViewModel()         {             LegendRefreshedCommand = new RelayCommand<Legend.RefreshedEventArgs>(OnLegendRefresh, null);         }                  private void OnLegendRefresh(Legend.RefreshedEventArgs refreshedEventArgs)         {             refreshedEventArgs.LayerItem.IsExpanded = false;         }     }


When the Refreshed event on the legend is bound to the LegendRefreshedCommand on the viewmodel via the extended TriggerAction the OnLegendRefresh method will handle the event. The RefreshedEventArgs are passed in and the LayerItem can now be accessed and the IsExpanded property set to false. This is the piece that is missing when using the plain EventTrigger, because it does not pass the event args.

Hopefully that all makes sense and is easy to follow. I have attached a very simple reference project that might make it more clear.

View solution in original post

0 Kudos
4 Replies
MichaelBranscomb
Esri Frequent Contributor
Hi,

One approach is to follow this example in the SilverLight forum: http://forums.arcgis.com/threads/43928-How-to-collapse-the-map-service-node-in-Legend-by-default

Cheers

Mike
0 Kudos
CorySchinkel
New Contributor II
Mike,

Thanks for your response.  I considered handling the legend refreshed event, however I am using MVVM and that approach does not work well with the pattern.  I may have a way to get around the MVVM issue, but it's not ideal.  Do you have any suggestions on how to handle the event while maintaining strict adherence to MVVM (no code-behind)?

Thanks,
Cory
0 Kudos
BKuiper
Occasional Contributor III
Mike,

Thanks for your response.  I considered handling the legend refreshed event, however I am using MVVM and that approach does not work well with the pattern.  I may have a way to get around the MVVM issue, but it's not ideal.  Do you have any suggestions on how to handle the event while maintaining strict adherence to MVVM (no code-behind)?

Thanks,
Cory


I guess you would be able to solve this by implementing a WPF behavior using attached properties.
0 Kudos
CorySchinkel
New Contributor II
A colleague and I came up with a solution to this problem. I wanted to use EventTriggers to handle the Legend Refresh event in my ViewModel, the problem is that EventTriggers do not support passing EventArgs. That is another topic all together, why event args are not passed with the EventTrigger. Anyway, my colleague extended the EventTrigger so that it supports passing the event args and it works great.

I will attempt to explain how it all comes together. In the view, a trigger is added to the legend control:
<esri:Legend Map="{Binding ElementName=MyMap}"[INDENT]LayerItemsMode="Tree"> <i:Interaction.Triggers>[/INDENT] [INDENT=2]<i:EventTrigger EventName="Refreshed" >[/INDENT] [INDENT=3]<Commands:InvokeCommandActionWithArgs Command="{Binding LegendRefreshedCommand}" />[/INDENT] [INDENT=2]</i:EventTrigger>[/INDENT] [INDENT]</i:Interaction.Triggers>[/INDENT] </esri:Legend>


The key thing to notice here is Commands:InvokeCommandActionWithArgs. This is an extended version of TriggerAction and looks like:
public class InvokeCommandActionWithArgs : TriggerAction<DependencyObject>     {         public static DependencyProperty CommandProperty =         DependencyProperty.Register("Command", typeof(ICommand),                                     typeof(InvokeCommandActionWithArgs));          public ICommand Command         {             get { return GetValue(CommandProperty) as ICommand; }             set { SetValue(CommandProperty, value); }         }                   protected override void Invoke(object parameter)         {             if (Command == null) return;             Command.Execute(parameter);         }     }


Also notice in the view that the command binding for the Triggeraction is Command="{Binding LegendRefreshedCommand}" . LegendRefreshedCommand is defined in our ViewModel which looks something like:

public class MainWindowViewModel    {          public ICommand LegendRefreshedCommand { get; private set; }          public MainWindowViewModel()         {             LegendRefreshedCommand = new RelayCommand<Legend.RefreshedEventArgs>(OnLegendRefresh, null);         }                  private void OnLegendRefresh(Legend.RefreshedEventArgs refreshedEventArgs)         {             refreshedEventArgs.LayerItem.IsExpanded = false;         }     }


When the Refreshed event on the legend is bound to the LegendRefreshedCommand on the viewmodel via the extended TriggerAction the OnLegendRefresh method will handle the event. The RefreshedEventArgs are passed in and the LayerItem can now be accessed and the IsExpanded property set to false. This is the piece that is missing when using the plain EventTrigger, because it does not pass the event args.

Hopefully that all makes sense and is easy to follow. I have attached a very simple reference project that might make it more clear.

0 Kudos