ObservableList.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Collections.ObjectModel;
  5. /* Turn off documentation warnings in this file. Generally they are
  6. * relevant in this library, but not for this file since it is mostly
  7. * methods found in normal List<> class, and thus it is no need to write
  8. * that comments once again with the drawback of making it hard to read.
  9. */
  10. #pragma warning disable 1591
  11. namespace Wayne.Lib
  12. {
  13. /// <summary>
  14. /// Extends the IList interface with some more members found in List class.
  15. /// </summary>
  16. /// <typeparam name="T"></typeparam>
  17. public interface IAdvancedList<T> : IList<T>
  18. {
  19. void AddRange(IEnumerable<T> collection);
  20. ReadOnlyCollection<T> AsReadOnly();
  21. void CopyTo(T[] array);
  22. void CopyTo(int index, T[] array, int arrayIndex, int count);
  23. void BeginUpdate();
  24. void EndUpdate();
  25. }
  26. /// <summary>
  27. /// Extends IAdvanced List with an event handler that makes it possible to
  28. /// follow when the contents has benn changed.
  29. /// </summary>
  30. /// <typeparam name="T"></typeparam>
  31. public interface IObservableList<T> : IAdvancedList<T>
  32. {
  33. event EventHandler Changed;
  34. }
  35. /// <summary>
  36. /// Observable list is a list class similar to .Net's List but with an
  37. /// event that notifies when something has been changed in the list.
  38. /// </summary>
  39. /// <typeparam name="T"></typeparam>
  40. public class ObservableList<T> : IObservableList<T>, IList
  41. {
  42. private object syncRoot;
  43. private readonly List<T> internalList = new List<T>();
  44. private int updateCount;
  45. private bool updated;
  46. public IEnumerator<T> GetEnumerator()
  47. {
  48. return internalList.GetEnumerator();
  49. }
  50. IEnumerator IEnumerable.GetEnumerator()
  51. {
  52. return GetEnumerator();
  53. }
  54. public int Count
  55. {
  56. get { return internalList.Count; }
  57. }
  58. int ICollection.Count
  59. {
  60. get { return Count; }
  61. }
  62. public bool Contains(T item)
  63. {
  64. return internalList.Contains(item);
  65. }
  66. public bool Contains(object value)
  67. {
  68. return IsCompatibleObject(value) && Contains((T)value);
  69. }
  70. public void Clear()
  71. {
  72. if (internalList.Count > 0)
  73. {
  74. internalList.Clear();
  75. ListChanged();
  76. }
  77. }
  78. void IList.Clear()
  79. {
  80. Clear();
  81. }
  82. public int IndexOf(T item)
  83. {
  84. return internalList.IndexOf(item);
  85. }
  86. int IList.IndexOf(object value)
  87. {
  88. return IsCompatibleObject(value) ? IndexOf((T)value) : -1;
  89. }
  90. public T this[int index]
  91. {
  92. get { return internalList[index]; }
  93. set
  94. {
  95. internalList[index] = value;
  96. ListChanged();
  97. }
  98. }
  99. object IList.this[int index]
  100. {
  101. get { return internalList[index]; }
  102. set
  103. {
  104. VerifyValueType(value);
  105. this[index] = (T)value;
  106. }
  107. }
  108. public void Add(T item)
  109. {
  110. internalList.Add(item);
  111. ListChanged();
  112. }
  113. public int Add(object value)
  114. {
  115. VerifyValueType(value);
  116. Add((T)value);
  117. return Count - 1;
  118. }
  119. public void AddRange(IEnumerable<T> collection)
  120. {
  121. internalList.AddRange(collection);
  122. ListChanged();
  123. }
  124. public ReadOnlyCollection<T> AsReadOnly()
  125. {
  126. return new ReadOnlyCollection<T>(internalList);
  127. }
  128. public void Insert(int index, T item)
  129. {
  130. internalList.Insert(index, item);
  131. ListChanged();
  132. }
  133. public void Insert(int index, object value)
  134. {
  135. VerifyValueType(value);
  136. Insert(index, (T)value);
  137. }
  138. public bool Remove(T item)
  139. {
  140. if (internalList.Remove(item))
  141. {
  142. ListChanged();
  143. return true;
  144. }
  145. return false;
  146. }
  147. public void Remove(object value)
  148. {
  149. VerifyValueType(value);
  150. Remove((T)value);
  151. }
  152. public void RemoveAt(int index)
  153. {
  154. internalList.RemoveAt(index);
  155. ListChanged();
  156. }
  157. void IList.RemoveAt(int index)
  158. {
  159. RemoveAt(index);
  160. }
  161. bool IList.IsReadOnly
  162. {
  163. get { return false; }
  164. }
  165. public bool IsFixedSize
  166. {
  167. get { return false; }
  168. }
  169. public void CopyTo(T[] array)
  170. {
  171. internalList.CopyTo(array);
  172. }
  173. public void CopyTo(T[] array, int arrayIndex)
  174. {
  175. internalList.CopyTo(array, arrayIndex);
  176. }
  177. public void CopyTo(int index, T[] array, int arrayIndex, int count)
  178. {
  179. internalList.CopyTo(index, array, arrayIndex, count);
  180. }
  181. public void CopyTo(Array array, int index)
  182. {
  183. if ((array != null) && (array.Rank != 1))
  184. throw new ArgumentException("Only single dimensional arrays are supported for the requested action.");
  185. try
  186. {
  187. Array.Copy(internalList.ToArray(), 0, array, index, internalList.Count);
  188. }
  189. catch (ArrayTypeMismatchException)
  190. {
  191. throw new ArgumentException("Target array type is not compatible with the type of items in the collection.");
  192. }
  193. }
  194. public object SyncRoot
  195. {
  196. get
  197. {
  198. if (syncRoot == null)
  199. System.Threading.Interlocked.CompareExchange(ref syncRoot, new object(), null);
  200. return syncRoot;
  201. }
  202. }
  203. public bool IsSynchronized
  204. {
  205. get { return false; }
  206. }
  207. public bool IsReadOnly
  208. {
  209. get { return IsReadOnly; }
  210. }
  211. private static bool IsCompatibleObject(object value)
  212. {
  213. return (value is T) || (value == null && !typeof(T).IsValueType);
  214. }
  215. private static void VerifyValueType(object value)
  216. {
  217. if (!IsCompatibleObject(value))
  218. throw new ArgumentException(string.Concat("The value \"", value.GetType(), "\" is not of type \"", typeof(T), "\" and cannot be used in this generic collection."));
  219. }
  220. public event EventHandler Changed;
  221. public void BeginUpdate()
  222. {
  223. updateCount++;
  224. }
  225. public void EndUpdate()
  226. {
  227. updateCount--;
  228. if ((updateCount == 0) && updated)
  229. {
  230. updated = false;
  231. ListChanged();
  232. }
  233. }
  234. private void ListChanged()
  235. {
  236. if (updateCount > 0)
  237. {
  238. updated = true;
  239. return;
  240. }
  241. if (Changed != null)
  242. Changed(this, EventArgs.Empty);
  243. }
  244. }
  245. }