context: // ********************************************************************************************************
  // Product Name: DotSpatial.Symbology.dll
  // Description:  The core libraries for the DotSpatial project.
  //
  // ********************************************************************************************************
  // The contents of this file are subject to the Lesser GPL
  // you may not use this file except in compliance with the License. You may obtain a copy of the License at
  // http://dotspatial.codeplex.com/license
  //
  // Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
  // ANY KIND, either expressed or implied. See the License for the specific language governing rights and
  // limitations under the License.
  //
  // The Original Code is DotSpatial.dll for the DotSpatial project
  //
  // The Initial Developer of this Original Code is Ted Dunsford. Created in September, 2007.
  //
  // Contributor(s): (Open source contributors should list themselves and their modifications here).
  //
  // ********************************************************************************************************
  
  using System;
  using System.Diagnostics;
  using DotSpatial.Data;
  
  namespace DotSpatial.Symbology
  {
      /// <summary>
      /// This extends the ChangeEventList by providing methods that allow access by an object Key, and will pass
      /// </summary>
      public class LayerEventList<T> : ChangeEventList<T>, ILayerEventList<T>, IDisposable,
          IDisposeLock where T : class, ILayer
      {
          #region Events
  
          /// <summary>
          /// Occurs if the maps should zoom to this layer.
          /// </summary>
          public event EventHandler<EnvelopeArgs> ZoomToLayer;
  
          /// <summary>
          /// Occurs when one of the layers in this collection changes visibility.
          /// </summary>
          public event EventHandler LayerVisibleChanged;
  
          /// <summary>
          /// Occurs when a layer is added to this item.
          /// </summary>
          public event EventHandler<LayerEventArgs> LayerAdded;
  
          /// <summary>
          /// Occurs when a layer is removed from this item.
          /// </summary>
          public event EventHandler<LayerEventArgs> LayerRemoved;
  
          /// <summary>
          /// Occurs immediately after a layer is selected.
          /// </summary>
          public event EventHandler<LayerSelectedEventArgs> LayerSelected;
  
          /// <summary>
          /// Occurs when the selection on a feature layer changes.
          /// </summary>
          public event EventHandler<FeatureLayerSelectionEventArgs> SelectionChanging;
  
          /// <summary>
          /// Occurs after the selection has changed, and all the layers have had their selection information updated.
          /// </summary>
          public event EventHandler SelectionChanged;
  
          #endregion
  
          #region Private Variables
  
          private int _disposeLockCount;
          private bool _isDisposed;
          private bool _isInitialized; // True if layers already existed before a member change
          private bool _layerAddedFired;
          private ILayer _selectedLayer;
  
          #endregion
  
          #region Constructors
  
          #endregion
  
          #region Methods
  
          /// <summary>
          /// This selects the layer with the specified integer index
          /// </summary>
          /// <param name="index">THe zero based integer index</param>
          public void SelectLayer(int index)
          {
              _selectedLayer = this[index];
          }
  
          #endregion
  
          #region Properties
  
          /// <summary>
          /// Gets the currently selected layer in this collection.
          /// </summary>
          public ILayer SelectedLayer
          {
              get { return _selectedLayer; }
              set
              {
                  _selectedLayer = value;
                  if (_selectedLayer != null)
                  {
                      OnLayerSelected(_selectedLayer, _selectedLayer.IsSelected);
                  }
                  //OnListChanged();
              }
          }
  
          /// <summary>
          /// The envelope that contains all of the layers for this data frame.  Essentially this would be
          /// the extents to use if you want to zoom to the world view.
          /// </summary>
          public virtual Extent Extent
          {
              get
              {
                  Extent env = new Extent();
                  if (Count == 0) return env;
                  foreach (T lyr in this)
                  {
                      env.ExpandToInclude(lyr.Extent);
                  }
                  return env;
              }
          }
  
          #endregion
  
          /// <summary>
          /// Gets a value indicating whether dispose has already been called on this object.
          /// </summary>
          public bool IsDisposed
          {
              get { return _isDisposed; }
          }
  
          #region IDisposable Members
  
          /// <summary>
          /// Standard Dispose implementation since layers are now disposable.
          /// </summary>
          public void Dispose()
          {
              Dispose(true);
  
              GC.SuppressFinalize(this);
          }
  
          #endregion
  
          #region IDisposeLock Members
  
          /// <summary>
          /// Adds one request to prevent disposal of this object and its children.
          /// </summary>
          public void LockDispose()
          {
              _disposeLockCount++;
          }
  
          /// <summary>
          /// Gets a value indicating whether there are requests to prevent disposal of this object.
          /// </summary>
          public bool IsDisposeLocked
          {
              get { return _disposeLockCount > 0; }
          }
  
          /// <summary>
          /// Removes one request to prevent disposal of this object and its children.
          /// </summary>
          public void UnlockDispose()
          {
              _disposeLockCount--;
          }
  
          #endregion
  
          /// <summary>
          /// Extends the event listeners to include events like ZoomToLayer and VisibleChanged
          /// </summary>
          /// <param name="item"></param>
          protected override void OnInclude(T item)
          {
              item.LockDispose();
              item.ZoomToLayer += Layer_ZoomToLayer;
              item.VisibleChanged += Layer_VisibleChanged;
              item.FinishedLoading += ItemFinishedLoading;
              item.SelectionChanged += SelectableSelectionChanged;
              item.LayerSelected += ItemLayerSelected;
              base.OnInclude(item);
              OnListChanged();
          }
  
          private void ItemLayerSelected(object sender, LayerEventArgs e)
          {
              // This will also automatically fire the event in the setter.
              SelectedLayer = e.Layer;
          }
  
          /// <summary>
          ///
          /// </summary>
          /// <param name="sender"></param>
          /// <param name="e"></param>
          private void SelectableSelectionChanged(object sender, EventArgs e)
          {
              OnSelectionChanged();
          }
  
          /// <summary>
          /// Occurs when the selection is changed
          /// </summary>
          protected virtual void OnSelectionChanged()
          {
              if (SelectionChanged != null) SelectionChanged(this, new EventArgs());
          }
  
          /// <summary>
          /// Ensures that we re-draw the content when inserting new layers
          /// </summary>
          /// <param name="item"></param>
          protected override void OnIncludeComplete(T item)
          {
              OnLayerAdded(this, new LayerEventArgs(item));
          }
  
          /// <summary>
          /// Removes the extended event listeners once a layer is removed from this list.
          /// </summary>
          /// <param name="item"></param>
          protected override void OnExclude(T item)
          {
              item.UnlockDispose();
              item.ZoomToLayer -= Layer_ZoomToLayer;
              item.VisibleChanged -= Layer_VisibleChanged;
              item.FinishedLoading -= ItemFinishedLoading;
              item.SelectionChanged -= SelectableSelectionChanged;
              item.LayerSelected -= ItemLayerSelected;
  
              //if the layer being removed is selected -
              //ensure that the SelectedLayer property is cleared
              if (item.Equals(SelectedLayer))
              {
                  SelectedLayer = null;
              }
              base.OnExclude(item);
              OnLayerRemoved(item);
              OnListChanged();
              if (!item.IsDisposeLocked)
              {
                  item.Dispose();
              }
          }
  
          /// <summary>
          /// Fires the LayerRemoved event
          /// </summary>
          /// <param name="item"></param>
          protected virtual void OnLayerRemoved(T item)
          {
              if (LayerRemoved != null) LayerRemoved(this, new LayerEventArgs(item));
          }
  
          /// <summary>
          /// Handles the default selection behavior and fires the LayerSelected event.
          /// </summary>
          /// <param name="index">The integer index of the layer being selected</param>
          protected virtual void OnLayerSelected(int index)
          {
              _selectedLayer = base[index];
              if (LayerSelected != null)
              {
                  LayerSelected(this, new LayerSelectedEventArgs(_selectedLayer, _selectedLayer.IsSelected));
              }
          }
  
          /// <summary>
          /// Fires the LayerSelected event and adjusts the selected state of the layer.
          /// </summary>
          /// <param name="layer">The layer to select</param>
          /// <param name="selected">Boolean, true if the specified layer is selected</param>
          protected virtual void OnLayerSelected(ILayer layer, bool selected)
          {
              if (LayerSelected != null)
              {
                  LayerSelected(this, new LayerSelectedEventArgs(layer, selected));
              }
          }
  
          /// <summary>
          /// Fires the ItemChanged event and the MembersChanged event and resets any cached lists
          /// </summary>
          protected override void OnListChanged()
          {
              if (EventsSuspended)
              {
                  base.OnListChanged();
                  return;
              }
  
gt:             if (_isInitialized == false)