using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
/* Turn off documentation warnings in this file. Generally they are
* relevant in this library, but not for this file since it is mostly
* methods found in normal List<> class, and thus it is no need to write
* that comments once again with the drawback of making it hard to read.
*/
#pragma warning disable 1591
namespace Wayne.Lib
{
///
/// Extends the IList interface with some more members found in List class.
///
///
public interface IAdvancedList : IList
{
void AddRange(IEnumerable collection);
ReadOnlyCollection AsReadOnly();
void CopyTo(T[] array);
void CopyTo(int index, T[] array, int arrayIndex, int count);
void BeginUpdate();
void EndUpdate();
}
///
/// Extends IAdvanced List with an event handler that makes it possible to
/// follow when the contents has benn changed.
///
///
public interface IObservableList : IAdvancedList
{
event EventHandler Changed;
}
///
/// Observable list is a list class similar to .Net's List but with an
/// event that notifies when something has been changed in the list.
///
///
public class ObservableList : IObservableList, IList
{
private object syncRoot;
private readonly List internalList = new List();
private int updateCount;
private bool updated;
public IEnumerator GetEnumerator()
{
return internalList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count
{
get { return internalList.Count; }
}
int ICollection.Count
{
get { return Count; }
}
public bool Contains(T item)
{
return internalList.Contains(item);
}
public bool Contains(object value)
{
return IsCompatibleObject(value) && Contains((T)value);
}
public void Clear()
{
if (internalList.Count > 0)
{
internalList.Clear();
ListChanged();
}
}
void IList.Clear()
{
Clear();
}
public int IndexOf(T item)
{
return internalList.IndexOf(item);
}
int IList.IndexOf(object value)
{
return IsCompatibleObject(value) ? IndexOf((T)value) : -1;
}
public T this[int index]
{
get { return internalList[index]; }
set
{
internalList[index] = value;
ListChanged();
}
}
object IList.this[int index]
{
get { return internalList[index]; }
set
{
VerifyValueType(value);
this[index] = (T)value;
}
}
public void Add(T item)
{
internalList.Add(item);
ListChanged();
}
public int Add(object value)
{
VerifyValueType(value);
Add((T)value);
return Count - 1;
}
public void AddRange(IEnumerable collection)
{
internalList.AddRange(collection);
ListChanged();
}
public ReadOnlyCollection AsReadOnly()
{
return new ReadOnlyCollection(internalList);
}
public void Insert(int index, T item)
{
internalList.Insert(index, item);
ListChanged();
}
public void Insert(int index, object value)
{
VerifyValueType(value);
Insert(index, (T)value);
}
public bool Remove(T item)
{
if (internalList.Remove(item))
{
ListChanged();
return true;
}
return false;
}
public void Remove(object value)
{
VerifyValueType(value);
Remove((T)value);
}
public void RemoveAt(int index)
{
internalList.RemoveAt(index);
ListChanged();
}
void IList.RemoveAt(int index)
{
RemoveAt(index);
}
bool IList.IsReadOnly
{
get { return false; }
}
public bool IsFixedSize
{
get { return false; }
}
public void CopyTo(T[] array)
{
internalList.CopyTo(array);
}
public void CopyTo(T[] array, int arrayIndex)
{
internalList.CopyTo(array, arrayIndex);
}
public void CopyTo(int index, T[] array, int arrayIndex, int count)
{
internalList.CopyTo(index, array, arrayIndex, count);
}
public void CopyTo(Array array, int index)
{
if ((array != null) && (array.Rank != 1))
throw new ArgumentException("Only single dimensional arrays are supported for the requested action.");
try
{
Array.Copy(internalList.ToArray(), 0, array, index, internalList.Count);
}
catch (ArrayTypeMismatchException)
{
throw new ArgumentException("Target array type is not compatible with the type of items in the collection.");
}
}
public object SyncRoot
{
get
{
if (syncRoot == null)
System.Threading.Interlocked.CompareExchange(ref syncRoot, new object(), null);
return syncRoot;
}
}
public bool IsSynchronized
{
get { return false; }
}
public bool IsReadOnly
{
get { return IsReadOnly; }
}
private static bool IsCompatibleObject(object value)
{
return (value is T) || (value == null && !typeof(T).IsValueType);
}
private static void VerifyValueType(object value)
{
if (!IsCompatibleObject(value))
throw new ArgumentException(string.Concat("The value \"", value.GetType(), "\" is not of type \"", typeof(T), "\" and cannot be used in this generic collection."));
}
public event EventHandler Changed;
public void BeginUpdate()
{
updateCount++;
}
public void EndUpdate()
{
updateCount--;
if ((updateCount == 0) && updated)
{
updated = false;
ListChanged();
}
}
private void ListChanged()
{
if (updateCount > 0)
{
updated = true;
return;
}
if (Changed != null)
Changed(this, EventArgs.Empty);
}
}
}