Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / Controls / InnerItemCollectionView.cs / 1305600 / 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. /// ////// public override SortDescriptionCollection SortDescriptions { get { if (_sort == null) SetSortDescriptions(new SortDescriptionCollection()); return _sort; } } ////// 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. /// /// 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 /// Move CurrentItem to this item. ///to the given item. /// If the item is not found, move to BeforeFirst. /// true if 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)); } ///points to an item within the view. /// Move /// Move CurrentItem to this index ///to the item at the given index. /// true if 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 ///points to an item within the view. /// Re-create the view, using any 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) { SortFieldComparer.SortHelper(_viewList, 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); } ///and/or . /// /// 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. /// ////// public override SortDescriptionCollection SortDescriptions { get { if (_sort == null) SetSortDescriptions(new SortDescriptionCollection()); return _sort; } } ////// 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. /// /// 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 /// Move CurrentItem to this item. ///to the given item. /// If the item is not found, move to BeforeFirst. /// true if 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)); } ///points to an item within the view. /// Move /// Move CurrentItem to this index ///to the item at the given index. /// true if 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 ///points to an item within the view. /// Re-create the view, using any 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) { SortFieldComparer.SortHelper(_viewList, 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); } ///and/or . /// /// 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- QuaternionRotation3D.cs
- NumericExpr.cs
- CompletedAsyncResult.cs
- ViewLoader.cs
- filewebresponse.cs
- XmlEventCache.cs
- CodeAttributeDeclaration.cs
- ProviderSettings.cs
- ItemCollection.cs
- ErrorActivity.cs
- RangeExpression.cs
- ImageSource.cs
- XPathArrayIterator.cs
- SchemaSetCompiler.cs
- Package.cs
- DataGridViewCheckBoxCell.cs
- XD.cs
- HtmlTableRowCollection.cs
- SecurityTimestamp.cs
- EventHandlerList.cs
- VirtualPathProvider.cs
- WindowsFormsHostAutomationPeer.cs
- XmlMemberMapping.cs
- ZipIOCentralDirectoryDigitalSignature.cs
- SqlFlattener.cs
- SecurityTokenAuthenticator.cs
- MouseGesture.cs
- InternalConfigRoot.cs
- Base64Encoding.cs
- ReplyChannel.cs
- DataKeyArray.cs
- XhtmlMobileTextWriter.cs
- WCFModelStrings.Designer.cs
- Rectangle.cs
- DispatchWrapper.cs
- AnnotationHelper.cs
- AdornerPresentationContext.cs
- StyleTypedPropertyAttribute.cs
- SetUserPreferenceRequest.cs
- DataRecordInternal.cs
- TreeViewEvent.cs
- SiteMapNodeItem.cs
- _ContextAwareResult.cs
- UDPClient.cs
- ReadingWritingEntityEventArgs.cs
- EncoderBestFitFallback.cs
- Queue.cs
- XmlSchemaSimpleTypeUnion.cs
- RoleGroup.cs
- ReadWriteObjectLock.cs
- DbRetry.cs
- XmlDocumentFragment.cs
- ViewgenGatekeeper.cs
- AppDomainEvidenceFactory.cs
- SemanticTag.cs
- PropertyTabChangedEvent.cs
- ResourceManager.cs
- MethodBuilderInstantiation.cs
- WindowsAuthenticationModule.cs
- FixedNode.cs
- AlternateView.cs
- HashMembershipCondition.cs
- Registration.cs
- BitmapEffect.cs
- DateTimePicker.cs
- AttachedPropertyDescriptor.cs
- DiagnosticSection.cs
- ColumnResizeUndoUnit.cs
- Rfc2898DeriveBytes.cs
- PersonalizationStateInfo.cs
- Config.cs
- ExceptionDetail.cs
- XsltOutput.cs
- EditorBrowsableAttribute.cs
- VarInfo.cs
- NativeMethods.cs
- Command.cs
- Tablet.cs
- SerializationObjectManager.cs
- BitHelper.cs
- ToolstripProfessionalRenderer.cs
- PointLight.cs
- DbConnectionOptions.cs
- XmlToDatasetMap.cs
- NetworkInterface.cs
- ListBox.cs
- SQLMembershipProvider.cs
- OlePropertyStructs.cs
- PipeConnection.cs
- HashAlgorithm.cs
- EditorPartChrome.cs
- DocumentGridContextMenu.cs
- NativeActivityAbortContext.cs
- NameNode.cs
- PageHandlerFactory.cs
- ExpressionNormalizer.cs
- ToolStripMenuItemDesigner.cs
- XPathBuilder.cs
- AnnotationHelper.cs
- DataRowExtensions.cs