NotifyCollectionChangedEventArgs.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. // Copyright (c) Microsoft. All rights reserved.
  2. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
  3. using System;
  4. using System.Collections;
  5. using System.Diagnostics;
  6. namespace PlatformSupport.Collections.Specialized
  7. {
  8. public delegate void NotifyCollectionChangedEventHandler(object sender, PlatformSupport.Collections.Specialized.NotifyCollectionChangedEventArgs e);
  9. public interface INotifyCollectionChanged
  10. {
  11. event NotifyCollectionChangedEventHandler CollectionChanged;
  12. }
  13. /// <summary>
  14. /// This enum describes the action that caused a CollectionChanged event.
  15. /// </summary>
  16. public enum NotifyCollectionChangedAction
  17. {
  18. /// <summary> One or more items were added to the collection. </summary>
  19. Add,
  20. /// <summary> One or more items were removed from the collection. </summary>
  21. Remove,
  22. /// <summary> One or more items were replaced in the collection. </summary>
  23. Replace,
  24. /// <summary> One or more items were moved within the collection. </summary>
  25. Move,
  26. /// <summary> The contents of the collection changed dramatically. </summary>
  27. Reset,
  28. }
  29. /// <summary>
  30. /// Arguments for the CollectionChanged event.
  31. /// A collection that supports INotifyCollectionChangedThis raises this event
  32. /// whenever an item is added or removed, or when the contents of the collection
  33. /// changes dramatically.
  34. /// </summary>
  35. public class NotifyCollectionChangedEventArgs : EventArgs
  36. {
  37. //------------------------------------------------------
  38. //
  39. // Constructors
  40. //
  41. //------------------------------------------------------
  42. /// <summary>
  43. /// Construct a NotifyCollectionChangedEventArgs that describes a reset change.
  44. /// </summary>
  45. /// <param name="action">The action that caused the event (must be Reset).</param>
  46. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action)
  47. {
  48. if (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Reset)
  49. throw new ArgumentException("action");
  50. InitializeAdd(action, null, -1);
  51. }
  52. /// <summary>
  53. /// Construct a NotifyCollectionChangedEventArgs that describes a one-item change.
  54. /// </summary>
  55. /// <param name="action">The action that caused the event; can only be Reset, Add or Remove action.</param>
  56. /// <param name="changedItem">The item affected by the change.</param>
  57. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, object changedItem)
  58. {
  59. if ((action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Add) && (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Remove)
  60. && (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Reset))
  61. throw new ArgumentException("action");
  62. if (action == PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Reset)
  63. {
  64. if (changedItem != null)
  65. throw new ArgumentException("action");
  66. InitializeAdd(action, null, -1);
  67. }
  68. else
  69. {
  70. InitializeAddOrRemove(action, new object[] { changedItem }, -1);
  71. }
  72. }
  73. /// <summary>
  74. /// Construct a NotifyCollectionChangedEventArgs that describes a one-item change.
  75. /// </summary>
  76. /// <param name="action">The action that caused the event.</param>
  77. /// <param name="changedItem">The item affected by the change.</param>
  78. /// <param name="index">The index where the change occurred.</param>
  79. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, object changedItem, int index)
  80. {
  81. if ((action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Add) && (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Remove)
  82. && (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Reset))
  83. throw new ArgumentException("action");
  84. if (action == PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Reset)
  85. {
  86. if (changedItem != null)
  87. throw new ArgumentException("action");
  88. if (index != -1)
  89. throw new ArgumentException("action");
  90. InitializeAdd(action, null, -1);
  91. }
  92. else
  93. {
  94. InitializeAddOrRemove(action, new object[] { changedItem }, index);
  95. }
  96. }
  97. /// <summary>
  98. /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item change.
  99. /// </summary>
  100. /// <param name="action">The action that caused the event.</param>
  101. /// <param name="changedItems">The items affected by the change.</param>
  102. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, IList changedItems)
  103. {
  104. if ((action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Add) && (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Remove)
  105. && (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Reset))
  106. throw new ArgumentException("action");
  107. if (action == PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Reset)
  108. {
  109. if (changedItems != null)
  110. throw new ArgumentException("action");
  111. InitializeAdd(action, null, -1);
  112. }
  113. else
  114. {
  115. if (changedItems == null)
  116. throw new ArgumentNullException("changedItems");
  117. InitializeAddOrRemove(action, changedItems, -1);
  118. }
  119. }
  120. /// <summary>
  121. /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item change (or a reset).
  122. /// </summary>
  123. /// <param name="action">The action that caused the event.</param>
  124. /// <param name="changedItems">The items affected by the change.</param>
  125. /// <param name="startingIndex">The index where the change occurred.</param>
  126. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
  127. {
  128. if ((action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Add) && (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Remove)
  129. && (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Reset))
  130. throw new ArgumentException("action");
  131. if (action == PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Reset)
  132. {
  133. if (changedItems != null)
  134. throw new ArgumentException("action");
  135. if (startingIndex != -1)
  136. throw new ArgumentException("action");
  137. InitializeAdd(action, null, -1);
  138. }
  139. else
  140. {
  141. if (changedItems == null)
  142. throw new ArgumentNullException("changedItems");
  143. if (startingIndex < -1)
  144. throw new ArgumentException("startingIndex");
  145. InitializeAddOrRemove(action, changedItems, startingIndex);
  146. }
  147. }
  148. /// <summary>
  149. /// Construct a NotifyCollectionChangedEventArgs that describes a one-item Replace event.
  150. /// </summary>
  151. /// <param name="action">Can only be a Replace action.</param>
  152. /// <param name="newItem">The new item replacing the original item.</param>
  153. /// <param name="oldItem">The original item that is replaced.</param>
  154. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, object newItem, object oldItem)
  155. {
  156. if (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Replace)
  157. throw new ArgumentException("action");
  158. InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, -1, -1);
  159. }
  160. /// <summary>
  161. /// Construct a NotifyCollectionChangedEventArgs that describes a one-item Replace event.
  162. /// </summary>
  163. /// <param name="action">Can only be a Replace action.</param>
  164. /// <param name="newItem">The new item replacing the original item.</param>
  165. /// <param name="oldItem">The original item that is replaced.</param>
  166. /// <param name="index">The index of the item being replaced.</param>
  167. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, object newItem, object oldItem, int index)
  168. {
  169. if (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Replace)
  170. throw new ArgumentException("action");
  171. InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, index, index);
  172. }
  173. /// <summary>
  174. /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Replace event.
  175. /// </summary>
  176. /// <param name="action">Can only be a Replace action.</param>
  177. /// <param name="newItems">The new items replacing the original items.</param>
  178. /// <param name="oldItems">The original items that are replaced.</param>
  179. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, IList newItems, IList oldItems)
  180. {
  181. if (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Replace)
  182. throw new ArgumentException("action");
  183. if (newItems == null)
  184. throw new ArgumentNullException("newItems");
  185. if (oldItems == null)
  186. throw new ArgumentNullException("oldItems");
  187. InitializeMoveOrReplace(action, newItems, oldItems, -1, -1);
  188. }
  189. /// <summary>
  190. /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Replace event.
  191. /// </summary>
  192. /// <param name="action">Can only be a Replace action.</param>
  193. /// <param name="newItems">The new items replacing the original items.</param>
  194. /// <param name="oldItems">The original items that are replaced.</param>
  195. /// <param name="startingIndex">The starting index of the items being replaced.</param>
  196. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex)
  197. {
  198. if (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Replace)
  199. throw new ArgumentException("action");
  200. if (newItems == null)
  201. throw new ArgumentNullException("newItems");
  202. if (oldItems == null)
  203. throw new ArgumentNullException("oldItems");
  204. InitializeMoveOrReplace(action, newItems, oldItems, startingIndex, startingIndex);
  205. }
  206. /// <summary>
  207. /// Construct a NotifyCollectionChangedEventArgs that describes a one-item Move event.
  208. /// </summary>
  209. /// <param name="action">Can only be a Move action.</param>
  210. /// <param name="changedItem">The item affected by the change.</param>
  211. /// <param name="index">The new index for the changed item.</param>
  212. /// <param name="oldIndex">The old index for the changed item.</param>
  213. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, object changedItem, int index, int oldIndex)
  214. {
  215. if (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Move)
  216. throw new ArgumentException("action");
  217. if (index < 0)
  218. throw new ArgumentException("index");
  219. object[] changedItems = new object[] { changedItem };
  220. InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
  221. }
  222. /// <summary>
  223. /// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Move event.
  224. /// </summary>
  225. /// <param name="action">The action that caused the event.</param>
  226. /// <param name="changedItems">The items affected by the change.</param>
  227. /// <param name="index">The new index for the changed items.</param>
  228. /// <param name="oldIndex">The old index for the changed items.</param>
  229. public NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, IList changedItems, int index, int oldIndex)
  230. {
  231. if (action != PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Move)
  232. throw new ArgumentException("action");
  233. if (index < 0)
  234. throw new ArgumentException("index");
  235. InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
  236. }
  237. /// <summary>
  238. /// Construct a NotifyCollectionChangedEventArgs with given fields (no validation). Used by WinRT marshaling.
  239. /// </summary>
  240. internal NotifyCollectionChangedEventArgs(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, IList newItems, IList oldItems, int newIndex, int oldIndex)
  241. {
  242. _action = action;
  243. _newItems = (newItems == null) ? null : new ReadOnlyList(newItems);
  244. _oldItems = (oldItems == null) ? null : new ReadOnlyList(oldItems);
  245. _newStartingIndex = newIndex;
  246. _oldStartingIndex = oldIndex;
  247. }
  248. private void InitializeAddOrRemove(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
  249. {
  250. if (action == PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Add)
  251. InitializeAdd(action, changedItems, startingIndex);
  252. else if (action == PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction.Remove)
  253. InitializeRemove(action, changedItems, startingIndex);
  254. else
  255. Debug.Assert(false, String.Format("Unsupported action: {0}", action.ToString()));
  256. }
  257. private void InitializeAdd(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, IList newItems, int newStartingIndex)
  258. {
  259. _action = action;
  260. _newItems = (newItems == null) ? null : new ReadOnlyList(newItems);
  261. _newStartingIndex = newStartingIndex;
  262. }
  263. private void InitializeRemove(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, IList oldItems, int oldStartingIndex)
  264. {
  265. _action = action;
  266. _oldItems = (oldItems == null) ? null : new ReadOnlyList(oldItems);
  267. _oldStartingIndex = oldStartingIndex;
  268. }
  269. private void InitializeMoveOrReplace(PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex, int oldStartingIndex)
  270. {
  271. InitializeAdd(action, newItems, startingIndex);
  272. InitializeRemove(action, oldItems, oldStartingIndex);
  273. }
  274. //------------------------------------------------------
  275. //
  276. // Public Properties
  277. //
  278. //------------------------------------------------------
  279. /// <summary>
  280. /// The action that caused the event.
  281. /// </summary>
  282. public PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction Action
  283. {
  284. get { return _action; }
  285. }
  286. /// <summary>
  287. /// The items affected by the change.
  288. /// </summary>
  289. public IList NewItems
  290. {
  291. get { return _newItems; }
  292. }
  293. /// <summary>
  294. /// The old items affected by the change (for Replace events).
  295. /// </summary>
  296. public IList OldItems
  297. {
  298. get { return _oldItems; }
  299. }
  300. /// <summary>
  301. /// The index where the change occurred.
  302. /// </summary>
  303. public int NewStartingIndex
  304. {
  305. get { return _newStartingIndex; }
  306. }
  307. /// <summary>
  308. /// The old index where the change occurred (for Move events).
  309. /// </summary>
  310. public int OldStartingIndex
  311. {
  312. get { return _oldStartingIndex; }
  313. }
  314. //------------------------------------------------------
  315. //
  316. // Private Fields
  317. //
  318. //------------------------------------------------------
  319. private PlatformSupport.Collections.Specialized.NotifyCollectionChangedAction _action;
  320. private IList _newItems, _oldItems;
  321. private int _newStartingIndex = -1;
  322. private int _oldStartingIndex = -1;
  323. }
  324. internal sealed class ReadOnlyList : IList
  325. {
  326. private readonly IList _list;
  327. internal ReadOnlyList(IList list)
  328. {
  329. Debug.Assert(list != null);
  330. _list = list;
  331. }
  332. public int Count
  333. {
  334. get { return _list.Count; }
  335. }
  336. public bool IsReadOnly
  337. {
  338. get { return true; }
  339. }
  340. public bool IsFixedSize
  341. {
  342. get { return true; }
  343. }
  344. public bool IsSynchronized
  345. {
  346. get { return _list.IsSynchronized; }
  347. }
  348. public object this[int index]
  349. {
  350. get
  351. {
  352. return _list[index];
  353. }
  354. set
  355. {
  356. throw new NotSupportedException();
  357. }
  358. }
  359. public object SyncRoot
  360. {
  361. get { return _list.SyncRoot; }
  362. }
  363. public int Add(object value)
  364. {
  365. throw new NotSupportedException();
  366. }
  367. public void Clear()
  368. {
  369. throw new NotSupportedException();
  370. }
  371. public bool Contains(object value)
  372. {
  373. return _list.Contains(value);
  374. }
  375. public void CopyTo(Array array, int index)
  376. {
  377. _list.CopyTo(array, index);
  378. }
  379. public IEnumerator GetEnumerator()
  380. {
  381. return _list.GetEnumerator();
  382. }
  383. public int IndexOf(object value)
  384. {
  385. return _list.IndexOf(value);
  386. }
  387. public void Insert(int index, object value)
  388. {
  389. throw new NotSupportedException();
  390. }
  391. public void Remove(object value)
  392. {
  393. throw new NotSupportedException();
  394. }
  395. public void RemoveAt(int index)
  396. {
  397. throw new NotSupportedException();
  398. }
  399. }
  400. }