GridViewColumnCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / GridViewColumnCollection.cs / 1305600 / GridViewColumnCollection.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 

 
using System.Collections.Generic;       // List 
using System.Collections.ObjectModel;   // ObservableCollection
using System.Collections.Specialized;   // NotifyCollectionChangedEventHandler 
using System.ComponentModel;            // DesignerSerializationVisibility
using System.Diagnostics;               // Debug
using System.Windows.Data;              // Binding.IndexerName
 
using MS.Internal;                      // Helper
 
 
namespace System.Windows.Controls
{ 
    /// 
    /// a List of GridViewColumn. Cooperating with GridViewRowPresenter, can insert and remove column.efficiently.
    /// 
 
    [Serializable()]
    public class GridViewColumnCollection : ObservableCollection 
    { 
        //-------------------------------------------------------------------
        // 
        //  Constructors
        //
        //-------------------------------------------------------------------
 
        //------------------------------------------------------
        // 
        //  Public Methods / Event 
        //
        //----------------------------------------------------- 

        //------------------------------------------------------
        //
        //  Protected Methods 
        //
        //------------------------------------------------------ 
 
        #region Protected Methods
 
        /// 
        /// called by base class ObservableCollection<T> when the list is being cleared;
        /// GridViewColumnCollection override this method to do some internal preprocess work
        ///  
        protected override void ClearItems()
        { 
            VerifyAccess(); 
            _internalEventArg = ClearPreprocess();
            base.ClearItems(); 
        }

        /// 
        /// called by base class ObservableCollection<T> when an column is removed from list; 
        /// GridViewColumnCollection override this method to do some internal preprocess work
        ///  
        protected override void RemoveItem(int index) 
        {
            VerifyAccess(); 
            _internalEventArg = RemoveAtPreprocess(index);
            base.RemoveItem(index);
        }
 
        /// 
        /// called by base class ObservableCollection<T> when an item is added to list; 
        /// GridViewColumnCollection override this method to do some internal preprocess work 
        /// 
        protected override void InsertItem(int index, GridViewColumn column) 
        {
            VerifyAccess();
            _internalEventArg = InsertPreprocess(index, column);
            base.InsertItem(index, column); 
        }
 
        ///  
        /// called by base class ObservableCollection<T> when an column is set in list;
        /// GridViewColumnCollection override this method to do some internal preprocess work 
        /// 
        protected override void SetItem(int index, GridViewColumn column)
        {
            VerifyAccess(); 
            _internalEventArg = SetPreprocess(index, column);
            if (_internalEventArg != null) // the new column is equals to the old one. 
            { 
                base.SetItem(index, column);
            } 
        }

        /// 
        /// Move column to a different index 
        /// 
        /// index of the column which is being moved 
        /// index of the column to be move to 
        protected override void MoveItem(int oldIndex, int newIndex)
        { 
            if (oldIndex != newIndex)
            {
                VerifyAccess();
                _internalEventArg = MovePreprocess(oldIndex, newIndex); 
                base.MoveItem(oldIndex, newIndex);
            } 
        } 

        // Override OnCollectionChanged method to ensure InternalCollectionChanged event is raised before public one. 
        #region OnCollectionChanged

        /// 
        /// raise CollectionChanged event to any listeners 
        /// 
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
        { 
            OnInternalCollectionChanged();
            base.OnCollectionChanged(e); 
        }

        #endregion OnCollectionChanged
 
        #endregion
 
        //----------------------------------------------------- 
        //
        //  Internal Methods / Properties 
        //
        //------------------------------------------------------

        #region Internal Methods / Properties 

        internal event NotifyCollectionChangedEventHandler InternalCollectionChanged 
        { 
            add { _internalCollectionChanged += value; }
            remove { _internalCollectionChanged -= value; } 
        }

        /// 
        /// Make the collection not changabel. 
        /// Should call UnblockWrite the same times as BlockWrite to make collection writable.
        ///  
        internal void BlockWrite() 
        {
            Debug.Assert(IsImmutable != true, "IsImmutable is true before BlockWrite"); 
            IsImmutable = true;
        }

        ///  
        /// Counterfact the effect of BlockWrite() - restore collection to a changable state.
        ///  
        internal void UnblockWrite() 
        {
            Debug.Assert(IsImmutable != false, "IsImmutable is flase before UnblockWrite"); 
            IsImmutable = false;
        }

        // Column list. Columns in this list are organized in the order 
        // that they were inserted into this collection. So Move operation
        // won't change this list. 
        internal List ColumnCollection { get { return _columns; } } 

        // Actual index list of GridViewColumn in ColumnCollection 
        // this[i] == ColumnCollection[IndexList[i]]
        internal List IndexList { get { return _actualIndices; } }

        #endregion 

        #region InheritanceContext 
 
        // The GridView that we're in
        internal DependencyObject Owner 
        {
            get { return _owner; }
            set
            { 
                if (value != _owner)
                { 
                    if (value == null) 
                    {
                        foreach (GridViewColumn c in _columns) 
                        {
                            InheritanceContextHelper.RemoveContextFromObject(_owner, c);
                        }
                    } 
                    else
                    { 
                        foreach (GridViewColumn c in _columns) 
                        {
                            InheritanceContextHelper.ProvideContextForObject(value, c); 
                        }
                    }

                    _owner = value; 
                }
            } 
        } 

        // The GridView that we're in 
        [NonSerializedAttribute]
        private DependencyObject _owner = null;

        // the Owner is GridView 
        internal bool InViewMode
        { 
            get { return _inViewMode; } 
            set { _inViewMode = value; }
        } 

        private bool _inViewMode;

        #endregion InheritanceContext 

        //----------------------------------------------------- 
        // 
        //  Private Methods
        // 
        //-----------------------------------------------------

        #region Private Methods
 
        private void OnInternalCollectionChanged()
        { 
            if (_internalCollectionChanged != null && _internalEventArg != null) 
            {
                _internalCollectionChanged(this, _internalEventArg); 
                // This class member is used as parameter, so clear it after used.
                // For details, see definition.
                _internalEventArg = null;
            } 
        }
 
        private void ColumnPropertyChanged(object sender, PropertyChangedEventArgs e) 
        {
            GridViewColumn column = sender as GridViewColumn; 

            if (_internalCollectionChanged != null && column != null)
            {
                _internalCollectionChanged(this, new GridViewColumnCollectionChangedEventArgs(column, e.PropertyName)); 
            }
        } 
 
        private GridViewColumnCollectionChangedEventArgs MovePreprocess(int oldIndex, int newIndex)
        { 
            Debug.Assert(oldIndex != newIndex, "oldIndex==newIndex when perform move action.");

            VerifyIndexInRange(oldIndex, "oldIndex");
            VerifyIndexInRange(newIndex, "newIndex"); 

            int actualIndex = _actualIndices[oldIndex]; 
 
            if (oldIndex < newIndex)
            { 
                for (int targetIndex = oldIndex; targetIndex < newIndex; targetIndex++)
                {
                    _actualIndices[targetIndex] = _actualIndices[targetIndex + 1];
                } 
            }
            else //if (oldIndex > newIndex) 
            { 
                for (int targetIndex = oldIndex; targetIndex > newIndex; targetIndex--)
                { 
                    _actualIndices[targetIndex] = _actualIndices[targetIndex - 1];
                }
            }
 
            _actualIndices[newIndex] = actualIndex;
 
            return new GridViewColumnCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, _columns[actualIndex], newIndex, oldIndex, actualIndex); 
        }
 
        private GridViewColumnCollectionChangedEventArgs ClearPreprocess()
        {
            GridViewColumn[] list = new GridViewColumn[Count];
            if (Count > 0) 
            {
                CopyTo(list, 0); 
            } 

            // reset columns *before* remove 
            foreach (GridViewColumn c in _columns)
            {
                c.ResetPrivateData();
                ((INotifyPropertyChanged)c).PropertyChanged -= new PropertyChangedEventHandler(ColumnPropertyChanged); 

                InheritanceContextHelper.RemoveContextFromObject(_owner, c); 
            } 

            _columns.Clear(); 
            _actualIndices.Clear();

            return new GridViewColumnCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, list);
        } 

        private GridViewColumnCollectionChangedEventArgs RemoveAtPreprocess(int index) 
        { 
            VerifyIndexInRange(index, "index");
 
            int actualIndex = _actualIndices[index];
            GridViewColumn column = _columns[actualIndex];

            column.ResetPrivateData(); 
            ((INotifyPropertyChanged)column).PropertyChanged -= new PropertyChangedEventHandler(ColumnPropertyChanged);
 
            _columns.RemoveAt(actualIndex); 

            UpdateIndexList(actualIndex, index); 

            UpdateActualIndexInColumn(actualIndex);

            InheritanceContextHelper.RemoveContextFromObject(_owner, column); 

            return new GridViewColumnCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, column, index, actualIndex); 
        } 

        // Remove the index of the removed column in _actualIndices 
        // Correct index in _actualIndices which is bigger than actualIndex
        private void UpdateIndexList(int actualIndex, int index)
        {
            for (int sourceIndex = 0; sourceIndex < index; sourceIndex++) 
            {
                int i = _actualIndices[sourceIndex]; 
                if (i > actualIndex) 
                {
                    _actualIndices[sourceIndex] = i - 1; 
                }
            }

            for (int sourceIndex = index + 1; sourceIndex < _actualIndices.Count; sourceIndex++) 
            {
                int i = _actualIndices[sourceIndex]; 
                if (i < actualIndex) 
                {
                    _actualIndices[sourceIndex - 1] = i; 
                }
                else if (i > actualIndex)
                {
                    _actualIndices[sourceIndex - 1] = i - 1; 
                }
            } 
 
            _actualIndices.RemoveAt(_actualIndices.Count - 1);
        } 

        // pack the actual indeices in columns from after the removed one
        private void UpdateActualIndexInColumn(int iStart)
        { 
            for (int i = iStart; i < _columns.Count; i++)
            { 
                _columns[i].ActualIndex = i; 
            }
        } 

        private GridViewColumnCollectionChangedEventArgs InsertPreprocess(int index, GridViewColumn column)
        {
            int count = _columns.Count; 
            if (index < 0 || index > count)
            { 
                throw new ArgumentOutOfRangeException("index"); 
            }
 
            ValidateColumnForInsert(column);

            _columns.Add(column);
            column.ActualIndex = count; 

            _actualIndices.Insert(index, count); 
 
            //
            // NOTE: 
            //
            //  To prevent a useless (if not error prone) event from being fired, we need to call
            //  {ProvideContextForObject()} before {column.PropertyChanged += ...}.
            // 
            //  Below is the case when a column property change event can be fired before the event
            //  that this column was added into the collection. 
            // 
            //  1. add a new column to the ColumnCollection, e.g.
            // 
            //         
            //
            //  2. once column is connected to the collection, DynamicResource will start loading
            //      the template 
            //
            //  3. #1 will trigger a collection change event which will be fired when this method 
            //      is accomplished. 
            //
            //  4. #2 will trigger a property change event which will be fired at the middle of this 
            //      method.
            //
            //  Ultimately, RowPresenter will receive both #3 and #4. But from above, #4 will come
            //      before #3. Therefore #4 is totally useless because #3 is unknown yet. 
            //
 
            InheritanceContextHelper.ProvideContextForObject(_owner, column); 

            ((INotifyPropertyChanged)column).PropertyChanged += new PropertyChangedEventHandler(ColumnPropertyChanged); 

            return new GridViewColumnCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, column, index, count /* actual index*/);
        }
 
        // This[index] = newColumn
        private GridViewColumnCollectionChangedEventArgs SetPreprocess(int index, GridViewColumn newColumn) 
        { 
            VerifyIndexInRange(index, "index");
 
            GridViewColumn oldColumn = this[index];

            if (oldColumn != newColumn)
            { 
                int oldColumnActualIndex = _actualIndices[index];
 
                RemoveAtPreprocess(index); 
                InsertPreprocess(index, newColumn);
 
                // NOTE: Insert Preprocess already updated InheritanceContext.
                // Don't update here again.

                return new GridViewColumnCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newColumn, oldColumn, index, oldColumnActualIndex); 
            }
 
            return null; 
        }
 
        private void VerifyIndexInRange(int index, string indexName)
        {
            if (index < 0 || index >= _actualIndices.Count)
            { 
                throw new ArgumentOutOfRangeException(indexName);
            } 
        } 

        // Throw if column is null or already existed in a GVCC 
        private void ValidateColumnForInsert(GridViewColumn column)
        {
            if (column == null)
            { 
                throw new ArgumentNullException("column");
            } 
 
            if (column.ActualIndex >= 0)
            { 
                throw new InvalidOperationException(SR.Get(SRID.ListView_NotAllowShareColumnToTwoColumnCollection));
            }
        }
 
        private void VerifyAccess()
        { 
            if (IsImmutable) 
            {
                throw new InvalidOperationException(SR.Get(SRID.ListView_GridViewColumnCollectionIsReadOnly)); 
            }

            // Although CheckReentrancy() is called in base class, we still need to call it here again,
            // otherwise, when Reentrancy is found and exception is thrown, our operation is done and can't be undo. 
            CheckReentrancy();
        } 
 
        #endregion
 
        //-----------------------------------------------------
        //
        //  Private Fields
        // 
        //------------------------------------------------------
 
        #region Private Fields 

        // internal storage of CollumnCollection 
        private List _columns = new List();

        // index of column in _columns
        // GridViewColumn this[i] in public interface is _columns[_actualIndices[i]] 
        private List _actualIndices = new List();
 
        // GridViewHeaderRowPresenter will set this field to true once reorder is started. 
        private bool IsImmutable
        { 
            get { return _isImmutable; }
            set { _isImmutable = value; }
        }
 
        private bool _isImmutable;
 
        private event NotifyCollectionChangedEventHandler _internalCollectionChanged; 

        // EventArgs for _internalCollectionChanged event. 
        // We should raise internal event just before ColletonChanged event of base class,
        // but can't pass this to OnCollectionChanged method as parameter. So store it as a class member.
        [NonSerialized]
        private GridViewColumnCollectionChangedEventArgs _internalEventArg; 

        #endregion 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK