EnumerableCollectionView.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / Data / EnumerableCollectionView.cs / 1305600 / EnumerableCollectionView.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Collection view over an IEnumerable. 
// 
//---------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.Collections.Specialized;
using System.ComponentModel; 
using System.Diagnostics; 
using System.Threading;
using System.Windows; 
using System.Windows.Data;

namespace MS.Internal.Data
{ 

    /// 
    /// Collection view over an IEnumerable. 
    ///
    internal class EnumerableCollectionView : CollectionView 
    {
        #region Constructors

        //----------------------------------------------------- 
        //
        //  Constructors 
        // 
        //-----------------------------------------------------
 
        // Set up a ListCollectionView over the
        // snapshot.  We will delegate all CollectionView functionality
        // to this view.
        internal EnumerableCollectionView(IEnumerable source) 
            : base(source, -1)
        { 
            _snapshot = new ObservableCollection(); 

            LoadSnapshotCore(source); 

            if (_snapshot.Count > 0)
            {
                SetCurrent(_snapshot[0], 0, 1); 
            }
            else 
            { 
                SetCurrent(null, -1, 0);
            } 

            // if the source doesn't raise collection change events, try to
            // detect changes by polling the enumerator
            _pollForChanges = !(source is INotifyCollectionChanged); 

            _view = new ListCollectionView(_snapshot); 
 
            INotifyCollectionChanged incc = _view as INotifyCollectionChanged;
            incc.CollectionChanged += new NotifyCollectionChangedEventHandler(_OnViewChanged); 

            INotifyPropertyChanged ipc = _view as INotifyPropertyChanged;
            ipc.PropertyChanged += new PropertyChangedEventHandler(_OnPropertyChanged);
 
            _view.CurrentChanging += new CurrentChangingEventHandler(_OnCurrentChanging);
            _view.CurrentChanged += new EventHandler(_OnCurrentChanged); 
        } 

        #endregion Constructors 

        //------------------------------------------------------
        //
        //  Interfaces 
        //
        //----------------------------------------------------- 
 
        #region ICollectionView
 
        /// 
        /// Culture to use during sorting.
        /// 
        public override System.Globalization.CultureInfo Culture 
        {
            get { return _view.Culture; } 
            set { _view.Culture = value; } 
        }
 
        /// 
        /// Return true if the item belongs to this view.  No assumptions are
        /// made about the item. This method will behave similarly to IList.Contains().
        /// 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) 
        {
            EnsureSnapshot(); 
            return _view.Contains(item);
        }

        ///  
        /// Set/get a filter callback to filter out items in collection.
        /// This property will always accept a filter, but the collection view for the 
        /// underlying InnerList or ItemsSource may not actually support filtering. 
        /// Please check 
        ///  
        /// 
        /// Collections assigned to ItemsSource may not support filtering and could throw a NotSupportedException.
        /// Use  property to test if sorting is supported before adding
        /// to SortDescriptions. 
        /// 
        public override Predicate Filter 
        { 
            get { return _view.Filter; }
            set { _view.Filter = value; } 
        }

        /// 
        /// Test if this ICollectionView supports filtering before assigning 
        /// a filter callback to .
        ///  
        public override bool CanFilter 
        {
            get { return _view.CanFilter; } 
        }

        /// 
        /// Set/get Sort criteria to sort items in collection. 
        /// 
        ///  
        /// 

/// Clear a sort criteria by assigning SortDescription.Empty to this property. /// One or more sort criteria in form of /// can be used, each specifying a property and direction to sort by. ///

///
/// /// Simpler implementations do not support sorting and will throw a NotSupportedException. /// Use property to test if sorting is supported before adding /// to SortDescriptions. /// public override SortDescriptionCollection SortDescriptions { get { return _view.SortDescriptions; } } /// /// Test if this ICollectionView supports sorting before adding /// to . /// public override bool CanSort { get { return _view.CanSort; } } /// /// Returns true if this view really supports grouping. /// When this returns false, the rest of the interface is ignored. /// public override bool CanGroup { get { return _view.CanGroup; } } /// /// The description of grouping, indexed by level. /// public override ObservableCollection GroupDescriptions { get { return _view.GroupDescriptions; } } /// /// The top-level groups, constructed according to the descriptions /// given in GroupDescriptions. /// public override ReadOnlyObservableCollection Groups { get { return _view.Groups; } } /// /// Enter a Defer Cycle. /// Defer cycles are used to coalesce changes to the ICollectionView. /// public override IDisposable DeferRefresh() { return _view.DeferRefresh(); } /// Return current item. public override object CurrentItem { get { return _view.CurrentItem; } } /// /// The ordinal position of the within the (optionally /// sorted and filtered) view. /// public override int CurrentPosition { get { return _view.CurrentPosition; } } /// Return true if currency is beyond the end (End-Of-File). public override bool IsCurrentAfterLast { get { return _view.IsCurrentAfterLast; } } /// Return true if currency is before the beginning (Beginning-Of-File). public override bool IsCurrentBeforeFirst { get { return _view.IsCurrentBeforeFirst; } } /// Move to the first item. public override bool MoveCurrentToFirst() { return _view.MoveCurrentToFirst(); } /// Move to the previous item. public override bool MoveCurrentToPrevious() { return _view.MoveCurrentToPrevious(); } /// Move to the next item. public override bool MoveCurrentToNext() { return _view.MoveCurrentToNext(); } /// Move to the last item. public override bool MoveCurrentToLast() { return _view.MoveCurrentToLast(); } /// Move to the given item. public override bool MoveCurrentTo(object item) { return _view.MoveCurrentTo(item); } /// Move CurrentItem to this index public override bool MoveCurrentToPosition(int position) { // // If the index is out of range here, I'll let the // _view be the one to make that determination. // return _view.MoveCurrentToPosition(position); } #endregion ICollectionView //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties /// /// Return the number of records (or -1, meaning "don't know"). /// A virtualizing view should return the best estimate it can /// without de-virtualizing all the data. A non-virtualizing view /// should return the exact count of its (filtered) data. /// public override int Count { get { EnsureSnapshot(); return _view.Count; } } public override bool IsEmpty { get { EnsureSnapshot(); return (_view != null) ? _view.IsEmpty : true; } } /// /// Returns true if this view needs to be refreshed. /// public override bool NeedsRefresh { get { return _view.NeedsRefresh; } } #endregion Public Properties //----------------------------------------------------- // // Public Methods // //------------------------------------------------------ #region Public Methods /// Return the index where the given item appears, or -1 if doesn't appear. /// /// data item public override int IndexOf(object item) { EnsureSnapshot(); return _view.IndexOf(item); } /// /// Return true if the item belongs to this view. The item is assumed to belong to the /// underlying DataCollection; this method merely takes filters into account. /// It is commonly used during collection-changed notifications to determine if the added/removed /// item requires processing. /// Returns true if no filter is set on collection view. /// public override bool PassesFilter(object item) { if (_view.CanFilter && _view.Filter != null) return _view.Filter(item); return true; } /// /// Retrieve item at the given zero-based index in this CollectionView. /// /// /// Thrown if index is out of range /// public override object GetItemAt(int index) { EnsureSnapshot(); return _view.GetItemAt(index); } #endregion Public Methods //----------------------------------------------------- // // Protected Methods // //----------------------------------------------------- #region Protected Methods /// Implementation of IEnumerable.GetEnumerator(). /// This provides a way to enumerate the members of the collection /// without changing the currency. /// protected override IEnumerator GetEnumerator() { EnsureSnapshot(); return ((IEnumerable) _view).GetEnumerator(); } /// Re-create the view, using any . protected override void RefreshOverride() { LoadSnapshot(SourceCollection); } /// /// Must be implemented by the derived classes to process a single change on the /// UI thread. The UI thread will have already been entered by now. /// /// /// The NotifyCollectionChangedEventArgs to be processed. /// protected override void ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) { // ignore events received during initialization if (_view == null) return; // apply the change to the snapshot switch (args.Action) { case NotifyCollectionChangedAction.Add: if (args.NewStartingIndex < 0 || _snapshot.Count <= args.NewStartingIndex) { // append for (int i=0; i=0; --i) { _snapshot.Insert(args.NewStartingIndex, args.NewItems[i]); } } break; case NotifyCollectionChangedAction.Remove: if (args.OldStartingIndex < 0) throw new InvalidOperationException(SR.Get(SRID.RemovedItemNotFound)); for (int i=args.OldItems.Count-1, index=args.OldStartingIndex+i; i>=0; --i, --index) { if (!Object.Equals(args.OldItems[i], _snapshot[index])) // throw new InvalidOperationException(SR.Get(SRID.AddedItemNotAtIndex, index)); _snapshot.RemoveAt(index); } break; case NotifyCollectionChangedAction.Replace: for (int i=args.NewItems.Count-1, index=args.NewStartingIndex+i; i>=0; --i, --index) { if (!Object.Equals(args.OldItems[i], _snapshot[index])) // throw new InvalidOperationException(SR.Get(SRID.AddedItemNotAtIndex, index)); _snapshot[index] = args.NewItems[i]; } break; case NotifyCollectionChangedAction.Move: if (args.NewStartingIndex < 0) throw new InvalidOperationException(SR.Get(SRID.CannotMoveToUnknownPosition)); if (args.OldStartingIndex < args.NewStartingIndex) { for (int i = args.OldItems.Count - 1, oldIndex = args.OldStartingIndex + i, newIndex = args.NewStartingIndex + i; i >= 0; --i, --oldIndex, --newIndex) { if (!Object.Equals(args.OldItems[i], _snapshot[oldIndex])) // throw new InvalidOperationException(SR.Get(SRID.AddedItemNotAtIndex, oldIndex)); _snapshot.Move(oldIndex, newIndex); } } else { for (int i = 0, oldIndex = args.OldStartingIndex + i, newIndex = args.NewStartingIndex + i; i < args.OldItems.Count; ++i, ++oldIndex, ++newIndex) { if (!Object.Equals(args.OldItems[i], _snapshot[oldIndex])) // throw new InvalidOperationException(SR.Get(SRID.AddedItemNotAtIndex, oldIndex)); _snapshot.Move(oldIndex, newIndex); } } break; case NotifyCollectionChangedAction.Reset: LoadSnapshot(SourceCollection); break; } } #endregion Protected Methods //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods // Load a snapshot of the contents of the IEnumerable into the // ObservableCollection. void LoadSnapshot(IEnumerable source) { // force currency off the collection (gives user a chance to save dirty information) OnCurrentChanging(); // remember the values of the scalar properties, so that we can restore // them and raise events after reloading the data object oldCurrentItem = CurrentItem; int oldCurrentPosition = CurrentPosition; bool oldIsCurrentBeforeFirst = IsCurrentBeforeFirst; bool oldIsCurrentAfterLast = IsCurrentAfterLast; // reload the data LoadSnapshotCore(source); // tell listeners everything has changed OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); OnCurrentChanged(); if (IsCurrentAfterLast != oldIsCurrentAfterLast) OnPropertyChanged(new PropertyChangedEventArgs(IsCurrentAfterLastPropertyName)); if (IsCurrentBeforeFirst != oldIsCurrentBeforeFirst) OnPropertyChanged(new PropertyChangedEventArgs(IsCurrentBeforeFirstPropertyName)); if (oldCurrentPosition != CurrentPosition) OnPropertyChanged(new PropertyChangedEventArgs(CurrentPositionPropertyName)); if (oldCurrentItem != CurrentItem) OnPropertyChanged(new PropertyChangedEventArgs(CurrentItemPropertyName)); } void LoadSnapshotCore(IEnumerable source) { _trackingEnumerator = source.GetEnumerator(); using (IgnoreViewEvents()) { _snapshot.Clear(); while (_trackingEnumerator.MoveNext()) { _snapshot.Add(_trackingEnumerator.Current); } } } // if the IEnumerable has changed, bring the snapshot up to date. // (This isn't necessary if the IEnumerable is also INotifyCollectionChanged // because we keep the snapshot in [....] incrementally.) void EnsureSnapshot() { if (_pollForChanges) { try { _trackingEnumerator.MoveNext(); } catch (InvalidOperationException) { // if (TraceData.IsEnabled && !_warningHasBeenRaised) { _warningHasBeenRaised = true; TraceData.Trace(TraceEventType.Warning, TraceData.CollectionChangedWithoutNotification(SourceCollection.GetType().FullName)); } // collection was changed - start over with a new enumerator LoadSnapshotCore(SourceCollection); } } } IDisposable IgnoreViewEvents() { return new IgnoreViewEventsHelper(this); } void BeginIgnoreEvents() { ++ _ignoreEventsLevel; } void EndIgnoreEvents() { -- _ignoreEventsLevel; } // forward events from the internal view to our own listeners void _OnPropertyChanged(object sender, PropertyChangedEventArgs args) { if (_ignoreEventsLevel != 0) return; OnPropertyChanged(args); } void _OnViewChanged(object sender, NotifyCollectionChangedEventArgs args) { if (_ignoreEventsLevel != 0) return; OnCollectionChanged(args); } void _OnCurrentChanging(object sender, CurrentChangingEventArgs args) { if (_ignoreEventsLevel != 0) return; OnCurrentChanging(); } void _OnCurrentChanged(object sender, EventArgs args) { if (_ignoreEventsLevel != 0) return; OnCurrentChanged(); } #endregion Private Methods #region Private Data //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ ListCollectionView _view; ObservableCollection _snapshot; IEnumerator _trackingEnumerator; int _ignoreEventsLevel; bool _pollForChanges; bool _warningHasBeenRaised; class IgnoreViewEventsHelper : IDisposable { public IgnoreViewEventsHelper(EnumerableCollectionView parent) { _parent = parent; _parent.BeginIgnoreEvents(); } public void Dispose() { if (_parent != null) { _parent.EndIgnoreEvents(); _parent = null; } GC.SuppressFinalize(this); } EnumerableCollectionView _parent; } #endregion Private Data } } // 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: Collection view over an IEnumerable. // //--------------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Threading; using System.Windows; using System.Windows.Data; namespace MS.Internal.Data { /// /// Collection view over an IEnumerable. /// internal class EnumerableCollectionView : CollectionView { #region Constructors //----------------------------------------------------- // // Constructors // //----------------------------------------------------- // Set up a ListCollectionView over the // snapshot. We will delegate all CollectionView functionality // to this view. internal EnumerableCollectionView(IEnumerable source) : base(source, -1) { _snapshot = new ObservableCollection(); LoadSnapshotCore(source); if (_snapshot.Count > 0) { SetCurrent(_snapshot[0], 0, 1); } else { SetCurrent(null, -1, 0); } // if the source doesn't raise collection change events, try to // detect changes by polling the enumerator _pollForChanges = !(source is INotifyCollectionChanged); _view = new ListCollectionView(_snapshot); INotifyCollectionChanged incc = _view as INotifyCollectionChanged; incc.CollectionChanged += new NotifyCollectionChangedEventHandler(_OnViewChanged); INotifyPropertyChanged ipc = _view as INotifyPropertyChanged; ipc.PropertyChanged += new PropertyChangedEventHandler(_OnPropertyChanged); _view.CurrentChanging += new CurrentChangingEventHandler(_OnCurrentChanging); _view.CurrentChanged += new EventHandler(_OnCurrentChanged); } #endregion Constructors //------------------------------------------------------ // // Interfaces // //----------------------------------------------------- #region ICollectionView /// /// Culture to use during sorting. /// public override System.Globalization.CultureInfo Culture { get { return _view.Culture; } set { _view.Culture = value; } } /// /// Return true if the item belongs to this view. No assumptions are /// made about the item. This method will behave similarly to IList.Contains(). /// 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) { EnsureSnapshot(); return _view.Contains(item); } /// /// Set/get a filter callback to filter out items in collection. /// This property will always accept a filter, but the collection view for the /// underlying InnerList or ItemsSource may not actually support filtering. /// Please check /// /// /// Collections assigned to ItemsSource may not support filtering and could throw a NotSupportedException. /// Use property to test if sorting is supported before adding /// to SortDescriptions. /// public override Predicate Filter { get { return _view.Filter; } set { _view.Filter = value; } } /// /// Test if this ICollectionView supports filtering before assigning /// a filter callback to . /// public override bool CanFilter { get { return _view.CanFilter; } } /// /// Set/get Sort criteria to sort items in collection. /// /// ///

/// Clear a sort criteria by assigning SortDescription.Empty to this property. /// One or more sort criteria in form of /// can be used, each specifying a property and direction to sort by. ///

///
/// /// Simpler implementations do not support sorting and will throw a NotSupportedException. /// Use property to test if sorting is supported before adding /// to SortDescriptions. /// public override SortDescriptionCollection SortDescriptions { get { return _view.SortDescriptions; } } /// /// Test if this ICollectionView supports sorting before adding /// to . /// public override bool CanSort { get { return _view.CanSort; } } /// /// Returns true if this view really supports grouping. /// When this returns false, the rest of the interface is ignored. /// public override bool CanGroup { get { return _view.CanGroup; } } /// /// The description of grouping, indexed by level. /// public override ObservableCollection GroupDescriptions { get { return _view.GroupDescriptions; } } /// /// The top-level groups, constructed according to the descriptions /// given in GroupDescriptions. /// public override ReadOnlyObservableCollection Groups { get { return _view.Groups; } } /// /// Enter a Defer Cycle. /// Defer cycles are used to coalesce changes to the ICollectionView. /// public override IDisposable DeferRefresh() { return _view.DeferRefresh(); } /// Return current item. public override object CurrentItem { get { return _view.CurrentItem; } } /// /// The ordinal position of the within the (optionally /// sorted and filtered) view. /// public override int CurrentPosition { get { return _view.CurrentPosition; } } /// Return true if currency is beyond the end (End-Of-File). public override bool IsCurrentAfterLast { get { return _view.IsCurrentAfterLast; } } /// Return true if currency is before the beginning (Beginning-Of-File). public override bool IsCurrentBeforeFirst { get { return _view.IsCurrentBeforeFirst; } } /// Move to the first item. public override bool MoveCurrentToFirst() { return _view.MoveCurrentToFirst(); } /// Move to the previous item. public override bool MoveCurrentToPrevious() { return _view.MoveCurrentToPrevious(); } /// Move to the next item. public override bool MoveCurrentToNext() { return _view.MoveCurrentToNext(); } /// Move to the last item. public override bool MoveCurrentToLast() { return _view.MoveCurrentToLast(); } /// Move to the given item. public override bool MoveCurrentTo(object item) { return _view.MoveCurrentTo(item); } /// Move CurrentItem to this index public override bool MoveCurrentToPosition(int position) { // // If the index is out of range here, I'll let the // _view be the one to make that determination. // return _view.MoveCurrentToPosition(position); } #endregion ICollectionView //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties /// /// Return the number of records (or -1, meaning "don't know"). /// A virtualizing view should return the best estimate it can /// without de-virtualizing all the data. A non-virtualizing view /// should return the exact count of its (filtered) data. /// public override int Count { get { EnsureSnapshot(); return _view.Count; } } public override bool IsEmpty { get { EnsureSnapshot(); return (_view != null) ? _view.IsEmpty : true; } } /// /// Returns true if this view needs to be refreshed. /// public override bool NeedsRefresh { get { return _view.NeedsRefresh; } } #endregion Public Properties //----------------------------------------------------- // // Public Methods // //------------------------------------------------------ #region Public Methods /// Return the index where the given item appears, or -1 if doesn't appear. /// /// data item public override int IndexOf(object item) { EnsureSnapshot(); return _view.IndexOf(item); } /// /// Return true if the item belongs to this view. The item is assumed to belong to the /// underlying DataCollection; this method merely takes filters into account. /// It is commonly used during collection-changed notifications to determine if the added/removed /// item requires processing. /// Returns true if no filter is set on collection view. /// public override bool PassesFilter(object item) { if (_view.CanFilter && _view.Filter != null) return _view.Filter(item); return true; } /// /// Retrieve item at the given zero-based index in this CollectionView. /// /// /// Thrown if index is out of range /// public override object GetItemAt(int index) { EnsureSnapshot(); return _view.GetItemAt(index); } #endregion Public Methods //----------------------------------------------------- // // Protected Methods // //----------------------------------------------------- #region Protected Methods /// Implementation of IEnumerable.GetEnumerator(). /// This provides a way to enumerate the members of the collection /// without changing the currency. /// protected override IEnumerator GetEnumerator() { EnsureSnapshot(); return ((IEnumerable) _view).GetEnumerator(); } /// Re-create the view, using any . protected override void RefreshOverride() { LoadSnapshot(SourceCollection); } /// /// Must be implemented by the derived classes to process a single change on the /// UI thread. The UI thread will have already been entered by now. /// /// /// The NotifyCollectionChangedEventArgs to be processed. /// protected override void ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) { // ignore events received during initialization if (_view == null) return; // apply the change to the snapshot switch (args.Action) { case NotifyCollectionChangedAction.Add: if (args.NewStartingIndex < 0 || _snapshot.Count <= args.NewStartingIndex) { // append for (int i=0; i=0; --i) { _snapshot.Insert(args.NewStartingIndex, args.NewItems[i]); } } break; case NotifyCollectionChangedAction.Remove: if (args.OldStartingIndex < 0) throw new InvalidOperationException(SR.Get(SRID.RemovedItemNotFound)); for (int i=args.OldItems.Count-1, index=args.OldStartingIndex+i; i>=0; --i, --index) { if (!Object.Equals(args.OldItems[i], _snapshot[index])) // throw new InvalidOperationException(SR.Get(SRID.AddedItemNotAtIndex, index)); _snapshot.RemoveAt(index); } break; case NotifyCollectionChangedAction.Replace: for (int i=args.NewItems.Count-1, index=args.NewStartingIndex+i; i>=0; --i, --index) { if (!Object.Equals(args.OldItems[i], _snapshot[index])) // throw new InvalidOperationException(SR.Get(SRID.AddedItemNotAtIndex, index)); _snapshot[index] = args.NewItems[i]; } break; case NotifyCollectionChangedAction.Move: if (args.NewStartingIndex < 0) throw new InvalidOperationException(SR.Get(SRID.CannotMoveToUnknownPosition)); if (args.OldStartingIndex < args.NewStartingIndex) { for (int i = args.OldItems.Count - 1, oldIndex = args.OldStartingIndex + i, newIndex = args.NewStartingIndex + i; i >= 0; --i, --oldIndex, --newIndex) { if (!Object.Equals(args.OldItems[i], _snapshot[oldIndex])) // throw new InvalidOperationException(SR.Get(SRID.AddedItemNotAtIndex, oldIndex)); _snapshot.Move(oldIndex, newIndex); } } else { for (int i = 0, oldIndex = args.OldStartingIndex + i, newIndex = args.NewStartingIndex + i; i < args.OldItems.Count; ++i, ++oldIndex, ++newIndex) { if (!Object.Equals(args.OldItems[i], _snapshot[oldIndex])) // throw new InvalidOperationException(SR.Get(SRID.AddedItemNotAtIndex, oldIndex)); _snapshot.Move(oldIndex, newIndex); } } break; case NotifyCollectionChangedAction.Reset: LoadSnapshot(SourceCollection); break; } } #endregion Protected Methods //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods // Load a snapshot of the contents of the IEnumerable into the // ObservableCollection. void LoadSnapshot(IEnumerable source) { // force currency off the collection (gives user a chance to save dirty information) OnCurrentChanging(); // remember the values of the scalar properties, so that we can restore // them and raise events after reloading the data object oldCurrentItem = CurrentItem; int oldCurrentPosition = CurrentPosition; bool oldIsCurrentBeforeFirst = IsCurrentBeforeFirst; bool oldIsCurrentAfterLast = IsCurrentAfterLast; // reload the data LoadSnapshotCore(source); // tell listeners everything has changed OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); OnCurrentChanged(); if (IsCurrentAfterLast != oldIsCurrentAfterLast) OnPropertyChanged(new PropertyChangedEventArgs(IsCurrentAfterLastPropertyName)); if (IsCurrentBeforeFirst != oldIsCurrentBeforeFirst) OnPropertyChanged(new PropertyChangedEventArgs(IsCurrentBeforeFirstPropertyName)); if (oldCurrentPosition != CurrentPosition) OnPropertyChanged(new PropertyChangedEventArgs(CurrentPositionPropertyName)); if (oldCurrentItem != CurrentItem) OnPropertyChanged(new PropertyChangedEventArgs(CurrentItemPropertyName)); } void LoadSnapshotCore(IEnumerable source) { _trackingEnumerator = source.GetEnumerator(); using (IgnoreViewEvents()) { _snapshot.Clear(); while (_trackingEnumerator.MoveNext()) { _snapshot.Add(_trackingEnumerator.Current); } } } // if the IEnumerable has changed, bring the snapshot up to date. // (This isn't necessary if the IEnumerable is also INotifyCollectionChanged // because we keep the snapshot in [....] incrementally.) void EnsureSnapshot() { if (_pollForChanges) { try { _trackingEnumerator.MoveNext(); } catch (InvalidOperationException) { // if (TraceData.IsEnabled && !_warningHasBeenRaised) { _warningHasBeenRaised = true; TraceData.Trace(TraceEventType.Warning, TraceData.CollectionChangedWithoutNotification(SourceCollection.GetType().FullName)); } // collection was changed - start over with a new enumerator LoadSnapshotCore(SourceCollection); } } } IDisposable IgnoreViewEvents() { return new IgnoreViewEventsHelper(this); } void BeginIgnoreEvents() { ++ _ignoreEventsLevel; } void EndIgnoreEvents() { -- _ignoreEventsLevel; } // forward events from the internal view to our own listeners void _OnPropertyChanged(object sender, PropertyChangedEventArgs args) { if (_ignoreEventsLevel != 0) return; OnPropertyChanged(args); } void _OnViewChanged(object sender, NotifyCollectionChangedEventArgs args) { if (_ignoreEventsLevel != 0) return; OnCollectionChanged(args); } void _OnCurrentChanging(object sender, CurrentChangingEventArgs args) { if (_ignoreEventsLevel != 0) return; OnCurrentChanging(); } void _OnCurrentChanged(object sender, EventArgs args) { if (_ignoreEventsLevel != 0) return; OnCurrentChanged(); } #endregion Private Methods #region Private Data //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ ListCollectionView _view; ObservableCollection _snapshot; IEnumerator _trackingEnumerator; int _ignoreEventsLevel; bool _pollForChanges; bool _warningHasBeenRaised; class IgnoreViewEventsHelper : IDisposable { public IgnoreViewEventsHelper(EnumerableCollectionView parent) { _parent = parent; _parent.BeginIgnoreEvents(); } public void Dispose() { if (_parent != null) { _parent.EndIgnoreEvents(); _parent = null; } GC.SuppressFinalize(this); } EnumerableCollectionView _parent; } #endregion Private Data } } // 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