28 changed files with 640 additions and 579 deletions
@ -1,153 +0,0 @@
@@ -1,153 +0,0 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
using System.Collections.ObjectModel; |
||||
using System.Collections.Specialized; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Dom |
||||
{ |
||||
/// <summary>
|
||||
/// A <see cref="IModelCollection{T}"/> that works by concatening multiple
|
||||
/// other model collections.
|
||||
/// </summary>
|
||||
public sealed class ConcatModelCollection<T> : IModelCollection<T> |
||||
{ |
||||
sealed class InputCollection : Collection<IModelCollection<T>> |
||||
{ |
||||
readonly ConcatModelCollection<T> owner; |
||||
|
||||
public InputCollection(ConcatModelCollection<T> owner) |
||||
{ |
||||
this.owner = owner; |
||||
} |
||||
|
||||
protected override void ClearItems() |
||||
{ |
||||
if (owner.collectionChanged != null) { |
||||
foreach (var input in Items) { |
||||
input.CollectionChanged -= owner.OnInputCollectionChanged; |
||||
} |
||||
} |
||||
base.ClearItems(); |
||||
owner.RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); |
||||
} |
||||
|
||||
protected override void InsertItem(int index, IModelCollection<T> item) |
||||
{ |
||||
if (owner.collectionChanged != null) |
||||
item.CollectionChanged += owner.OnInputCollectionChanged; |
||||
base.InsertItem(index, item); |
||||
owner.RaiseCollectionChanged(new NotifyCollectionChangedEventArgs( |
||||
NotifyCollectionChangedAction.Add, item.ToArray(), owner.GetCount(index))); |
||||
} |
||||
|
||||
protected override void RemoveItem(int index) |
||||
{ |
||||
if (owner.collectionChanged != null) |
||||
Items[index].CollectionChanged -= owner.OnInputCollectionChanged; |
||||
var oldItems = Items[index].ToArray(); |
||||
base.RemoveItem(index); |
||||
owner.RaiseCollectionChanged(new NotifyCollectionChangedEventArgs( |
||||
NotifyCollectionChangedAction.Remove, oldItems, owner.GetCount(index))); |
||||
} |
||||
|
||||
protected override void SetItem(int index, IModelCollection<T> item) |
||||
{ |
||||
RemoveItem(index); |
||||
InsertItem(index, item); |
||||
} |
||||
} |
||||
|
||||
InputCollection inputs; |
||||
|
||||
public ConcatModelCollection() |
||||
{ |
||||
this.inputs = new InputCollection(this); |
||||
} |
||||
|
||||
public IList<IModelCollection<T>> Inputs { |
||||
get { return inputs; } |
||||
} |
||||
|
||||
NotifyCollectionChangedEventHandler collectionChanged; |
||||
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged { |
||||
add { |
||||
var oldEventHandlers = collectionChanged; |
||||
collectionChanged += value; |
||||
if (oldEventHandlers == null && collectionChanged != null) { |
||||
foreach (var input in inputs) |
||||
input.CollectionChanged += OnInputCollectionChanged; |
||||
} |
||||
} |
||||
remove { |
||||
var oldEventHandlers = collectionChanged; |
||||
collectionChanged -= value; |
||||
if (oldEventHandlers != null && collectionChanged == null) { |
||||
foreach (var input in inputs) |
||||
input.CollectionChanged -= OnInputCollectionChanged; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e) |
||||
{ |
||||
if (collectionChanged != null) |
||||
collectionChanged(this, e); |
||||
} |
||||
|
||||
void OnInputCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||
{ |
||||
int inputIndex = inputs.IndexOf((IModelCollection<T>)sender); |
||||
int startIndex = GetCount(inputIndex); |
||||
NotifyCollectionChangedEventArgs newEventArgs; |
||||
switch (e.Action) { |
||||
case NotifyCollectionChangedAction.Add: |
||||
newEventArgs = new NotifyCollectionChangedEventArgs(e.Action, e.NewItems, startIndex + e.NewStartingIndex); |
||||
break; |
||||
case NotifyCollectionChangedAction.Remove: |
||||
newEventArgs = new NotifyCollectionChangedEventArgs(e.Action, e.OldItems, startIndex + e.OldStartingIndex); |
||||
break; |
||||
case NotifyCollectionChangedAction.Replace: |
||||
newEventArgs = new NotifyCollectionChangedEventArgs(e.Action, e.OldItems, e.NewItems, startIndex + e.OldStartingIndex); |
||||
break; |
||||
case NotifyCollectionChangedAction.Move: |
||||
newEventArgs = new NotifyCollectionChangedEventArgs(e.Action, e.OldItems, startIndex + e.OldStartingIndex, startIndex + e.NewStartingIndex); |
||||
break; |
||||
case NotifyCollectionChangedAction.Reset: |
||||
newEventArgs = new NotifyCollectionChangedEventArgs(e.Action); |
||||
break; |
||||
default: |
||||
throw new NotSupportedException("Invalid value for NotifyCollectionChangedAction"); |
||||
} |
||||
collectionChanged(this, newEventArgs); |
||||
} |
||||
|
||||
public int Count { |
||||
get { return GetCount(inputs.Count); } |
||||
} |
||||
|
||||
int GetCount(int inputIndex) |
||||
{ |
||||
int count = 0; |
||||
for (int i = 0; i < inputIndex; i++) { |
||||
count += inputs[i].Count; |
||||
} |
||||
return count; |
||||
} |
||||
|
||||
public IEnumerator<T> GetEnumerator() |
||||
{ |
||||
return inputs.SelectMany(i => i).GetEnumerator(); |
||||
} |
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() |
||||
{ |
||||
return GetEnumerator(); |
||||
} |
||||
} |
||||
} |
||||
@ -1,104 +0,0 @@
@@ -1,104 +0,0 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
using System.Collections.Specialized; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Dom |
||||
{ |
||||
/// <summary>
|
||||
/// A model collection that filters an input collection.
|
||||
/// </summary>
|
||||
public sealed class FilterModelCollection<T> : IModelCollection<T> |
||||
{ |
||||
readonly IModelCollection<T> input; |
||||
readonly Func<T, bool> predicate; |
||||
bool isAttached; |
||||
NotifyCollectionChangedEventHandler collectionChanged; |
||||
|
||||
public FilterModelCollection(IModelCollection<T> input, Func<T, bool> predicate) |
||||
{ |
||||
if (input == null) |
||||
throw new ArgumentNullException("input"); |
||||
if (predicate == null) |
||||
throw new ArgumentNullException("predicate"); |
||||
this.input = input; |
||||
this.predicate = predicate; |
||||
} |
||||
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged { |
||||
add { |
||||
collectionChanged += value; |
||||
if (collectionChanged != null && !isAttached) { |
||||
input.CollectionChanged += input_CollectionChanged; |
||||
isAttached = true; |
||||
} |
||||
} |
||||
remove { |
||||
collectionChanged -= value; |
||||
if (collectionChanged == null && isAttached) { |
||||
input.CollectionChanged -= input_CollectionChanged; |
||||
isAttached = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void input_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||
{ |
||||
switch (e.Action) { |
||||
case NotifyCollectionChangedAction.Add: |
||||
collectionChanged(this, new NotifyCollectionChangedEventArgs( |
||||
NotifyCollectionChangedAction.Add, ApplyFilter(e.NewItems))); |
||||
break; |
||||
case NotifyCollectionChangedAction.Remove: |
||||
collectionChanged(this, new NotifyCollectionChangedEventArgs( |
||||
NotifyCollectionChangedAction.Remove, ApplyFilter(e.OldItems))); |
||||
break; |
||||
case NotifyCollectionChangedAction.Replace: |
||||
collectionChanged(this, new NotifyCollectionChangedEventArgs( |
||||
NotifyCollectionChangedAction.Replace, ApplyFilter(e.OldItems), ApplyFilter(e.NewItems))); |
||||
break; |
||||
case NotifyCollectionChangedAction.Move: |
||||
// this collection is unordered
|
||||
break; |
||||
case NotifyCollectionChangedAction.Reset: |
||||
collectionChanged(this, new NotifyCollectionChangedEventArgs( |
||||
NotifyCollectionChangedAction.Reset)); |
||||
break; |
||||
default: |
||||
throw new NotSupportedException(); |
||||
} |
||||
} |
||||
|
||||
IList ApplyFilter(IList inputItems) |
||||
{ |
||||
if (inputItems == null) |
||||
return null; |
||||
List<T> outputItems = new List<T>(); |
||||
foreach (T item in inputItems) { |
||||
if (predicate(item)) |
||||
outputItems.Add(item); |
||||
} |
||||
return outputItems; |
||||
} |
||||
|
||||
public int Count { |
||||
get { |
||||
return input.Count(predicate); |
||||
} |
||||
} |
||||
|
||||
public IEnumerator<T> GetEnumerator() |
||||
{ |
||||
return input.Where(predicate).GetEnumerator(); |
||||
} |
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() |
||||
{ |
||||
return GetEnumerator(); |
||||
} |
||||
} |
||||
} |
||||
@ -1,54 +0,0 @@
@@ -1,54 +0,0 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.ObjectModel; |
||||
using System.Collections.Specialized; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Dom |
||||
{ |
||||
/// <summary>
|
||||
/// Observable KeyedCollection.
|
||||
/// </summary>
|
||||
public abstract class KeyedModelCollection<TKey, TItem> : KeyedCollection<TKey, TItem>, IModelCollection<TItem> |
||||
{ |
||||
// TODO: do we still need this class? maybe we should remove it?
|
||||
|
||||
public bool TryGetValue(TKey key, out TItem item) |
||||
{ |
||||
return Dictionary.TryGetValue(key, out item); |
||||
} |
||||
|
||||
protected override void ClearItems() |
||||
{ |
||||
base.ClearItems(); |
||||
if (CollectionChanged != null) |
||||
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); |
||||
} |
||||
|
||||
protected override void InsertItem(int index, TItem item) |
||||
{ |
||||
base.InsertItem(index, item); |
||||
if (CollectionChanged != null) |
||||
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); |
||||
} |
||||
|
||||
protected override void RemoveItem(int index) |
||||
{ |
||||
var oldItem = Items[index]; |
||||
base.RemoveItem(index); |
||||
if (CollectionChanged != null) |
||||
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItem, index)); |
||||
} |
||||
|
||||
protected override void SetItem(int index, TItem item) |
||||
{ |
||||
var oldItem = Items[index]; |
||||
base.SetItem(index, item); |
||||
if (CollectionChanged != null) |
||||
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItem, index)); |
||||
} |
||||
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged; |
||||
} |
||||
} |
||||
@ -0,0 +1,191 @@
@@ -0,0 +1,191 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Collections.ObjectModel; |
||||
using System.Linq; |
||||
using System.Runtime.InteropServices.WindowsRuntime; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Dom |
||||
{ |
||||
/// <summary>
|
||||
/// Provides LINQ operators for .
|
||||
/// </summary>
|
||||
public static class ModelCollectionLinq |
||||
{ |
||||
// A general 'AsObservableCollection()' would be nice; but I don't see any good way
|
||||
// to implement that without leaking memory.
|
||||
// The problem is that IModelCollection is unordered; but ObservableCollection requires us to maintain a stable order.
|
||||
|
||||
#region Where
|
||||
/*public static IModelCollection<TSource> Where<TSource>(this IModelCollection<TSource> source, Func<TSource, bool> predicate) |
||||
{ |
||||
|
||||
}*/ |
||||
#endregion
|
||||
|
||||
#region Select
|
||||
public static IModelCollection<TResult> Select<TSource, TResult>(this IModelCollection<TSource> source, Func<TSource, TResult> selector) |
||||
{ |
||||
// HACK: emulating Select with SelectMany is much less efficient than a direct implementation could be
|
||||
return SelectMany(source, item => new ReadOnlyModelCollection<TSource>(new[] { item }), (a, b) => selector(b)); |
||||
} |
||||
#endregion
|
||||
|
||||
#region SelectMany
|
||||
public static IModelCollection<S> SelectMany<T, S>(this IModelCollection<T> input, Func<T, IModelCollection<S>> selector) |
||||
{ |
||||
return SelectMany(input, selector, (a, b) => b); |
||||
} |
||||
|
||||
public static IModelCollection<TResult> SelectMany<TSource, TCollection, TResult>(this IModelCollection<TSource> source, Func<TSource, IModelCollection<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector) |
||||
{ |
||||
if (source == null) |
||||
throw new ArgumentNullException("source"); |
||||
if (collectionSelector == null) |
||||
throw new ArgumentNullException("collectionSelector"); |
||||
if (resultSelector == null) |
||||
throw new ArgumentNullException("resultSelector"); |
||||
return new SelectManyModelCollection<TSource, TCollection, TResult>(source, collectionSelector, resultSelector); |
||||
} |
||||
|
||||
sealed class SelectManyModelCollection<TSource, TCollection, TResult> : IModelCollection<TResult> |
||||
{ |
||||
readonly IModelCollection<TSource> source; |
||||
readonly Func<TSource, IModelCollection<TCollection>> collectionSelector; |
||||
readonly Func<TSource, TCollection, TResult> resultSelector; |
||||
List<InputCollection> inputCollections; |
||||
|
||||
public SelectManyModelCollection(IModelCollection<TSource> source, Func<TSource, IModelCollection<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector) |
||||
{ |
||||
this.source = source; |
||||
this.collectionSelector = collectionSelector; |
||||
this.resultSelector = resultSelector; |
||||
} |
||||
|
||||
ModelCollectionChangedEventHandler<TResult> collectionChanged; |
||||
|
||||
public event ModelCollectionChangedEventHandler<TResult> CollectionChanged { |
||||
add { |
||||
if (value == null) |
||||
return; |
||||
if (inputCollections == null) { |
||||
source.CollectionChanged += OnSourceCollectionChanged; |
||||
inputCollections = new List<InputCollection>(); |
||||
foreach (var item in source) { |
||||
var inputCollection = new InputCollection(this, item); |
||||
inputCollection.RegisterEvent(); |
||||
inputCollections.Add(inputCollection); |
||||
} |
||||
} |
||||
collectionChanged += value; |
||||
} |
||||
remove { |
||||
if (collectionChanged == null) |
||||
return; |
||||
collectionChanged -= value; |
||||
if (collectionChanged == null) { |
||||
source.CollectionChanged -= OnSourceCollectionChanged; |
||||
foreach (var inputCollection in inputCollections) { |
||||
inputCollection.UnregisterEvent(); |
||||
} |
||||
inputCollections = null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void OnCollectionChanged(IReadOnlyCollection<TResult> removedItems, IReadOnlyCollection<TResult> addedItems) |
||||
{ |
||||
if (collectionChanged != null) |
||||
collectionChanged(removedItems, addedItems); |
||||
} |
||||
|
||||
void OnSourceCollectionChanged(IReadOnlyCollection<TSource> removedItems, IReadOnlyCollection<TSource> addedItems) |
||||
{ |
||||
List<TResult> removedResults = new List<TResult>(); |
||||
foreach (TSource removedSource in removedItems) { |
||||
for (int i = 0; i < inputCollections.Count; i++) { |
||||
var inputCollection = inputCollections[i]; |
||||
if (EqualityComparer<TSource>.Default.Equals(inputCollection.source, removedSource)) { |
||||
inputCollection.AddResultsToList(removedResults); |
||||
inputCollection.UnregisterEvent(); |
||||
inputCollections.RemoveAt(i); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
List<TResult> addedResults = new List<TResult>(); |
||||
foreach (TSource addedSource in addedItems) { |
||||
var inputCollection = new InputCollection(this, addedSource); |
||||
inputCollection.AddResultsToList(addedResults); |
||||
inputCollection.RegisterEvent(); |
||||
inputCollections.Add(inputCollection); |
||||
} |
||||
OnCollectionChanged(removedResults, addedResults); |
||||
} |
||||
|
||||
class InputCollection |
||||
{ |
||||
readonly SelectManyModelCollection<TSource, TCollection, TResult> parent; |
||||
internal readonly TSource source; |
||||
readonly IModelCollection<TCollection> collection; |
||||
|
||||
public InputCollection(SelectManyModelCollection<TSource, TCollection, TResult> parent, TSource source) |
||||
{ |
||||
this.parent = parent; |
||||
this.source = source; |
||||
this.collection = parent.collectionSelector(source); |
||||
} |
||||
|
||||
public void AddResultsToList(List<TResult> output) |
||||
{ |
||||
foreach (var item in collection) { |
||||
output.Add(parent.resultSelector(source, item)); |
||||
} |
||||
} |
||||
|
||||
public void RegisterEvent() |
||||
{ |
||||
collection.CollectionChanged += OnCollectionChanged; |
||||
} |
||||
|
||||
public void UnregisterEvent() |
||||
{ |
||||
collection.CollectionChanged -= OnCollectionChanged; |
||||
} |
||||
|
||||
IReadOnlyCollection<TResult> GetResults(IReadOnlyCollection<TCollection> itemsCollection) |
||||
{ |
||||
List<TResult> results = new List<TResult>(itemsCollection.Count); |
||||
foreach (var item in itemsCollection) { |
||||
results.Add(parent.resultSelector(source, item)); |
||||
} |
||||
return results; |
||||
} |
||||
|
||||
void OnCollectionChanged(IReadOnlyCollection<TCollection> removedItems, IReadOnlyCollection<TCollection> addedItems) |
||||
{ |
||||
parent.OnCollectionChanged(GetResults(removedItems), GetResults(addedItems)); |
||||
} |
||||
} |
||||
|
||||
public IEnumerator<TResult> GetEnumerator() |
||||
{ |
||||
return source.AsEnumerable().SelectMany(collectionSelector, resultSelector).GetEnumerator(); |
||||
} |
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
||||
{ |
||||
return GetEnumerator(); |
||||
} |
||||
|
||||
public int Count { |
||||
get { |
||||
return source.Sum(c => collectionSelector(c).Count); |
||||
} |
||||
} |
||||
} |
||||
#endregion
|
||||
} |
||||
} |
||||
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)using System;
|
||||
|
||||
using System.Collections.Generic; |
||||
using System.Collections.ObjectModel; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Dom |
||||
{ |
||||
/// <summary>
|
||||
/// A model collection implementation that is based on a ReadOnlyCollection.
|
||||
/// </summary>
|
||||
public class ReadOnlyModelCollection<T> : ReadOnlyCollection<T>, IModelCollection<T> |
||||
{ |
||||
public ReadOnlyModelCollection(IEnumerable<T> items) |
||||
: base(items.ToList()) |
||||
{ |
||||
} |
||||
|
||||
event ModelCollectionChangedEventHandler<T> IModelCollection<T>.CollectionChanged { add {} remove {} } |
||||
} |
||||
} |
||||
@ -0,0 +1,206 @@
@@ -0,0 +1,206 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)using System;
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Collections.ObjectModel; |
||||
using System.Collections.Specialized; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory; |
||||
using ICSharpCode.NRefactory.Utils; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Dom |
||||
{ |
||||
/// <summary>
|
||||
/// A model collection implementation.
|
||||
/// </summary>
|
||||
public class SimpleModelCollection<T> : IMutableModelCollection<T> |
||||
{ |
||||
readonly List<T> list; |
||||
List<T> addedItems; |
||||
List<T> removedItems; |
||||
|
||||
public SimpleModelCollection() |
||||
{ |
||||
this.list = new List<T>(); |
||||
} |
||||
|
||||
public SimpleModelCollection(IEnumerable<T> items) |
||||
{ |
||||
this.list = new List<T>(items); |
||||
} |
||||
|
||||
protected void CheckReentrancy() |
||||
{ |
||||
if (isRaisingEvent) |
||||
throw new InvalidOperationException("Cannot modify the collection from within the CollectionChanged event."); |
||||
} |
||||
|
||||
protected virtual void ValidateItem(T item) |
||||
{ |
||||
} |
||||
|
||||
#region CollectionChanged / BatchUpdate()
|
||||
public event ModelCollectionChangedEventHandler<T> CollectionChanged; |
||||
|
||||
bool isWithinBatchOperation; |
||||
bool isRaisingEvent; |
||||
|
||||
void RaiseEventIfNotInBatch() |
||||
{ |
||||
if (isWithinBatchOperation) |
||||
return; |
||||
IReadOnlyCollection<T> removed = this.removedItems; |
||||
IReadOnlyCollection<T> added = this.addedItems; |
||||
this.removedItems = null; |
||||
this.addedItems = null; |
||||
this.isRaisingEvent = true; |
||||
try { |
||||
OnCollectionChanged(removed ?? EmptyList<T>.Instance, added ?? EmptyList<T>.Instance); |
||||
} finally { |
||||
this.isRaisingEvent = false; |
||||
} |
||||
} |
||||
|
||||
protected virtual void OnCollectionChanged(IReadOnlyCollection<T> removedItems, IReadOnlyCollection<T> addedItems) |
||||
{ |
||||
var handler = CollectionChanged; |
||||
if (handler != null) |
||||
handler(removedItems, addedItems); |
||||
} |
||||
|
||||
public IDisposable BatchUpdate() |
||||
{ |
||||
if (isWithinBatchOperation) |
||||
return null; |
||||
isWithinBatchOperation = true; |
||||
return new CallbackOnDispose( |
||||
delegate { |
||||
isWithinBatchOperation = false; |
||||
if (removedItems != null || addedItems != null) |
||||
RaiseEventIfNotInBatch(); |
||||
}); |
||||
} |
||||
#endregion
|
||||
|
||||
#region Read-Only list access
|
||||
|
||||
public int Count { |
||||
get { return list.Count; } |
||||
} |
||||
|
||||
public bool Contains(T item) |
||||
{ |
||||
return list.Contains(item); |
||||
} |
||||
|
||||
public void CopyTo(T[] array, int arrayIndex) |
||||
{ |
||||
list.CopyTo(array, arrayIndex); |
||||
} |
||||
|
||||
bool ICollection<T>.IsReadOnly { |
||||
get { return false; } |
||||
} |
||||
|
||||
public IEnumerator<T> GetEnumerator() |
||||
{ |
||||
return list.GetEnumerator(); |
||||
} |
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
||||
{ |
||||
return list.GetEnumerator(); |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region IMutableModelCollection implementation
|
||||
|
||||
public void Clear() |
||||
{ |
||||
CheckReentrancy(); |
||||
addedItems = null; |
||||
if (removedItems == null) |
||||
removedItems = new List<T>(); |
||||
removedItems.AddRange(list); |
||||
list.Clear(); |
||||
RaiseEventIfNotInBatch(); |
||||
} |
||||
|
||||
public void Add(T item) |
||||
{ |
||||
CheckReentrancy(); |
||||
ValidateItem(item); |
||||
if (removedItems != null) |
||||
removedItems.Remove(item); |
||||
if (addedItems == null) |
||||
addedItems = new List<T>(); |
||||
addedItems.Add(item); |
||||
list.Add(item); |
||||
RaiseEventIfNotInBatch(); |
||||
} |
||||
|
||||
public void AddRange(IEnumerable<T> items) |
||||
{ |
||||
if (items == null) |
||||
throw new ArgumentNullException("items"); |
||||
CheckReentrancy(); |
||||
List<T> itemsList = items.ToList(); |
||||
for (int i = 0; i < itemsList.Count; i++) { |
||||
ValidateItem(itemsList[i]); |
||||
} |
||||
if (removedItems != null) { |
||||
for (int i = 0; i < itemsList.Count; i++) { |
||||
removedItems.Remove(itemsList[i]); |
||||
} |
||||
} |
||||
if (addedItems != null) |
||||
addedItems.AddRange(itemsList); |
||||
else |
||||
addedItems = itemsList; |
||||
list.AddRange(itemsList); |
||||
RaiseEventIfNotInBatch(); |
||||
} |
||||
|
||||
public bool Remove(T item) |
||||
{ |
||||
CheckReentrancy(); |
||||
if (list.Remove(item)) { |
||||
if (addedItems != null) |
||||
addedItems.Remove(item); |
||||
if (removedItems == null) |
||||
removedItems = new List<T>(); |
||||
removedItems.Add(item); |
||||
RaiseEventIfNotInBatch(); |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public int RemoveAll(Predicate<T> predicate) |
||||
{ |
||||
CheckReentrancy(); |
||||
int count = list.RemoveAll( |
||||
delegate(T obj) { |
||||
if (predicate(obj)) { |
||||
if (addedItems != null) |
||||
addedItems.Remove(obj); |
||||
if (removedItems == null) |
||||
removedItems = new List<T>(); |
||||
removedItems.Add(obj); |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
}); |
||||
if (count > 0) |
||||
RaiseEventIfNotInBatch(); |
||||
return count; |
||||
} |
||||
|
||||
#endregion
|
||||
} |
||||
} |
||||
|
||||
Loading…
Reference in new issue