Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / MS / Internal / Data / CollectionViewProxy.cs / 1 / CollectionViewProxy.cs
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
// See spec at http://avalon/connecteddata/Specs/CollectionView.mht
//
// Description: Proxy that adds context affinity to an ICollectionView that
// doesn't already have it.
//
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Data;
namespace MS.Internal.Data
{
///
/// Proxy view, used to interpose between the UI and a view that doesn't
/// support context affinity.
///
internal class CollectionViewProxy : CollectionView, IEditableCollectionView, IItemProperties
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
internal CollectionViewProxy(ICollectionView view)
: base(view.SourceCollection, false)
{
_view = view;
view.CollectionChanged += new NotifyCollectionChangedEventHandler(_OnViewChanged);
view.CurrentChanging += new CurrentChangingEventHandler(_OnCurrentChanging);
view.CurrentChanged += new EventHandler(_OnCurrentChanged);
INotifyPropertyChanged ipc = view as INotifyPropertyChanged;
if (ipc != null)
ipc.PropertyChanged += new PropertyChangedEventHandler(_OnPropertyChanged);
}
//------------------------------------------------------
//
// Interfaces
//
//-----------------------------------------------------
#region ICollectionView
///
/// Culture to use during sorting.
///
public override System.Globalization.CultureInfo Culture
{
get { return ProxiedView.Culture; }
set { ProxiedView.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)
{
return ProxiedView.Contains(item);
}
///
/// SourceCollection is the original un-filtered collection of which
/// this ICollectionView is a view.
///
public override IEnumerable SourceCollection
{
get { return base.SourceCollection; }
}
///
/// 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 ProxiedView.Filter; }
set { ProxiedView.Filter = value; }
}
///
/// Test if this ICollectionView supports filtering before assigning
/// a filter callback to .
///
public override bool CanFilter
{
get { return ProxiedView.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 ProxiedView.SortDescriptions; }
}
///
/// Test if this ICollectionView supports sorting before adding
/// to .
///
public override bool CanSort
{
get { return ProxiedView.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 ProxiedView.CanGroup; }
}
///
/// The description of grouping, indexed by level.
///
public override ObservableCollection GroupDescriptions
{
get { return ProxiedView.GroupDescriptions; }
}
///
/// The top-level groups, constructed according to the descriptions
/// given in GroupDescriptions.
///
public override ReadOnlyObservableCollection Groups
{
get { return ProxiedView.Groups; }
}
/// Re-create the view, using any .
public override void Refresh()
{
IndexedEnumerable indexer = (IndexedEnumerable) Interlocked.Exchange(ref _indexer, null);
if (indexer != null)
{
indexer.Invalidate();
}
ProxiedView.Refresh();
}
///
/// Enter a Defer Cycle.
/// Defer cycles are used to coalesce changes to the ICollectionView.
///
public override IDisposable DeferRefresh()
{
return ProxiedView.DeferRefresh();
}
/// Return current item.
public override object CurrentItem
{
get { return ProxiedView.CurrentItem; }
}
///
/// The ordinal position of the within the (optionally
/// sorted and filtered) view.
///
public override int CurrentPosition
{
get { return ProxiedView.CurrentPosition; }
}
/// Return true if currency is beyond the end (End-Of-File).
public override bool IsCurrentAfterLast
{
get { return ProxiedView.IsCurrentAfterLast; }
}
/// Return true if currency is before the beginning (Beginning-Of-File).
public override bool IsCurrentBeforeFirst
{
get { return ProxiedView.IsCurrentBeforeFirst; }
}
/// Move to the first item.
public override bool MoveCurrentToFirst()
{
return ProxiedView.MoveCurrentToFirst();
}
/// Move to the previous item.
public override bool MoveCurrentToPrevious()
{
return ProxiedView.MoveCurrentToPrevious();
}
/// Move to the next item.
public override bool MoveCurrentToNext()
{
return ProxiedView.MoveCurrentToNext();
}
/// Move to the last item.
public override bool MoveCurrentToLast()
{
return ProxiedView.MoveCurrentToLast();
}
/// Move to the given item.
public override bool MoveCurrentTo(object item)
{
return ProxiedView.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
// ProxiedView be the one to make that determination.
//
return ProxiedView.MoveCurrentToPosition(position);
}
public override event CurrentChangingEventHandler CurrentChanging
{
add { PrivateCurrentChanging += value; }
remove { PrivateCurrentChanging -= value; }
}
public override event EventHandler CurrentChanged
{
add { PrivateCurrentChanged += value; }
remove { PrivateCurrentChanged -= value; }
}
#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 { return EnumerableWrapper.Count; }
}
public override bool IsEmpty
{
get { return ProxiedView.IsEmpty; }
}
public ICollectionView ProxiedView
{
get
{
// VerifyAccess();
return _view;
}
}
#endregion Public Properties
//-----------------------------------------------------
//
// Public Methods
//
//------------------------------------------------------
#region Public Methods
/// Return the index where the given de belongs, or -1 if this index is unknown.
/// More precisely, if this returns an index other than -1, it must always be true that
/// view[index-1] < de <= view[index], where the comparisons are done via
/// the view's IComparer.Compare method (if any).
///
/// data item
public override int IndexOf(object item)
{
return EnumerableWrapper.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 (ProxiedView.CanFilter && ProxiedView.Filter != null &&
item != NewItemPlaceholder && item != ((IEditableCollectionView)this).CurrentAddItem)
return ProxiedView.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)
{
// only check lower bound because Count could be expensive
if (index < 0)
throw new ArgumentOutOfRangeException("index");
return EnumerableWrapper[index];
}
#endregion Public Methods
#region IEditableCollectionView
#region Adding new items
///
/// Indicates whether to include a placeholder for a new item, and if so,
/// where to put it.
///
NewItemPlaceholderPosition IEditableCollectionView.NewItemPlaceholderPosition
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.NewItemPlaceholderPosition;
}
else
{
return NewItemPlaceholderPosition.None;
}
}
set
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.NewItemPlaceholderPosition = value;
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "NewItemPlaceholderPosition"));
}
}
}
///
/// Return true if the view supports .
///
bool IEditableCollectionView.CanAddNew
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.CanAddNew;
}
else
{
return false;
}
}
}
///
/// Add a new item to the underlying collection. Returns the new item.
/// After calling AddNew and changing the new item as desired, either
/// or should be
/// called to complete the transaction.
///
object IEditableCollectionView.AddNew()
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.AddNew();
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "AddNew"));
}
}
///
/// Complete the transaction started by . The new
/// item remains in the collection, and the view's sort, filter, and grouping
/// specifications (if any) are applied to the new item.
///
void IEditableCollectionView.CommitNew()
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.CommitNew();
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "CommitNew"));
}
}
///
/// Complete the transaction started by . The new
/// item is removed from the collection.
///
void IEditableCollectionView.CancelNew()
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.CancelNew();
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "CancelNew"));
}
}
///
/// Returns true if an transaction is in progress.
///
bool IEditableCollectionView.IsAddingNew
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.IsAddingNew;
}
else
{
return false;
}
}
}
///
/// When an transaction is in progress, this property
/// returns the new item. Otherwise it returns null.
///
object IEditableCollectionView.CurrentAddItem
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.CurrentAddItem;
}
else
{
return null;
}
}
}
#endregion Adding new items
#region Removing items
///
/// Return true if the view supports and
/// .
///
bool IEditableCollectionView.CanRemove
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.CanRemove;
}
else
{
return false;
}
}
}
///
/// Remove the item at the given index from the underlying collection.
/// The index is interpreted with respect to the view (not with respect to
/// the underlying collection).
///
void IEditableCollectionView.RemoveAt(int index)
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.RemoveAt(index);
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "RemoveAt"));
}
}
///
/// Remove the given item from the underlying collection.
///
void IEditableCollectionView.Remove(object item)
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.Remove(item);
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "Remove"));
}
}
#endregion Removing items
#region Transactional editing of an item
///
/// Begins an editing transaction on the given item. The transaction is
/// completed by calling either or
/// . Any changes made to the item during
/// the transaction are considered "pending", provided that the view supports
/// the notion of "pending changes" for the given item.
///
void IEditableCollectionView.EditItem(object item)
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.EditItem(item);
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "EditItem"));
}
}
///
/// Complete the transaction started by .
/// The pending changes (if any) to the item are committed.
///
void IEditableCollectionView.CommitEdit()
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.CommitEdit();
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "CommitEdit"));
}
}
///
/// Complete the transaction started by .
/// The pending changes (if any) to the item are discarded.
///
void IEditableCollectionView.CancelEdit()
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.CancelEdit();
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "CancelEdit"));
}
}
///
/// Returns true if the view supports the notion of "pending changes" on the
/// current edit item. This may vary, depending on the view and the particular
/// item. For example, a view might return true if the current edit item
/// implements , or if the view has special
/// knowledge about the item that it can use to support rollback of pending
/// changes.
///
bool IEditableCollectionView.CanCancelEdit
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.CanCancelEdit;
}
else
{
return false;
}
}
}
///
/// Returns true if an transaction is in progress.
///
bool IEditableCollectionView.IsEditingItem
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.IsEditingItem;
}
else
{
return false;
}
}
}
///
/// When an transaction is in progress, this property
/// returns the affected item. Otherwise it returns null.
///
object IEditableCollectionView.CurrentEditItem
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.CurrentEditItem;
}
else
{
return null;
}
}
}
#endregion Transactional editing of an item
#endregion IEditableCollectionView
#region IItemProperties
///
/// Returns information about the properties available on items in the
/// underlying collection. This information may come from a schema, from
/// a type descriptor, from a representative item, or from some other source
/// known to the view.
///
ReadOnlyCollection IItemProperties.ItemProperties
{
get
{
IItemProperties iip = ProxiedView as IItemProperties;
if (iip != null)
{
return iip.ItemProperties;
}
else
{
return null;
}
}
}
#endregion IItemProperties
//-----------------------------------------------------
//
// 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() { return ((IEnumerable) ProxiedView).GetEnumerator(); }
#endregion Protected Methods
//-----------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
#region Private Methods
void _OnPropertyChanged(object sender, PropertyChangedEventArgs args)
{
OnPropertyChanged(args);
}
void _OnViewChanged(object sender, NotifyCollectionChangedEventArgs args)
{
// VerifyAccess(); // will throw an exception if caller is not in correct UiContext
OnCollectionChanged(args);
}
void _OnCurrentChanging(object sender, CurrentChangingEventArgs args)
{
// VerifyAccess(); // will throw an exception if caller is not in correct UiContext
if (PrivateCurrentChanging != null)
PrivateCurrentChanging(this, args);
}
void _OnCurrentChanged(object sender, EventArgs args)
{
// VerifyAccess(); // will throw an exception if caller is not in correct UiContext
if (PrivateCurrentChanged != null)
PrivateCurrentChanged(this, args);
}
private IndexedEnumerable EnumerableWrapper
{
get
{
if (_indexer == null)
{
IndexedEnumerable newIndexer = new IndexedEnumerable(ProxiedView, new Predicate(this.PassesFilter));
Interlocked.CompareExchange(ref _indexer, newIndexer, null);
}
return _indexer;
}
}
#endregion Private Methods
//-----------------------------------------------------
//
// Private Fields
//
//------------------------------------------------------
ICollectionView _view;
IndexedEnumerable _indexer;
event CurrentChangingEventHandler PrivateCurrentChanging;
event EventHandler PrivateCurrentChanged;
}
}
// 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.
//
//
// See spec at http://avalon/connecteddata/Specs/CollectionView.mht
//
// Description: Proxy that adds context affinity to an ICollectionView that
// doesn't already have it.
//
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Data;
namespace MS.Internal.Data
{
///
/// Proxy view, used to interpose between the UI and a view that doesn't
/// support context affinity.
///
internal class CollectionViewProxy : CollectionView, IEditableCollectionView, IItemProperties
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
internal CollectionViewProxy(ICollectionView view)
: base(view.SourceCollection, false)
{
_view = view;
view.CollectionChanged += new NotifyCollectionChangedEventHandler(_OnViewChanged);
view.CurrentChanging += new CurrentChangingEventHandler(_OnCurrentChanging);
view.CurrentChanged += new EventHandler(_OnCurrentChanged);
INotifyPropertyChanged ipc = view as INotifyPropertyChanged;
if (ipc != null)
ipc.PropertyChanged += new PropertyChangedEventHandler(_OnPropertyChanged);
}
//------------------------------------------------------
//
// Interfaces
//
//-----------------------------------------------------
#region ICollectionView
///
/// Culture to use during sorting.
///
public override System.Globalization.CultureInfo Culture
{
get { return ProxiedView.Culture; }
set { ProxiedView.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)
{
return ProxiedView.Contains(item);
}
///
/// SourceCollection is the original un-filtered collection of which
/// this ICollectionView is a view.
///
public override IEnumerable SourceCollection
{
get { return base.SourceCollection; }
}
///
/// 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 ProxiedView.Filter; }
set { ProxiedView.Filter = value; }
}
///
/// Test if this ICollectionView supports filtering before assigning
/// a filter callback to .
///
public override bool CanFilter
{
get { return ProxiedView.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 ProxiedView.SortDescriptions; }
}
///
/// Test if this ICollectionView supports sorting before adding
/// to .
///
public override bool CanSort
{
get { return ProxiedView.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 ProxiedView.CanGroup; }
}
///
/// The description of grouping, indexed by level.
///
public override ObservableCollection GroupDescriptions
{
get { return ProxiedView.GroupDescriptions; }
}
///
/// The top-level groups, constructed according to the descriptions
/// given in GroupDescriptions.
///
public override ReadOnlyObservableCollection Groups
{
get { return ProxiedView.Groups; }
}
/// Re-create the view, using any .
public override void Refresh()
{
IndexedEnumerable indexer = (IndexedEnumerable) Interlocked.Exchange(ref _indexer, null);
if (indexer != null)
{
indexer.Invalidate();
}
ProxiedView.Refresh();
}
///
/// Enter a Defer Cycle.
/// Defer cycles are used to coalesce changes to the ICollectionView.
///
public override IDisposable DeferRefresh()
{
return ProxiedView.DeferRefresh();
}
/// Return current item.
public override object CurrentItem
{
get { return ProxiedView.CurrentItem; }
}
///
/// The ordinal position of the within the (optionally
/// sorted and filtered) view.
///
public override int CurrentPosition
{
get { return ProxiedView.CurrentPosition; }
}
/// Return true if currency is beyond the end (End-Of-File).
public override bool IsCurrentAfterLast
{
get { return ProxiedView.IsCurrentAfterLast; }
}
/// Return true if currency is before the beginning (Beginning-Of-File).
public override bool IsCurrentBeforeFirst
{
get { return ProxiedView.IsCurrentBeforeFirst; }
}
/// Move to the first item.
public override bool MoveCurrentToFirst()
{
return ProxiedView.MoveCurrentToFirst();
}
/// Move to the previous item.
public override bool MoveCurrentToPrevious()
{
return ProxiedView.MoveCurrentToPrevious();
}
/// Move to the next item.
public override bool MoveCurrentToNext()
{
return ProxiedView.MoveCurrentToNext();
}
/// Move to the last item.
public override bool MoveCurrentToLast()
{
return ProxiedView.MoveCurrentToLast();
}
/// Move to the given item.
public override bool MoveCurrentTo(object item)
{
return ProxiedView.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
// ProxiedView be the one to make that determination.
//
return ProxiedView.MoveCurrentToPosition(position);
}
public override event CurrentChangingEventHandler CurrentChanging
{
add { PrivateCurrentChanging += value; }
remove { PrivateCurrentChanging -= value; }
}
public override event EventHandler CurrentChanged
{
add { PrivateCurrentChanged += value; }
remove { PrivateCurrentChanged -= value; }
}
#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 { return EnumerableWrapper.Count; }
}
public override bool IsEmpty
{
get { return ProxiedView.IsEmpty; }
}
public ICollectionView ProxiedView
{
get
{
// VerifyAccess();
return _view;
}
}
#endregion Public Properties
//-----------------------------------------------------
//
// Public Methods
//
//------------------------------------------------------
#region Public Methods
/// Return the index where the given de belongs, or -1 if this index is unknown.
/// More precisely, if this returns an index other than -1, it must always be true that
/// view[index-1] < de <= view[index], where the comparisons are done via
/// the view's IComparer.Compare method (if any).
///
/// data item
public override int IndexOf(object item)
{
return EnumerableWrapper.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 (ProxiedView.CanFilter && ProxiedView.Filter != null &&
item != NewItemPlaceholder && item != ((IEditableCollectionView)this).CurrentAddItem)
return ProxiedView.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)
{
// only check lower bound because Count could be expensive
if (index < 0)
throw new ArgumentOutOfRangeException("index");
return EnumerableWrapper[index];
}
#endregion Public Methods
#region IEditableCollectionView
#region Adding new items
///
/// Indicates whether to include a placeholder for a new item, and if so,
/// where to put it.
///
NewItemPlaceholderPosition IEditableCollectionView.NewItemPlaceholderPosition
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.NewItemPlaceholderPosition;
}
else
{
return NewItemPlaceholderPosition.None;
}
}
set
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.NewItemPlaceholderPosition = value;
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "NewItemPlaceholderPosition"));
}
}
}
///
/// Return true if the view supports .
///
bool IEditableCollectionView.CanAddNew
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.CanAddNew;
}
else
{
return false;
}
}
}
///
/// Add a new item to the underlying collection. Returns the new item.
/// After calling AddNew and changing the new item as desired, either
/// or should be
/// called to complete the transaction.
///
object IEditableCollectionView.AddNew()
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.AddNew();
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "AddNew"));
}
}
///
/// Complete the transaction started by . The new
/// item remains in the collection, and the view's sort, filter, and grouping
/// specifications (if any) are applied to the new item.
///
void IEditableCollectionView.CommitNew()
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.CommitNew();
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "CommitNew"));
}
}
///
/// Complete the transaction started by . The new
/// item is removed from the collection.
///
void IEditableCollectionView.CancelNew()
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.CancelNew();
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "CancelNew"));
}
}
///
/// Returns true if an transaction is in progress.
///
bool IEditableCollectionView.IsAddingNew
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.IsAddingNew;
}
else
{
return false;
}
}
}
///
/// When an transaction is in progress, this property
/// returns the new item. Otherwise it returns null.
///
object IEditableCollectionView.CurrentAddItem
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.CurrentAddItem;
}
else
{
return null;
}
}
}
#endregion Adding new items
#region Removing items
///
/// Return true if the view supports and
/// .
///
bool IEditableCollectionView.CanRemove
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.CanRemove;
}
else
{
return false;
}
}
}
///
/// Remove the item at the given index from the underlying collection.
/// The index is interpreted with respect to the view (not with respect to
/// the underlying collection).
///
void IEditableCollectionView.RemoveAt(int index)
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.RemoveAt(index);
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "RemoveAt"));
}
}
///
/// Remove the given item from the underlying collection.
///
void IEditableCollectionView.Remove(object item)
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.Remove(item);
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "Remove"));
}
}
#endregion Removing items
#region Transactional editing of an item
///
/// Begins an editing transaction on the given item. The transaction is
/// completed by calling either or
/// . Any changes made to the item during
/// the transaction are considered "pending", provided that the view supports
/// the notion of "pending changes" for the given item.
///
void IEditableCollectionView.EditItem(object item)
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.EditItem(item);
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "EditItem"));
}
}
///
/// Complete the transaction started by .
/// The pending changes (if any) to the item are committed.
///
void IEditableCollectionView.CommitEdit()
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.CommitEdit();
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "CommitEdit"));
}
}
///
/// Complete the transaction started by .
/// The pending changes (if any) to the item are discarded.
///
void IEditableCollectionView.CancelEdit()
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
ecv.CancelEdit();
}
else
{
throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "CancelEdit"));
}
}
///
/// Returns true if the view supports the notion of "pending changes" on the
/// current edit item. This may vary, depending on the view and the particular
/// item. For example, a view might return true if the current edit item
/// implements , or if the view has special
/// knowledge about the item that it can use to support rollback of pending
/// changes.
///
bool IEditableCollectionView.CanCancelEdit
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.CanCancelEdit;
}
else
{
return false;
}
}
}
///
/// Returns true if an transaction is in progress.
///
bool IEditableCollectionView.IsEditingItem
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.IsEditingItem;
}
else
{
return false;
}
}
}
///
/// When an transaction is in progress, this property
/// returns the affected item. Otherwise it returns null.
///
object IEditableCollectionView.CurrentEditItem
{
get
{
IEditableCollectionView ecv = ProxiedView as IEditableCollectionView;
if (ecv != null)
{
return ecv.CurrentEditItem;
}
else
{
return null;
}
}
}
#endregion Transactional editing of an item
#endregion IEditableCollectionView
#region IItemProperties
///
/// Returns information about the properties available on items in the
/// underlying collection. This information may come from a schema, from
/// a type descriptor, from a representative item, or from some other source
/// known to the view.
///
ReadOnlyCollection IItemProperties.ItemProperties
{
get
{
IItemProperties iip = ProxiedView as IItemProperties;
if (iip != null)
{
return iip.ItemProperties;
}
else
{
return null;
}
}
}
#endregion IItemProperties
//-----------------------------------------------------
//
// 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() { return ((IEnumerable) ProxiedView).GetEnumerator(); }
#endregion Protected Methods
//-----------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
#region Private Methods
void _OnPropertyChanged(object sender, PropertyChangedEventArgs args)
{
OnPropertyChanged(args);
}
void _OnViewChanged(object sender, NotifyCollectionChangedEventArgs args)
{
// VerifyAccess(); // will throw an exception if caller is not in correct UiContext
OnCollectionChanged(args);
}
void _OnCurrentChanging(object sender, CurrentChangingEventArgs args)
{
// VerifyAccess(); // will throw an exception if caller is not in correct UiContext
if (PrivateCurrentChanging != null)
PrivateCurrentChanging(this, args);
}
void _OnCurrentChanged(object sender, EventArgs args)
{
// VerifyAccess(); // will throw an exception if caller is not in correct UiContext
if (PrivateCurrentChanged != null)
PrivateCurrentChanged(this, args);
}
private IndexedEnumerable EnumerableWrapper
{
get
{
if (_indexer == null)
{
IndexedEnumerable newIndexer = new IndexedEnumerable(ProxiedView, new Predicate(this.PassesFilter));
Interlocked.CompareExchange(ref _indexer, newIndexer, null);
}
return _indexer;
}
}
#endregion Private Methods
//-----------------------------------------------------
//
// Private Fields
//
//------------------------------------------------------
ICollectionView _view;
IndexedEnumerable _indexer;
event CurrentChangingEventHandler PrivateCurrentChanging;
event EventHandler PrivateCurrentChanged;
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.