InnerItemCollectionView.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / MS / Internal / Controls / InnerItemCollectionView.cs / 1 / InnerItemCollectionView.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: inner item collection view used by ItemsControl. 
//                  This is a "cached" view which allows modifications while the view is 
//                  sorted/filtered; it does not keep the view in sorted/filtered state.
// 
// See specs at http://avalon/connecteddata/Specs/ItemsControl.mht
//
//---------------------------------------------------------------------------
 
using System;
using System.Collections; 
using System.Collections.Specialized; 
using System.ComponentModel;
using System.Windows; 
using System.Windows.Controls;
using System.Windows.Data;
using MS.Internal.Data;
 
namespace MS.Internal.Controls
{ 
    internal sealed class InnerItemCollectionView : CollectionView, IList 
    {
        // InnerItemCollectionView will return itself as SourceCollection (SourceCollection property is overridden); 
        // shouldProcessCollectionChanged is turned off because this class will handle its own events.
        public InnerItemCollectionView(int capacity, ItemCollection itemCollection)
            : base(EmptyEnumerable.Instance, false)
        { 
            // This list is cloned and diverged when Sort/Filter is applied.
            _rawList = _viewList = new ArrayList(capacity); 
            _itemCollection = itemCollection; 
        }
 
        //-----------------------------------------------------
        //
        //  Public Interfaces
        // 
        //-----------------------------------------------------
 
#region ICollectionView 

        ///  
        /// Collection of Sort criteria to sort items in this view over the SourceCollection.
        /// 
        /// 
        /// 

/// Simpler implementations do not support sorting and will return an empty /// and immutable / read-only SortDescription collection. /// Attempting to modify such a collection will cause NotSupportedException. /// Use property on CollectionView to test if sorting is supported /// before modifying the returned collection. ///

///

/// One or more sort criteria in form of /// can be added, each specifying a property and direction to sort by. ///

///
public override SortDescriptionCollection SortDescriptions { get { if (_sort == null) SetSortDescriptions(new SortDescriptionCollection()); return _sort; } } /// /// Test if this ICollectionView supports sorting before adding /// to . /// public override bool CanSort { get { return true; } } /// /// Return true if the item belongs to this view. No assumptions are /// made about the item. This method will behave similarly to IList.Contains() /// and will do an exhaustive search through all items in the view. /// If the caller knows that the item belongs to the /// underlying collection, it is more efficient to call PassesFilter. /// public override bool Contains(object item) { return _viewList.Contains(item); } #endregion ICollectionView #region IList /// Gets or sets the element at the specified index. /// The zero-based index of the element to get or set. /// The element at the specified index. public object this[int index] { get { return GetItemAt(index); } set { // will throw an exception if item already has a model parent DependencyObject node = AssertPristineModelChild(value); bool changingCurrentItem = (CurrentPosition == index); // getter checks index and will throw out of range exception object originalItem = _viewList[index]; // add new item into list for now, but might be rolled back if things go wrong _viewList[index] = value; int originalIndexR = -1; if (IsCachedMode) { originalIndexR = _rawList.IndexOf(originalItem); _rawList[originalIndexR] = value; } // try setting model parent, be prepared to rollback item from ItemCollection bool isAddSuccessful = true; if (node != null) { isAddSuccessful = false; try { SetModelParent(value); isAddSuccessful = true; } finally { if (!isAddSuccessful) { // failed to set new model parent, back new item out of collection // and keep old item in collection (note: its parent hasn't been cleared yet!) _viewList[index] = originalItem; if (originalIndexR > 0) { _rawList[originalIndexR] = originalItem; } } else { // was able to parent new item, now cleanup old item ClearModelParent(originalItem); } } } if (!isAddSuccessful) return; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, originalItem, index)); SetIsModified(); } } public bool IsReadOnly { get { return false; } } public bool IsFixedSize { get { return false; } } // always adds at the end of list and view public int Add(object item) { // will throw an exception if item already has a model parent DependencyObject node = AssertPristineModelChild(item); // add to collection before attempting to set model parent int indexV = _viewList.Add(item); int indexR = -1; if (IsCachedMode) { indexR = _rawList.Add(item); } // try setting model parent, be prepared to rollback item from ItemCollection bool isAddSuccessful = true; if (node != null) { isAddSuccessful = false; try { SetModelParent(item); isAddSuccessful = true; } finally { if (!isAddSuccessful) { // failed to set new model parent, back item out of collection _viewList.RemoveAt(indexV); if (indexR >= 0) { _rawList.RemoveAt(indexR); } // also roll back the parent set ClearModelParent(item); indexV = -1; } } } if (!isAddSuccessful) return -1; AdjustCurrencyForAdd(indexV); SetIsModified(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, indexV)); return indexV; } /// /// Clears the collection. Releases the references on all items /// currently in the collection. /// /// /// the ItemCollection is read-only because it is in ItemsSource mode /// public void Clear() { try { for (int i = _rawList.Count - 1; i >=0; --i) { ClearModelParent(_rawList[i]); } } finally { _rawList.Clear(); // Refresh will [....] the _viewList to the cleared _rawList RefreshOrDefer(); } } public void Insert(int index, object item) { // will throw an exception if item already has a model parent DependencyObject node = AssertPristineModelChild(item); // add to collection before attempting to set model parent _viewList.Insert(index, item); int indexR = -1; if (IsCachedMode) { indexR = _rawList.Add(item); } // try setting model parent, be prepared to rollback item from ItemCollection bool isAddSuccessful = true; if (node != null) { isAddSuccessful = false; try { SetModelParent(item); isAddSuccessful = true; } finally { if (!isAddSuccessful) { // failed to set new model parent, back item out of collection _viewList.RemoveAt(index); if (indexR >= 0) { _rawList.RemoveAt(indexR); } // also roll back the parent set ClearModelParent(item); } } } if (!isAddSuccessful) return; AdjustCurrencyForAdd(index); SetIsModified(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); } public void Remove(object item) { int indexV = _viewList.IndexOf(item); int indexR = -1; if (IsCachedMode) { indexR = _rawList.IndexOf(item); } _RemoveAt(indexV, indexR, item); } public void RemoveAt(int index) { if ((0 <= index) && (index < ViewCount)) { object item = this[index]; int indexR = -1; if (IsCachedMode) { indexR = _rawList.IndexOf(item); } _RemoveAt(index, indexR, item); } else { throw new ArgumentOutOfRangeException("index", SR.Get(SRID.ItemCollectionRemoveArgumentOutOfRange)); } } #endregion IList #region ICollection /// /// Gets a value indicating whether access to the collection is synchronized (thread-safe). /// /// true if access to the collection is synchronized (thread-safe); otherwise, false. bool ICollection.IsSynchronized { get { return false; } } /// /// Gets an object that can be used to synchronize access to the view /// /// an object that can be used to synchronize access to the view object ICollection.SyncRoot { get { return _rawList.SyncRoot; } } /// /// Copies all the elements of the current collection (view) to the specified one-dimensional Array. /// void ICollection.CopyTo(Array array, int index) { _viewList.CopyTo(array, index); } #endregion ICollection //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- #region Public Properties public override IEnumerable SourceCollection { get { return this; } } /// /// Return the number of records in (filtered) view /// public override int Count { get { return ViewCount; } } /// /// Returns true if the resulting (filtered) view is emtpy. /// public override bool IsEmpty { get { return ViewCount == 0; } } public override bool NeedsRefresh { get { return base.NeedsRefresh || _isModified; } } #endregion Public Properties //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// Return the index where the given item belongs, or -1 if this index is unknown. /// /// /// If this method returns an index other than -1, it must always be true that /// view[index-1] < item <= view[index], where the comparisons are done via /// the view's IComparer.Compare method (if any). /// (This method is used by a listener's (e.g. System.Windows.Controls.ItemsControl) /// CollectionChanged event handler to speed up its reaction to insertion and deletion of items. /// If IndexOf is not implemented, a listener does a binary search using IComparer.Compare.) /// /// data item public override int IndexOf(object item) { return _viewList.IndexOf(item); } /// /// Retrieve item at the given zero-based index in this CollectionView. /// /// ///

The index is evaluated with any SortDescriptions or Filter being set on this CollectionView.

///
/// /// Thrown if index is out of range /// public override object GetItemAt(int index) { return _viewList[index]; } /// /// Move to the given item. /// If the item is not found, move to BeforeFirst. /// /// Move CurrentItem to this item. /// true if points to an item within the view. public override bool MoveCurrentTo(object item) { // if already on item, don't do anything if (Object.Equals(CurrentItem, item)) { // also check that we're not fooled by a false null CurrentItem if (item != null || IsCurrentInView) return IsCurrentInView; } return MoveCurrentToPosition(IndexOf(item)); } /// /// Move to the item at the given index. /// /// Move CurrentItem to this index /// true if points to an item within the view. public override bool MoveCurrentToPosition(int position) { if (position < -1 || position > ViewCount) throw new ArgumentOutOfRangeException("position"); if (position != CurrentPosition && OKToChangeCurrent()) { bool oldIsCurrentAfterLast = IsCurrentAfterLast; bool oldIsCurrentBeforeFirst = IsCurrentBeforeFirst; _MoveCurrentToPosition(position); OnCurrentChanged(); if (IsCurrentAfterLast != oldIsCurrentAfterLast) OnPropertyChanged(IsCurrentAfterLastPropertyName); if (IsCurrentBeforeFirst != oldIsCurrentBeforeFirst) OnPropertyChanged(IsCurrentBeforeFirstPropertyName); OnPropertyChanged(CurrentPositionPropertyName); OnPropertyChanged(CurrentItemPropertyName); } return IsCurrentInView; } #endregion Public Methods //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ #region Protected Methods /// /// Re-create the view, using any and/or . /// protected override void RefreshOverride() { bool wasEmpty = IsEmpty; object oldCurrentItem = CurrentItem; bool oldIsCurrentAfterLast = IsCurrentAfterLast; bool oldIsCurrentBeforeFirst = IsCurrentBeforeFirst; int oldCurrentPosition = CurrentPosition; // force currency off the collection (gives user a chance to save dirty information) OnCurrentChanging(); if (SortDescriptions.Count > 0 || Filter != null) { // filter the view list if (Filter == null) { _viewList = new ArrayList(_rawList); } else { // optimized for footprint: initialize to size 0 and let AL amortize cost of growth _viewList = new ArrayList(); for (int k = 0; k < _rawList.Count; ++k) { if (Filter(_rawList[k])) _viewList.Add(_rawList[k]); } } // sort the view list if (_sort != null && _sort.Count > 0 && ViewCount > 0) { _viewList.Sort(new SortFieldComparer(_sort, Culture)); } } else // no sort or filter { _viewList = _rawList; } if (IsEmpty || oldIsCurrentBeforeFirst) { _MoveCurrentToPosition(-1); } else if (oldIsCurrentAfterLast) { _MoveCurrentToPosition(ViewCount); } else if (oldCurrentItem != null) // set currency back to old current item, or first if not found { int index = _viewList.IndexOf(oldCurrentItem); if (index < 0) { index = 0; } _MoveCurrentToPosition(index); } ClearIsModified(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); OnCurrentChanged(); if (IsCurrentAfterLast != oldIsCurrentAfterLast) OnPropertyChanged(IsCurrentAfterLastPropertyName); if (IsCurrentBeforeFirst != oldIsCurrentBeforeFirst) OnPropertyChanged(IsCurrentBeforeFirstPropertyName); if (oldCurrentPosition != CurrentPosition) OnPropertyChanged(CurrentPositionPropertyName); if (oldCurrentItem != CurrentItem) OnPropertyChanged(CurrentItemPropertyName); } /// /// Returns an object that enumerates the items in this view. /// protected override IEnumerator GetEnumerator() { return _viewList.GetEnumerator(); } #endregion Protected Methods //----------------------------------------------------- // // Internal Properties // //----------------------------------------------------- #region Internal Properties internal ItemCollection ItemCollection { get { return _itemCollection; } } internal IEnumerator LogicalChildren { get { return _rawList.GetEnumerator(); } } #endregion Internal Properties //----------------------------------------------------- // // Private Properties // //------------------------------------------------------ #region Private Properties internal int RawCount { get { return _rawList.Count; } } private int ViewCount { get { return _viewList.Count; } } // Cached Mode is when two lists are maintained. private bool IsCachedMode { get { return _viewList != _rawList; } } private FrameworkElement ModelParentFE { get { return ItemCollection.ModelParentFE; } } private bool IsCurrentInView { get { return (0 <= CurrentPosition && CurrentPosition < ViewCount); } } #endregion Private Properties //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods // called when making any modifying action on the collection that could cause a refresh to be needed. private void SetIsModified() { if (IsCachedMode) _isModified = true; } private void ClearIsModified() { _isModified = false; } private void _RemoveAt(int index, int indexR, object item) { if (index >=0) _viewList.RemoveAt(index); if (indexR >= 0) _rawList.RemoveAt(indexR); try { // removing the model parent could throw, but we'd be left in a consistent state: // item is already removed from this collection when unparenting throws ClearModelParent(item); } finally { if (index >= 0) { AdjustCurrencyForRemove(index); //SetIsModified(); // A Remove is not affected by the view's sort and filter OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); // currency has to change after firing the deletion event, // so event handlers have the right picture if (_currentElementWasRemoved) { MoveCurrencyOffDeletedElement(); } } } } // check that item is not already parented // throws an exception if already parented DependencyObject AssertPristineModelChild(object item) { DependencyObject node = item as DependencyObject; if (node == null) { return null; } // refuse a child which already has a different model parent! // NOTE: model tree spec would allow reparenting if the parent does not change // but this code will throw: this is a efficient way to catch // an attempt to add the same element twice to the collection if (LogicalTreeHelper.GetParent(node) != null) { throw new InvalidOperationException(SR.Get(SRID.ReparentModelChildIllegal)); } return node; } // NOTE: Only change the item's logical links if the host is a Visual (bug 986386) void SetModelParent(object item) { // to avoid the unnecessary, expensive code in AddLogicalChild, check for DO first if ((ModelParentFE != null) && (item is DependencyObject)) LogicalTreeHelper.AddLogicalChild(ModelParentFE, null, item); } // if item implements IModelTree, clear model parent void ClearModelParent(object item) { // ClearModelParent is also called for items that are not a DependencyObject; // to avoid the unnecessary, expensive code in RemoveLogicalChild, check for DO first if ((ModelParentFE != null) && (item is DependencyObject)) LogicalTreeHelper.RemoveLogicalChild(ModelParentFE, null, item); } // set new SortDescription collection; rehook collection change notification handler private void SetSortDescriptions(SortDescriptionCollection descriptions) { if (_sort != null) { ((INotifyCollectionChanged)_sort).CollectionChanged -= new NotifyCollectionChangedEventHandler(SortDescriptionsChanged); } _sort = descriptions; if (_sort != null) { Invariant.Assert(_sort.Count == 0, "must be empty SortDescription collection"); ((INotifyCollectionChanged)_sort).CollectionChanged += new NotifyCollectionChangedEventHandler(SortDescriptionsChanged); } } // SortDescription was added/removed, refresh CollectionView private void SortDescriptionsChanged(object sender, NotifyCollectionChangedEventArgs e) { RefreshOrDefer(); } // Just move it. No argument check, no events, just move current to position. private void _MoveCurrentToPosition(int position) { if (position < 0) { SetCurrent(null, -1); } else if (position >= ViewCount) { SetCurrent(null, ViewCount); } else { SetCurrent(_viewList[position], position); } } // fix up CurrentPosition and CurrentItem after a collection change private void AdjustCurrencyForAdd(int index) { if (index < 0) return; if (ViewCount == 1) { // added first item; set current at BeforeFirst SetCurrent(null, -1); } else if (index <= CurrentPosition) // adjust current index if insertion is earlier { int newCurrentPosition = CurrentPosition + 1; if (newCurrentPosition < ViewCount) { // CurrentItem might be out of [....] if underlying list is not INCC // or if this Add is the result of a Replace (Rem + Add) SetCurrent(_viewList[newCurrentPosition], newCurrentPosition); } else { SetCurrent(null, ViewCount); } } } // fix up CurrentPosition and CurrentItem after a collection change private void AdjustCurrencyForRemove(int index) { if (index < 0) return; // adjust current index if deletion is earlier if (index < CurrentPosition) { int newCurrentPosition = CurrentPosition - 1; SetCurrent(_viewList[newCurrentPosition], newCurrentPosition); } // move currency off the deleted element else if (index == CurrentPosition) { _currentElementWasRemoved = true; } } // set CurrentItem to the item at CurrentPosition private void MoveCurrencyOffDeletedElement() { int lastPosition = ViewCount - 1; // OK if last is -1 // if position falls beyond last position, move back to last position int newPosition = (CurrentPosition < lastPosition) ? CurrentPosition : lastPosition; // reset this before raising events to avoid problems in re-entrancy _currentElementWasRemoved = false; // ignore cancel, there's no choice in this currency change OnCurrentChanging(); // update CurrentItem to match new position _MoveCurrentToPosition(newPosition); OnCurrentChanged(); } /// /// Helper to raise a PropertyChanged event />). /// private void OnPropertyChanged(string propertyName) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } #endregion Private Methods //------------------------------------------------------ // // Private Fields // //----------------------------------------------------- SortDescriptionCollection _sort; ArrayList _viewList, _rawList; ItemCollection _itemCollection; bool _isModified; bool _currentElementWasRemoved = false; // true if we need to MoveCurrencyOffDeletedElement } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // // Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: inner item collection view used by ItemsControl. // This is a "cached" view which allows modifications while the view is // sorted/filtered; it does not keep the view in sorted/filtered state. // // See specs at http://avalon/connecteddata/Specs/ItemsControl.mht // //--------------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using MS.Internal.Data; namespace MS.Internal.Controls { internal sealed class InnerItemCollectionView : CollectionView, IList { // InnerItemCollectionView will return itself as SourceCollection (SourceCollection property is overridden); // shouldProcessCollectionChanged is turned off because this class will handle its own events. public InnerItemCollectionView(int capacity, ItemCollection itemCollection) : base(EmptyEnumerable.Instance, false) { // This list is cloned and diverged when Sort/Filter is applied. _rawList = _viewList = new ArrayList(capacity); _itemCollection = itemCollection; } //----------------------------------------------------- // // Public Interfaces // //----------------------------------------------------- #region ICollectionView /// /// Collection of Sort criteria to sort items in this view over the SourceCollection. /// /// ///

/// Simpler implementations do not support sorting and will return an empty /// and immutable / read-only SortDescription collection. /// Attempting to modify such a collection will cause NotSupportedException. /// Use property on CollectionView to test if sorting is supported /// before modifying the returned collection. ///

///

/// One or more sort criteria in form of /// can be added, each specifying a property and direction to sort by. ///

///
public override SortDescriptionCollection SortDescriptions { get { if (_sort == null) SetSortDescriptions(new SortDescriptionCollection()); return _sort; } } /// /// Test if this ICollectionView supports sorting before adding /// to . /// public override bool CanSort { get { return true; } } /// /// Return true if the item belongs to this view. No assumptions are /// made about the item. This method will behave similarly to IList.Contains() /// and will do an exhaustive search through all items in the view. /// If the caller knows that the item belongs to the /// underlying collection, it is more efficient to call PassesFilter. /// public override bool Contains(object item) { return _viewList.Contains(item); } #endregion ICollectionView #region IList /// Gets or sets the element at the specified index. /// The zero-based index of the element to get or set. /// The element at the specified index. public object this[int index] { get { return GetItemAt(index); } set { // will throw an exception if item already has a model parent DependencyObject node = AssertPristineModelChild(value); bool changingCurrentItem = (CurrentPosition == index); // getter checks index and will throw out of range exception object originalItem = _viewList[index]; // add new item into list for now, but might be rolled back if things go wrong _viewList[index] = value; int originalIndexR = -1; if (IsCachedMode) { originalIndexR = _rawList.IndexOf(originalItem); _rawList[originalIndexR] = value; } // try setting model parent, be prepared to rollback item from ItemCollection bool isAddSuccessful = true; if (node != null) { isAddSuccessful = false; try { SetModelParent(value); isAddSuccessful = true; } finally { if (!isAddSuccessful) { // failed to set new model parent, back new item out of collection // and keep old item in collection (note: its parent hasn't been cleared yet!) _viewList[index] = originalItem; if (originalIndexR > 0) { _rawList[originalIndexR] = originalItem; } } else { // was able to parent new item, now cleanup old item ClearModelParent(originalItem); } } } if (!isAddSuccessful) return; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, originalItem, index)); SetIsModified(); } } public bool IsReadOnly { get { return false; } } public bool IsFixedSize { get { return false; } } // always adds at the end of list and view public int Add(object item) { // will throw an exception if item already has a model parent DependencyObject node = AssertPristineModelChild(item); // add to collection before attempting to set model parent int indexV = _viewList.Add(item); int indexR = -1; if (IsCachedMode) { indexR = _rawList.Add(item); } // try setting model parent, be prepared to rollback item from ItemCollection bool isAddSuccessful = true; if (node != null) { isAddSuccessful = false; try { SetModelParent(item); isAddSuccessful = true; } finally { if (!isAddSuccessful) { // failed to set new model parent, back item out of collection _viewList.RemoveAt(indexV); if (indexR >= 0) { _rawList.RemoveAt(indexR); } // also roll back the parent set ClearModelParent(item); indexV = -1; } } } if (!isAddSuccessful) return -1; AdjustCurrencyForAdd(indexV); SetIsModified(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, indexV)); return indexV; } /// /// Clears the collection. Releases the references on all items /// currently in the collection. /// /// /// the ItemCollection is read-only because it is in ItemsSource mode /// public void Clear() { try { for (int i = _rawList.Count - 1; i >=0; --i) { ClearModelParent(_rawList[i]); } } finally { _rawList.Clear(); // Refresh will [....] the _viewList to the cleared _rawList RefreshOrDefer(); } } public void Insert(int index, object item) { // will throw an exception if item already has a model parent DependencyObject node = AssertPristineModelChild(item); // add to collection before attempting to set model parent _viewList.Insert(index, item); int indexR = -1; if (IsCachedMode) { indexR = _rawList.Add(item); } // try setting model parent, be prepared to rollback item from ItemCollection bool isAddSuccessful = true; if (node != null) { isAddSuccessful = false; try { SetModelParent(item); isAddSuccessful = true; } finally { if (!isAddSuccessful) { // failed to set new model parent, back item out of collection _viewList.RemoveAt(index); if (indexR >= 0) { _rawList.RemoveAt(indexR); } // also roll back the parent set ClearModelParent(item); } } } if (!isAddSuccessful) return; AdjustCurrencyForAdd(index); SetIsModified(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); } public void Remove(object item) { int indexV = _viewList.IndexOf(item); int indexR = -1; if (IsCachedMode) { indexR = _rawList.IndexOf(item); } _RemoveAt(indexV, indexR, item); } public void RemoveAt(int index) { if ((0 <= index) && (index < ViewCount)) { object item = this[index]; int indexR = -1; if (IsCachedMode) { indexR = _rawList.IndexOf(item); } _RemoveAt(index, indexR, item); } else { throw new ArgumentOutOfRangeException("index", SR.Get(SRID.ItemCollectionRemoveArgumentOutOfRange)); } } #endregion IList #region ICollection /// /// Gets a value indicating whether access to the collection is synchronized (thread-safe). /// /// true if access to the collection is synchronized (thread-safe); otherwise, false. bool ICollection.IsSynchronized { get { return false; } } /// /// Gets an object that can be used to synchronize access to the view /// /// an object that can be used to synchronize access to the view object ICollection.SyncRoot { get { return _rawList.SyncRoot; } } /// /// Copies all the elements of the current collection (view) to the specified one-dimensional Array. /// void ICollection.CopyTo(Array array, int index) { _viewList.CopyTo(array, index); } #endregion ICollection //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- #region Public Properties public override IEnumerable SourceCollection { get { return this; } } /// /// Return the number of records in (filtered) view /// public override int Count { get { return ViewCount; } } /// /// Returns true if the resulting (filtered) view is emtpy. /// public override bool IsEmpty { get { return ViewCount == 0; } } public override bool NeedsRefresh { get { return base.NeedsRefresh || _isModified; } } #endregion Public Properties //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// Return the index where the given item belongs, or -1 if this index is unknown. /// /// /// If this method returns an index other than -1, it must always be true that /// view[index-1] < item <= view[index], where the comparisons are done via /// the view's IComparer.Compare method (if any). /// (This method is used by a listener's (e.g. System.Windows.Controls.ItemsControl) /// CollectionChanged event handler to speed up its reaction to insertion and deletion of items. /// If IndexOf is not implemented, a listener does a binary search using IComparer.Compare.) /// /// data item public override int IndexOf(object item) { return _viewList.IndexOf(item); } /// /// Retrieve item at the given zero-based index in this CollectionView. /// /// ///

The index is evaluated with any SortDescriptions or Filter being set on this CollectionView.

///
/// /// Thrown if index is out of range /// public override object GetItemAt(int index) { return _viewList[index]; } /// /// Move to the given item. /// If the item is not found, move to BeforeFirst. /// /// Move CurrentItem to this item. /// true if points to an item within the view. public override bool MoveCurrentTo(object item) { // if already on item, don't do anything if (Object.Equals(CurrentItem, item)) { // also check that we're not fooled by a false null CurrentItem if (item != null || IsCurrentInView) return IsCurrentInView; } return MoveCurrentToPosition(IndexOf(item)); } /// /// Move to the item at the given index. /// /// Move CurrentItem to this index /// true if points to an item within the view. public override bool MoveCurrentToPosition(int position) { if (position < -1 || position > ViewCount) throw new ArgumentOutOfRangeException("position"); if (position != CurrentPosition && OKToChangeCurrent()) { bool oldIsCurrentAfterLast = IsCurrentAfterLast; bool oldIsCurrentBeforeFirst = IsCurrentBeforeFirst; _MoveCurrentToPosition(position); OnCurrentChanged(); if (IsCurrentAfterLast != oldIsCurrentAfterLast) OnPropertyChanged(IsCurrentAfterLastPropertyName); if (IsCurrentBeforeFirst != oldIsCurrentBeforeFirst) OnPropertyChanged(IsCurrentBeforeFirstPropertyName); OnPropertyChanged(CurrentPositionPropertyName); OnPropertyChanged(CurrentItemPropertyName); } return IsCurrentInView; } #endregion Public Methods //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ #region Protected Methods /// /// Re-create the view, using any and/or . /// protected override void RefreshOverride() { bool wasEmpty = IsEmpty; object oldCurrentItem = CurrentItem; bool oldIsCurrentAfterLast = IsCurrentAfterLast; bool oldIsCurrentBeforeFirst = IsCurrentBeforeFirst; int oldCurrentPosition = CurrentPosition; // force currency off the collection (gives user a chance to save dirty information) OnCurrentChanging(); if (SortDescriptions.Count > 0 || Filter != null) { // filter the view list if (Filter == null) { _viewList = new ArrayList(_rawList); } else { // optimized for footprint: initialize to size 0 and let AL amortize cost of growth _viewList = new ArrayList(); for (int k = 0; k < _rawList.Count; ++k) { if (Filter(_rawList[k])) _viewList.Add(_rawList[k]); } } // sort the view list if (_sort != null && _sort.Count > 0 && ViewCount > 0) { _viewList.Sort(new SortFieldComparer(_sort, Culture)); } } else // no sort or filter { _viewList = _rawList; } if (IsEmpty || oldIsCurrentBeforeFirst) { _MoveCurrentToPosition(-1); } else if (oldIsCurrentAfterLast) { _MoveCurrentToPosition(ViewCount); } else if (oldCurrentItem != null) // set currency back to old current item, or first if not found { int index = _viewList.IndexOf(oldCurrentItem); if (index < 0) { index = 0; } _MoveCurrentToPosition(index); } ClearIsModified(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); OnCurrentChanged(); if (IsCurrentAfterLast != oldIsCurrentAfterLast) OnPropertyChanged(IsCurrentAfterLastPropertyName); if (IsCurrentBeforeFirst != oldIsCurrentBeforeFirst) OnPropertyChanged(IsCurrentBeforeFirstPropertyName); if (oldCurrentPosition != CurrentPosition) OnPropertyChanged(CurrentPositionPropertyName); if (oldCurrentItem != CurrentItem) OnPropertyChanged(CurrentItemPropertyName); } /// /// Returns an object that enumerates the items in this view. /// protected override IEnumerator GetEnumerator() { return _viewList.GetEnumerator(); } #endregion Protected Methods //----------------------------------------------------- // // Internal Properties // //----------------------------------------------------- #region Internal Properties internal ItemCollection ItemCollection { get { return _itemCollection; } } internal IEnumerator LogicalChildren { get { return _rawList.GetEnumerator(); } } #endregion Internal Properties //----------------------------------------------------- // // Private Properties // //------------------------------------------------------ #region Private Properties internal int RawCount { get { return _rawList.Count; } } private int ViewCount { get { return _viewList.Count; } } // Cached Mode is when two lists are maintained. private bool IsCachedMode { get { return _viewList != _rawList; } } private FrameworkElement ModelParentFE { get { return ItemCollection.ModelParentFE; } } private bool IsCurrentInView { get { return (0 <= CurrentPosition && CurrentPosition < ViewCount); } } #endregion Private Properties //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods // called when making any modifying action on the collection that could cause a refresh to be needed. private void SetIsModified() { if (IsCachedMode) _isModified = true; } private void ClearIsModified() { _isModified = false; } private void _RemoveAt(int index, int indexR, object item) { if (index >=0) _viewList.RemoveAt(index); if (indexR >= 0) _rawList.RemoveAt(indexR); try { // removing the model parent could throw, but we'd be left in a consistent state: // item is already removed from this collection when unparenting throws ClearModelParent(item); } finally { if (index >= 0) { AdjustCurrencyForRemove(index); //SetIsModified(); // A Remove is not affected by the view's sort and filter OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); // currency has to change after firing the deletion event, // so event handlers have the right picture if (_currentElementWasRemoved) { MoveCurrencyOffDeletedElement(); } } } } // check that item is not already parented // throws an exception if already parented DependencyObject AssertPristineModelChild(object item) { DependencyObject node = item as DependencyObject; if (node == null) { return null; } // refuse a child which already has a different model parent! // NOTE: model tree spec would allow reparenting if the parent does not change // but this code will throw: this is a efficient way to catch // an attempt to add the same element twice to the collection if (LogicalTreeHelper.GetParent(node) != null) { throw new InvalidOperationException(SR.Get(SRID.ReparentModelChildIllegal)); } return node; } // NOTE: Only change the item's logical links if the host is a Visual (bug 986386) void SetModelParent(object item) { // to avoid the unnecessary, expensive code in AddLogicalChild, check for DO first if ((ModelParentFE != null) && (item is DependencyObject)) LogicalTreeHelper.AddLogicalChild(ModelParentFE, null, item); } // if item implements IModelTree, clear model parent void ClearModelParent(object item) { // ClearModelParent is also called for items that are not a DependencyObject; // to avoid the unnecessary, expensive code in RemoveLogicalChild, check for DO first if ((ModelParentFE != null) && (item is DependencyObject)) LogicalTreeHelper.RemoveLogicalChild(ModelParentFE, null, item); } // set new SortDescription collection; rehook collection change notification handler private void SetSortDescriptions(SortDescriptionCollection descriptions) { if (_sort != null) { ((INotifyCollectionChanged)_sort).CollectionChanged -= new NotifyCollectionChangedEventHandler(SortDescriptionsChanged); } _sort = descriptions; if (_sort != null) { Invariant.Assert(_sort.Count == 0, "must be empty SortDescription collection"); ((INotifyCollectionChanged)_sort).CollectionChanged += new NotifyCollectionChangedEventHandler(SortDescriptionsChanged); } } // SortDescription was added/removed, refresh CollectionView private void SortDescriptionsChanged(object sender, NotifyCollectionChangedEventArgs e) { RefreshOrDefer(); } // Just move it. No argument check, no events, just move current to position. private void _MoveCurrentToPosition(int position) { if (position < 0) { SetCurrent(null, -1); } else if (position >= ViewCount) { SetCurrent(null, ViewCount); } else { SetCurrent(_viewList[position], position); } } // fix up CurrentPosition and CurrentItem after a collection change private void AdjustCurrencyForAdd(int index) { if (index < 0) return; if (ViewCount == 1) { // added first item; set current at BeforeFirst SetCurrent(null, -1); } else if (index <= CurrentPosition) // adjust current index if insertion is earlier { int newCurrentPosition = CurrentPosition + 1; if (newCurrentPosition < ViewCount) { // CurrentItem might be out of [....] if underlying list is not INCC // or if this Add is the result of a Replace (Rem + Add) SetCurrent(_viewList[newCurrentPosition], newCurrentPosition); } else { SetCurrent(null, ViewCount); } } } // fix up CurrentPosition and CurrentItem after a collection change private void AdjustCurrencyForRemove(int index) { if (index < 0) return; // adjust current index if deletion is earlier if (index < CurrentPosition) { int newCurrentPosition = CurrentPosition - 1; SetCurrent(_viewList[newCurrentPosition], newCurrentPosition); } // move currency off the deleted element else if (index == CurrentPosition) { _currentElementWasRemoved = true; } } // set CurrentItem to the item at CurrentPosition private void MoveCurrencyOffDeletedElement() { int lastPosition = ViewCount - 1; // OK if last is -1 // if position falls beyond last position, move back to last position int newPosition = (CurrentPosition < lastPosition) ? CurrentPosition : lastPosition; // reset this before raising events to avoid problems in re-entrancy _currentElementWasRemoved = false; // ignore cancel, there's no choice in this currency change OnCurrentChanging(); // update CurrentItem to match new position _MoveCurrentToPosition(newPosition); OnCurrentChanged(); } /// /// Helper to raise a PropertyChanged event />). /// private void OnPropertyChanged(string propertyName) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } #endregion Private Methods //------------------------------------------------------ // // Private Fields // //----------------------------------------------------- SortDescriptionCollection _sort; ArrayList _viewList, _rawList; ItemCollection _itemCollection; bool _isModified; bool _currentElementWasRemoved = false; // true if we need to MoveCurrencyOffDeletedElement } } // 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