File: src\Framework\System\Windows\Controls\DataGridColumnHeaderCollection.cs
Project: wpf\PresentationFramework.csproj (PresentationFramework)
//---------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//---------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
 
namespace System.Windows.Controls
{
    /// <summary>
    ///     Collection used as the ItemsSource of The DataGridColumnHeadersPresenter.  This is a wrapper around the Column collection; each item
    ///     returns the corresponding Column.Header.
    /// </summary>
    internal class DataGridColumnHeaderCollection : IEnumerable, INotifyCollectionChanged, IDisposable
    {
        public DataGridColumnHeaderCollection(ObservableCollection<DataGridColumn> columns)
        {
            _columns = columns;
 
            if (_columns != null)
            {
                _columns.CollectionChanged += OnColumnsChanged;
            }
        }
 
        public DataGridColumn ColumnFromIndex(int index)
        {
            if (index >= 0 && index < _columns.Count)
            {
                return _columns[index];
            }
 
            return null;
        }
 
        #region Notification Propagation
 
        /// <summary>
        /// Called when the Header property on a Column changes.  Causes us to fire a CollectionChanged event to specify that an item has been replaced.
        /// </summary>
        /// <param name="column"></param>
        internal void NotifyHeaderPropertyChanged(DataGridColumn column, DependencyPropertyChangedEventArgs e)
        {
            Debug.Assert(e.Property == DataGridColumn.HeaderProperty, "We only want to know about the header property changing");
            Debug.Assert(_columns.Contains(column));
 
            NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(
                NotifyCollectionChangedAction.Replace,
                e.NewValue,
                e.OldValue,
                _columns.IndexOf(column));
 
            FireCollectionChanged(args);
        }
 
        #endregion
 
        #region IDisposable Members
 
        public void Dispose()
        {
            GC.SuppressFinalize(this);
            if (_columns != null)
            {
                _columns.CollectionChanged -= OnColumnsChanged;
            }
        }
 
        #endregion 
 
        #region IEnumerable Members
 
        public IEnumerator GetEnumerator()
        {
            return new ColumnHeaderCollectionEnumerator(_columns);
        }
 
        private class ColumnHeaderCollectionEnumerator : IEnumerator, IDisposable
        {
            public ColumnHeaderCollectionEnumerator(ObservableCollection<DataGridColumn> columns)
            {
                if (columns != null)
                {
                    _columns = columns;
                    _columns.CollectionChanged += OnColumnsChanged;
                }
 
                _current = -1;
            }
 
            #region IEnumerator Members
 
            public object Current
            {
                get
                {
                    if (IsValid)
                    {
                        DataGridColumn column = _columns[_current];
 
                        if (column != null)
                        {
                            return column.Header;
                        }
 
                        return null;
                    }
 
                    throw new InvalidOperationException();
                }
            }
 
            public bool MoveNext()
            {
                if (HasChanged)
                {
                    throw new InvalidOperationException();
                }
 
                if (_columns != null && _current < _columns.Count - 1)
                {
                    _current++;
                    return true;
                }
 
                return false;
            }
 
            public void Reset()
            {
                if (HasChanged)
                {
                    throw new InvalidOperationException();
                }
 
                _current = -1;
            }
 
            #endregion
 
            #region IDisposable Members
 
            public void Dispose()
            {
                GC.SuppressFinalize(this);
                if (_columns != null)
                {
                    _columns.CollectionChanged -= OnColumnsChanged;
                }
            }
 
            #endregion 
 
            #region Helpers
 
            private bool HasChanged
            {
                get
                {
                    return _columnsChanged;
                }
            }
 
            private bool IsValid
            {
                get
                {
                    return _columns != null && _current >= 0 && _current < _columns.Count && !HasChanged;
                }
            }
 
            private void OnColumnsChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                _columnsChanged = true;
            }
 
            #endregion 
 
            #region Data
 
            private int _current;
            private bool _columnsChanged;
            private ObservableCollection<DataGridColumn> _columns;
 
            #endregion
        }
 
        #endregion
 
        #region INotifyCollectionChanged Members
 
        /// <summary>
        /// INotifyCollectionChanged CollectionChanged event
        /// </summary>
        public event NotifyCollectionChangedEventHandler CollectionChanged;
 
        /// <summary>
        ///     Helper to raise a CollectionChanged event when the columns collection has changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnColumnsChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            NotifyCollectionChangedEventArgs newArgs;
 
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    newArgs = new NotifyCollectionChangedEventArgs(e.Action, HeadersFromColumns(e.NewItems), e.NewStartingIndex);
                    break;
 
                case NotifyCollectionChangedAction.Remove:
                    newArgs = new NotifyCollectionChangedEventArgs(e.Action, HeadersFromColumns(e.OldItems), e.OldStartingIndex);
                    break;
 
                case NotifyCollectionChangedAction.Move:
                    newArgs = new NotifyCollectionChangedEventArgs(e.Action, HeadersFromColumns(e.OldItems), e.NewStartingIndex, e.OldStartingIndex);
                    break;
 
                case NotifyCollectionChangedAction.Replace:
                    newArgs = new NotifyCollectionChangedEventArgs(e.Action, HeadersFromColumns(e.NewItems), HeadersFromColumns(e.OldItems), e.OldStartingIndex);
                    break;
 
                default:
                    newArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                    break;
            }
 
            FireCollectionChanged(newArgs);
        }
 
        private void FireCollectionChanged(NotifyCollectionChangedEventArgs args)
        {
            if (CollectionChanged != null)
            {
                CollectionChanged(this, args);
            }
        }
        
        private static object[] HeadersFromColumns(IList columns)
        {
            object[] headers = new object[columns.Count];
 
            for (int i = 0; i < columns.Count; i++)
            {
                DataGridColumn column = columns[i] as DataGridColumn;
 
                if (column != null)
                {
                    headers[i] = column.Header;
                }
                else
                {
                    headers[i] = null;
                }
            }
 
            return headers;
        }
 
        #endregion
 
        private ObservableCollection<DataGridColumn> _columns;
    }
}