using System; using System.Collections.Generic; using System.Collections; using System.Diagnostics; using System.Runtime.InteropServices; using System.ComponentModel; namespace DevComponents.DotNetBar.Primitives { /// /// Represents custom collection with INotifyPropertyChanged and INotifyCollectionChanged interface support. /// /// [Serializable, DebuggerDisplay("Count = {Count}"), ComVisible(false)] public class CustomCollection : IList, IList, INotifyPropertyChanged, INotifyCollectionChanged { #region Events /// /// Occurs when property value has changed. /// public event PropertyChangedEventHandler PropertyChanged; #endregion #region Private variables private SimpleMonitor _monitor; private object _SyncRoot; private readonly IList _Items; private bool _FloatLastItem; #endregion #region Constructors /// /// Creates new instance of object. /// public CustomCollection() { _monitor = new SimpleMonitor(); _Items = new List(); } public void Dispose() { _monitor.Dispose(); } /// /// Creates new instance of object. /// public CustomCollection(int capacity) { _monitor = new SimpleMonitor(); _Items = new List(capacity); } /// /// Creates new instance of object. /// /// List to initialize collection with. public CustomCollection(IList list) { if (list == null) throw new ArgumentNullException("list"); _monitor = new SimpleMonitor(); _Items = list; } #endregion #region Add /// /// Add item to collection. /// /// Item to add. public void Add(T item) { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); InsertItem(_Items.Count, item); } #endregion #region Sort // // Summary: // Sorts the elements in the entire collection using // the default comparer. // // Exceptions: // System.InvalidOperationException: // The default comparer System.Collections.Generic.Comparer.Default cannot // find an implementation of the System.IComparable generic interface or // the System.IComparable interface for type T. public void Sort() { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); if(!(_Items is List)) throw new NotSupportedException("collection must be default List collection"); ((List)_Items).Sort(); OnCollectionChanged(NotifyCollectionChangedAction.Reset, null, -1); } // // Summary: // Reverse sorts the elements in the entire collection. // public void SortReverse() { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); if (!(_Items is List)) throw new NotSupportedException("collection must be default List collection"); ((List)_Items).Sort(); ((List)_Items).Reverse(); OnCollectionChanged(NotifyCollectionChangedAction.Reset, null, -1); } // // Summary: // Sorts the elements in the entire collection using // the specified System.Comparison. // // Parameters: // comparison: // The System.Comparison to use when comparing elements. // // Exceptions: // System.ArgumentNullException: // comparison is null. // // System.ArgumentException: // The implementation of comparison caused an error during the sort. For example, // comparison might not return 0 when comparing an item with itself. public void Sort(Comparison comparison) { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); if (!(_Items is List)) throw new NotSupportedException("collection must be default List collection"); ((List)_Items).Sort(comparison); OnCollectionChanged(NotifyCollectionChangedAction.Reset, null, -1); } // // Summary: // Sorts the elements in the entire System.Collections.Generic.List using // the specified comparer. // // Parameters: // comparer: // The System.Collections.Generic.IComparer implementation to use when comparing // elements, or null to use the default comparer System.Collections.Generic.Comparer.Default. // // Exceptions: // System.InvalidOperationException: // comparer is null, and the default comparer System.Collections.Generic.Comparer.Default // cannot find implementation of the System.IComparable generic interface // or the System.IComparable interface for type T. // // System.ArgumentException: // The implementation of comparer caused an error during the sort. For example, // comparer might not return 0 when comparing an item with itself. public void Sort(IComparer comparer) { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); if (!(_Items is List)) throw new NotSupportedException("collection must be default List collection"); ((List)_Items).Sort(comparer); OnCollectionChanged(NotifyCollectionChangedAction.Reset, null, -1); } // // Summary: // Sorts the elements in a range of elements in System.Collections.Generic.List // using the specified comparer. // // Parameters: // index: // The zero-based starting index of the range to sort. // // count: // The length of the range to sort. // // comparer: // The System.Collections.Generic.IComparer implementation to use when comparing // elements, or null to use the default comparer System.Collections.Generic.Comparer.Default. // // Exceptions: // System.ArgumentOutOfRangeException: // index is less than 0.-or-count is less than 0. // // System.ArgumentException: // index and count do not specify a valid range in the System.Collections.Generic.List.-or-The // implementation of comparer caused an error during the sort. For example, // comparer might not return 0 when comparing an item with itself. // // System.InvalidOperationException: // comparer is null, and the default comparer System.Collections.Generic.Comparer.Default // cannot find implementation of the System.IComparable generic interface // or the System.IComparable interface for type T. public void Sort(int index, int count, IComparer comparer) { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); if (!(_Items is List)) throw new NotSupportedException("collection must be default List collection"); ((List)_Items).Sort(index, count, comparer); OnCollectionChanged(NotifyCollectionChangedAction.Reset, null, -1); } #endregion #region Clear /// /// Remove all items from collection. /// public void Clear() { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); ClearItems(); } /// /// Remove all items from collection. /// protected virtual void ClearItems() { CheckReentrancy(); T item = default(T); if (_FloatLastItem == true) { if (_Items.Count > 0) item = _Items[_Items.Count - 1]; } _Items.Clear(); OnPropertyChanged(new PropertyChangedEventArgs(CountString)); OnPropertyChanged(new PropertyChangedEventArgs(ItemString)); OnCollectionReset(); if (_FloatLastItem == true) _Items.Add(item); } #endregion #region Contains /// /// Checks whether collection contains item. /// /// Item to look for. /// true if item is in collection. public bool Contains(T item) { OnCollectionReadAccess(); return (_Items.Contains(item)); } #endregion #region CopyTo /// /// Copy collection to array. /// /// Array to copy to. /// Index to copy from. public void CopyTo(T[] array, int index) { OnCollectionReadAccess(); _Items.CopyTo(array, index); } /// /// Copy collection to array. /// /// Array to copy to. public void CopyTo(T[] array) { CopyTo(array, 0); } #endregion #region Count /// /// Returns number of items in collection. /// public int Count { get { OnCollectionReadAccess(); return (_Items.Count); } } #endregion #region CountString private string CountString { get { return ("Count"); } } #endregion #region FloatLastItem internal bool FloatLastItem { get { return (_FloatLastItem); } set { _FloatLastItem = value; } } #endregion #region GetEnumerator /// /// Gets enumerator for collection. /// /// Enumerator. public IEnumerator GetEnumerator() { OnCollectionReadAccess(); return (_Items.GetEnumerator()); } #endregion #region Indexer[int] /// /// Returns item at index. /// /// Index of item. /// Item at index. public T this[int index] { get { OnCollectionReadAccess(); return (_Items[index]); } set { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); if ((index < 0) || (index >= _Items.Count)) throw new ArgumentOutOfRangeException(); SetItem(index, value); } } #endregion #region IndexOf /// /// Returns index of an item. /// /// Reference to item. /// Index of item. public int IndexOf(T item) { OnCollectionReadAccess(); return (_Items.IndexOf(item)); } #endregion #region Insert /// /// Insert item at specified location. /// /// Index to insert item in. /// Item to insert. public void Insert(int index, T item) { if ((index < 0) || (index > this._Items.Count)) throw new ArgumentOutOfRangeException("index"); InsertItem(index, item); } #endregion #region InsertItem /// /// Inserts item. /// /// Index to insert item at. /// Reference to item. protected virtual void InsertItem(int index, T item) { CheckReentrancy(); if (_FloatLastItem == true) { if (_Items.Count > 0 && index == _Items.Count) index--; } _Items.Insert(index, item); OnPropertyChanged(new PropertyChangedEventArgs(CountString)); OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index); } #endregion #region IsCompatibleObject private static bool IsCompatibleObject(object value) { return (value is T) || (value == null && !typeof(T).IsValueType); } #endregion #region ItemString private string ItemString { get { return ("Item[]"); } } #endregion #region Remove /// /// Removes item from collection. /// /// Item to remove. /// true if item was removed. public bool Remove(T item) { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); int index = _Items.IndexOf(item); if (index < 0) return (false); RemoveItem(index); return (true); } #endregion #region RemoveAt /// /// Remove item at specified location. /// /// Index of item to remove. public void RemoveAt(int index) { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); if ((index < 0) || (index >= _Items.Count)) throw new ArgumentOutOfRangeException(); RemoveItem(index); } #endregion #region RemoveItem /// /// Remove item at specified location. /// /// Index of item to remove. protected virtual void RemoveItem(int index) { CheckReentrancy(); object item = _Items[index]; _Items.RemoveAt(index); OnPropertyChanged(new PropertyChangedEventArgs(CountString)); OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index); } #endregion #region SetItem /// /// Set item on location. /// /// Index /// Item to assign. protected virtual void SetItem(int index, T item) { CheckReentrancy(); T oldItem = _Items[index]; _Items[index] = item; OnPropertyChanged(new PropertyChangedEventArgs(CountString)); OnPropertyChanged(new PropertyChangedEventArgs(ItemString)); OnCollectionChanged(NotifyCollectionChangedAction.Replace, oldItem, item, index); } #endregion #region IList support #region Add int IList.Add(object value) { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); VerifyValueType(value); Add((T)value); return (Count - 1); } #endregion #region Contains bool IList.Contains(object value) { return (IsCompatibleObject(value) && Contains((T)value)); } #endregion #region GetItemsDirect /// /// Returns items directly without checks. /// /// List of items. protected IList GetItemsDirect() { return (_Items); } #endregion #region Indexer[int] object IList.this[int index] { get { OnCollectionReadAccess(); return this._Items[index]; } set { VerifyValueType(value); this[index] = (T)value; } } #region IndexOf int IList.IndexOf(object value) { OnCollectionReadAccess(); return (IsCompatibleObject(value) ? IndexOf((T)value) : -1); } #endregion #region Insert void IList.Insert(int index, object value) { if (this._Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); VerifyValueType(value); Insert(index, (T)value); } #endregion #region IsFixedSize bool IList.IsFixedSize { get { IList items = _Items as IList; return ((items != null) && items.IsFixedSize); } } #endregion #region IsReadOnly bool IList.IsReadOnly { get { return (_Items.IsReadOnly); } } #endregion #region Items /// /// Returns the IList interface for items in collection. /// protected IList Items { get { OnCollectionReadAccess(); return (_Items); } } #endregion #region Remove void IList.Remove(object value) { if (_Items.IsReadOnly) throw new NotSupportedException("collection is read-only"); if (IsCompatibleObject(value)) Remove((T)value); } #endregion #endregion #region VerifyValueType private static void VerifyValueType(object value) { if (!IsCompatibleObject(value)) throw new ArgumentException("value is of wrong type"); } #endregion #endregion #region IEnumerable.GetEnumerator IEnumerator IEnumerable.GetEnumerator() { OnCollectionReadAccess(); return (_Items.GetEnumerator()); } #endregion #region ICollection support #region CopyTo void ICollection.CopyTo(Array array, int index) { CheckReentrancy(); OnCollectionReadAccess(); if (array == null) throw new ArgumentNullException("array"); if (array.Rank != 1) throw new ArgumentException("Argument array.Rank multi-dimensional not supported"); if (array.GetLowerBound(0) != 0) throw new ArgumentException("Argument array non zero lower bound not supported"); if (index < 0) throw new ArgumentOutOfRangeException("index", "index must be non-negative number"); if ((array.Length - index) < this.Count) throw new ArgumentException("array too small"); T[] localArray = array as T[]; if (localArray != null) { _Items.CopyTo(localArray, index); } else { Type elementType = array.GetType().GetElementType(); Type c = typeof(T); if (elementType == null || (!elementType.IsAssignableFrom(c) && !c.IsAssignableFrom(elementType))) { throw new ArgumentException("Argument array of invalid type"); } object[] objArray = array as object[]; if (objArray == null) throw new ArgumentException("Argument array invalid type"); int count = this._Items.Count; try { for (int i = 0; i < count; i++) objArray[index++] = this._Items[i]; } catch (ArrayTypeMismatchException) { throw new ArgumentException("Argument array invalid type"); } } } #endregion #region IsSynchronized bool ICollection.IsSynchronized { get { return false; } } #endregion #region IsReadOnly bool ICollection.IsReadOnly { get { return this._Items.IsReadOnly; } } #endregion #region SyncRoot object ICollection.SyncRoot { get { if (_SyncRoot == null) { ICollection items = _Items as ICollection; if (items != null) _SyncRoot = items.SyncRoot; else System.Threading.Interlocked.CompareExchange(ref _SyncRoot, new object(), null); } return (_SyncRoot); } } #endregion #endregion #region OnCollectionReadAccess /// /// Occurs when collection is read. /// protected virtual void OnCollectionReadAccess() { } #endregion #region OnPropertyChanged /// /// Occurs when collection property has changed. /// /// Event arguments. protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) PropertyChanged(this, e); } #endregion #region BlockReentrancy /// /// Blocks the collection reentrancy. /// /// IDisposable to end re-entrancy protected IDisposable BlockReentrancy() { _monitor.Enter(); return (_monitor); } #endregion #region CheckReentrancy /// /// Checks whether call creates reentrancy. /// protected void CheckReentrancy() { if ((_monitor.Busy && (CollectionChanged != null)) && (CollectionChanged.GetInvocationList().Length > 1)) { throw new InvalidOperationException("CustomCollectionReentrancyNotAllowed"); } } #endregion #region SimpleMonitor [Serializable] private class SimpleMonitor : IDisposable { // Fields private int _BusyCount; // Methods public void Dispose() { _BusyCount--; } public void Enter() { _BusyCount++; } // Properties public bool Busy { get { return (_BusyCount > 0); } } } #endregion #region INotifyCollectionChanged Members /// /// Occurs when collection has changed. /// public event NotifyCollectionChangedEventHandler CollectionChanged; private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index) { this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index)); } private void OnCollectionChanged(NotifyCollectionChangedAction action, object oldItem, object newItem, int index) { this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index)); } private void OnCollectionReset() { this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } /// /// Called when collection has changed. /// /// Event arguments. protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (this.CollectionChanged != null) { using (this.BlockReentrancy()) { this.CollectionChanged(this, e); } } } #endregion } #region INotifyCollectionChanged /// /// Represents collection changed notification interface. /// public interface INotifyCollectionChanged { /// /// Occurs when collection changed. /// event NotifyCollectionChangedEventHandler CollectionChanged; } /// /// Defines change actions. /// public enum NotifyCollectionChangedAction { /// /// Items were added. /// Add, /// /// Items were removed. /// Remove, /// /// Items were replaced. /// Replace, /// /// Items were moved. /// Move, /// /// Collection was reset. /// Reset } /// /// Defines delegate for collection notification events. /// /// Event sender. /// Event arguments. public delegate void NotifyCollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs e); /// /// Defines collection change notification event arguments. /// public class NotifyCollectionChangedEventArgs : EventArgs { #region Private Vars private NotifyCollectionChangedAction _Action; private IList _NewItems; private int _NewStartingIndex; private IList _OldItems; private int _OldStartingIndex; #endregion /// /// Create new instance of object. /// /// Action public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (action != NotifyCollectionChangedAction.Reset) { throw new ArgumentException("WrongActionForCtor"); } this.InitializeAdd(action, null, -1); } /// /// Creates new instance of object. /// /// Specifies action. /// List of changed items. public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset)) { throw new ArgumentException("MustBeResetAddOrRemoveActionForCtor"); } if (action == NotifyCollectionChangedAction.Reset) { if (changedItems != null) { throw new ArgumentException("ResetActionRequiresNullItem"); } this.InitializeAdd(action, null, -1); } else { if (changedItems == null) { throw new ArgumentNullException("changedItems"); } this.InitializeAddOrRemove(action, changedItems, -1); } } /// /// Creates new instance of object. /// /// Specifies action. /// Item that was changed. public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset)) { throw new ArgumentException("MustBeResetAddOrRemoveActionForCtor"); } if (action == NotifyCollectionChangedAction.Reset) { if (changedItem != null) { throw new ArgumentException("ResetActionRequiresNullItem"); } this.InitializeAdd(action, null, -1); } else { this.InitializeAddOrRemove(action, new object[] { changedItem }, -1); } } /// /// Creates new instance of object. /// /// Action. /// New items in collection. /// Old items in collection. public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (action != NotifyCollectionChangedAction.Replace) { throw new ArgumentException("WrongActionForCtor"); } if (newItems == null) { throw new ArgumentNullException("newItems"); } if (oldItems == null) { throw new ArgumentNullException("oldItems"); } this.InitializeMoveOrReplace(action, newItems, oldItems, -1, -1); } /// /// Creates new instance of object. /// /// Action. /// List of changed items. /// Starting index of change. public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int startingIndex) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset)) { throw new ArgumentException("MustBeResetAddOrRemoveActionForCtor"); } if (action == NotifyCollectionChangedAction.Reset) { if (changedItems != null) { throw new ArgumentException("ResetActionRequiresNullItem"); } if (startingIndex != -1) { throw new ArgumentException("ResetActionRequiresIndexMinus1"); } this.InitializeAdd(action, null, -1); } else { if (changedItems == null) { throw new ArgumentNullException("changedItems"); } if (startingIndex < -1) { throw new ArgumentException("IndexCannotBeNegative"); } this.InitializeAddOrRemove(action, changedItems, startingIndex); } } /// /// Creates new instance of object. /// /// Action /// Changed item /// Index of change public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset)) { throw new ArgumentException("MustBeResetAddOrRemoveActionForCtor"); } if (action == NotifyCollectionChangedAction.Reset) { if (changedItem != null) { throw new ArgumentException("ResetActionRequiresNullItem"); } if (index != -1) { throw new ArgumentException("ResetActionRequiresIndexMinus1"); } this.InitializeAdd(action, null, -1); } else { this.InitializeAddOrRemove(action, new object[] { changedItem }, index); } } /// /// Creates new instance of object. /// /// Action /// New item /// Old item public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (action != NotifyCollectionChangedAction.Replace) { throw new ArgumentException("WrongActionForCtor"); } this.InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, -1, -1); } /// /// Creates new instance of object. /// /// Action /// New items. /// Removed items. /// Starting index of change. public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (action != NotifyCollectionChangedAction.Replace) { throw new ArgumentException("WrongActionForCtor"); } if (newItems == null) { throw new ArgumentNullException("newItems"); } if (oldItems == null) { throw new ArgumentNullException("oldItems"); } this.InitializeMoveOrReplace(action, newItems, oldItems, startingIndex, startingIndex); } /// /// Creates new instance of object. /// /// Action /// Changed items /// New index /// Old index public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int index, int oldIndex) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (action != NotifyCollectionChangedAction.Move) { throw new ArgumentException("WrongActionForCtor"); } if (index < 0) { throw new ArgumentException("IndexCannotBeNegative"); } this.InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex); } /// /// Creates new instance of object. /// /// Action /// Changed item /// New index /// Old index public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index, int oldIndex) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (action != NotifyCollectionChangedAction.Move) { throw new ArgumentException("WrongActionForCtor"); } if (index < 0) { throw new ArgumentException("IndexCannotBeNegative"); } object[] newItems = new object[] { changedItem }; this.InitializeMoveOrReplace(action, newItems, newItems, index, oldIndex); } /// /// Creates new instance of object. /// /// Action. /// New item /// Old item /// New index public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem, int index) { this._NewStartingIndex = -1; this._OldStartingIndex = -1; if (action != NotifyCollectionChangedAction.Replace) { throw new ArgumentException("WrongActionForCtor"); } this.InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, index, index); } private void InitializeAdd(NotifyCollectionChangedAction action, IList newItems, int newStartingIndex) { this._Action = action; this._NewItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems); this._NewStartingIndex = newStartingIndex; } private void InitializeAddOrRemove(NotifyCollectionChangedAction action, IList changedItems, int startingIndex) { if (action == NotifyCollectionChangedAction.Add) { this.InitializeAdd(action, changedItems, startingIndex); } else if (action == NotifyCollectionChangedAction.Remove) { this.InitializeRemove(action, changedItems, startingIndex); } } private void InitializeMoveOrReplace(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex, int oldStartingIndex) { this.InitializeAdd(action, newItems, startingIndex); this.InitializeRemove(action, oldItems, oldStartingIndex); } private void InitializeRemove(NotifyCollectionChangedAction action, IList oldItems, int oldStartingIndex) { this._Action = action; this._OldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems); this._OldStartingIndex = oldStartingIndex; } /// /// Gets the type of the collection change action. /// public NotifyCollectionChangedAction Action { get { return this._Action; } } /// /// Gets list of newly added items. /// public IList NewItems { get { return this._NewItems; } } /// /// Gets new starting index. /// public int NewStartingIndex { get { return this._NewStartingIndex; } } /// /// Gets list of removed items. /// public IList OldItems { get { return this._OldItems; } } /// /// Old starting index. /// public int OldStartingIndex { get { return this._OldStartingIndex; } } } #endregion }