using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
namespace ESRI.ArcGIS.Client.Toolkit.Primitives
{
///
/// Internal class encapsulating a layer item representing the virtual root item for the legend tree.
/// The LayerItems collection of this item is the collection of map layer item displayed at the first level of the TOC.
/// This class manages the events coming from the map, from the map layers and from the map layer items.
///
internal sealed class LegendTree : LayerItemViewModel
{
#region Constructor
public LegendTree()
{
LayerItemsOptions = new LayerItemsOpts(false, false, true, true);
Attach(this);
}
~LegendTree()
{
Detach();
}
#endregion
#region LegendItemTemplate
///
/// Gets or sets the legend item template.
///
/// The legend item template.
private DataTemplate _legendItemTemplate;
internal DataTemplate LegendItemTemplate
{
get
{
return _legendItemTemplate;
}
set
{
if (_legendItemTemplate != value)
{
_legendItemTemplate = value;
PropagateTemplate();
UpdateLayerItemsOptions();
}
}
}
#endregion
#region LayerTemplate
private DataTemplate _layerTemplate;
///
/// Gets or sets the layer template i.e. the template used to display a layer in the legend.
///
/// The layer template.
internal DataTemplate LayerTemplate
{
get
{
return _layerTemplate;
}
set
{
if (_layerTemplate != value)
{
_layerTemplate = value;
PropagateTemplate();
}
}
}
#endregion
#region MapLayerTemplate
private DataTemplate _mapLayerTemplate;
///
/// Gets or sets the map layer template.
///
/// The map layer template.
internal DataTemplate MapLayerTemplate
{
get
{
return _mapLayerTemplate;
}
set
{
if (_mapLayerTemplate != value)
{
_mapLayerTemplate = value;
PropagateTemplate();
}
}
}
#endregion
#region Map
private Map _map;
private LayerCollection _oldLayers = null; // to be able to unhook when Layers changes
///
/// Gets or sets the map that the legend control is buddied to.
///
/// The map.
internal Map Map
{
get
{
return _map;
}
set
{
if (_map != value)
{
if (_map != null)
{
_map.PropertyChanged -= Map_PropertyChanged;
_map.ExtentChanged -= new EventHandler(Map_ExtentChanged);
if (_map.Layers != null)
_map.Layers.CollectionChanged -= Layers_CollectionChanged;
}
_map = value;
if (_map != null)
{
_map.PropertyChanged += Map_PropertyChanged;
_map.ExtentChanged += new EventHandler(Map_ExtentChanged);
if (_map.Layers != null)
_map.Layers.CollectionChanged += Layers_CollectionChanged;
}
UpdateMapLayerItems();
}
}
}
#endregion
#region LayerIDs
private IEnumerable _layerIDs = null;
///
/// Gets or sets the layer IDs of the layers participating in the legend.
///
///
/// 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.
///
/// The layer IDs.
internal IEnumerable LayerIDs
{
get
{
return _layerIDs;
}
set
{
if (_layerIDs != value)
{
_layerIDs = value;
UpdateMapLayerItems();
}
}
}
#endregion
#region ShowOnlyVisibleLayers
private bool _showOnlyVisibleLayers = true;
///
/// Gets or sets a value indicating whether only the visible layers are participating to the legend.
///
///
/// true if only the visible layers are participating to the legend; otherwise, false.
///
internal bool ShowOnlyVisibleLayers
{
get
{
return _showOnlyVisibleLayers;
}
set
{
_showOnlyVisibleLayers = value;
LayerItemsOpts mode = LayerItemsOptions;
mode.ShowOnlyVisibleLayers = value;
PropagateLayerItemsOptions(mode);
}
}
#endregion
#region Refresh
///
/// Refreshes the legend control.
///
/// Note : In most cases, the control is always up to date without calling the refresh method.
internal void Refresh()
{
MapLayerItems.ForEach(mapLayerItem => mapLayerItem.Refresh());
}
#endregion
#region Event Refreshed
///
/// Occurs when the legend is refreshed.
/// Give the opportunity for an application to add or remove legend items.
///
internal event EventHandler Refreshed;
internal void OnRefreshed(object sender, Legend.RefreshedEventArgs args)
{
EventHandler refreshed = Refreshed;
if (refreshed != null)
{
refreshed(sender, args);
}
}
#endregion
#region Map Event Handlers
private void Map_ExtentChanged(object sender, ExtentEventArgs e)
{
if (e.NewExtent != null)
{
if (e.OldExtent == null || e.NewExtent.Height != e.OldExtent.Height || e.NewExtent.Width != e.OldExtent.Width)
{
UpdateLayerVisibilities();
}
}
}
private void Map_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Layers")
{
if (_oldLayers != null)
_oldLayers.CollectionChanged -= Layers_CollectionChanged;
_oldLayers = (sender as Map).Layers;
if (_oldLayers != null)
_oldLayers.CollectionChanged += Layers_CollectionChanged;
UpdateMapLayerItems();
}
}
private void Layers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
UpdateMapLayerItems();
}
#endregion
#region Propagate methods propagating a property to all legend items of the legend tree
private void PropagateTemplate()
{
// set the template on all descendants including the legend items
LayerItems.Descendants(item => item.LayerItems).ForEach(item =>
{
item.Template = item.GetTemplate();
item.LegendItems.ForEach(legendItem => legendItem.Template = legendItem.GetTemplate());
});
}
private void PropagateLayerItemsOptions(LayerItemsOpts layerItemsOptions)
{
if (!LayerItemsOptions.Equals(layerItemsOptions))
{
DeferLayerItemsSourceChanged = true;
LayerItemsOptions = layerItemsOptions;
// set value on all descendants
LayerItems.Descendants(layerItem => layerItem.LayerItems).ForEach(layerItem => layerItem.LayerItemsOptions = layerItemsOptions);
DeferLayerItemsSourceChanged = false;
}
}
#endregion
#region Private Methods
private static IEnumerable GetLayers(IEnumerable ids, Map map)
{
if (map != null && map.Layers != null)
{
if (ids != null)
{
foreach (string item in ids)
{
if (!string.IsNullOrEmpty(item) && map.Layers[item] != null)
yield return map.Layers[item];
}
}
else
{
foreach (Layer layer in map.Layers)
{
yield return layer;
}
}
}
}
private void UpdateMapLayerItems()
{
ObservableCollection mapLayerItems = new ObservableCollection();
foreach (Layer layer in GetLayers(LayerIDs, Map))
{
MapLayerItem mapLayerItem = FindMapLayerItem(layer);
if (mapLayerItem == null) // else reuse existing map layer item to avoid query again the legend
{
// Create a new map layer item
mapLayerItem = new MapLayerItem(layer) {LegendTree = this};
mapLayerItem.Refresh();
}
mapLayerItems.Add(mapLayerItem);
}
LayerItems = mapLayerItems;
}
private IEnumerable MapLayerItems
{
get
{
if (LayerItems == null)
return null;
return LayerItems.OfType();
}
}
private MapLayerItem FindMapLayerItem(Layer layer)
{
return MapLayerItems == null ? null : MapLayerItems.FirstOrDefault(mapLayerItem => mapLayerItem.Layer == layer) as MapLayerItem;
}
private void UpdateLayerVisibilities()
{
LayerItems.ForEach(layerItem =>
{
layerItem.DeferLayerItemsSourceChanged = true;
layerItem.UpdateLayerVisibilities(true, true);
layerItem.DeferLayerItemsSourceChanged = false;
}
);
}
#endregion
#region LayerItemsMode
private Legend.Mode _layerItemsMode = Legend.Mode.Flat;
internal Legend.Mode LayerItemsMode
{
get
{
return _layerItemsMode;
}
set
{
if (value != _layerItemsMode)
{
_layerItemsMode = value;
UpdateLayerItemsOptions();
}
}
}
private void UpdateLayerItemsOptions()
{
LayerItemsOpts layerItemsOptions;
bool returnsLegendItems = (LegendItemTemplate != null);
switch (LayerItemsMode)
{
case Legend.Mode.Tree:
layerItemsOptions = new LayerItemsOpts(true, true, returnsLegendItems, ShowOnlyVisibleLayers);
break;
default:
layerItemsOptions = new LayerItemsOpts(false, false, returnsLegendItems, ShowOnlyVisibleLayers);
break;
}
PropagateLayerItemsOptions(layerItemsOptions);
}
#endregion
}
}