PageRenderTime 54ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/src/BurnSystems/src/Collections/ListTransformView.cs

https://bitbucket.org/mbrenn/entityconnector
C# | 472 lines | 216 code | 47 blank | 209 comment | 24 complexity | 5b50cac266ec38d33388c7ef80c4fc70 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Collections;
  6. using System.ComponentModel;
  7. using System.Collections.Specialized;
  8. using BurnSystems.Test;
  9. namespace BurnSystems.Collections
  10. {
  11. /// <summary>
  12. /// This class transforms a list into another view dynamically.
  13. /// It implements the interface IList, INotifyPropertyChanged and INotifyCollectionChanged correctly.
  14. ///
  15. /// It is necessary to call Detach if the transformation is not required any more.
  16. /// This list is read-only because the original list has to be modified
  17. /// </summary>
  18. /// <typeparam name="T">Type of the elements of the list that is the source type</typeparam>
  19. /// <typeparam name="Q">Type of the elements of the list, that shall be delivered</typeparam>
  20. public class ListTransformView<T, Q> : IList<Q>, IList, INotifyPropertyChanged //, INotifyCollectionChanged
  21. {
  22. /// <summary>
  23. /// Stores the synchronization root
  24. /// </summary>
  25. private object syncRoot = new object();
  26. /// <summary>
  27. /// Stores the selector
  28. /// </summary>
  29. private Func<T, Q> selector;
  30. /// <summary>
  31. /// Stores the list
  32. /// </summary>
  33. private IList<T> list;
  34. /// <summary>
  35. /// Initializes a new instance of the ListTransformView
  36. /// </summary>
  37. /// <param name="list">List to be transformed</param>
  38. /// <param name="selector">Selector to be used for transformation</param>
  39. public ListTransformView(IList<T> list ,Func<T,Q> selector)
  40. {
  41. var notifyPropertyChanged = list as INotifyPropertyChanged;
  42. var notifyCollectionChanged = list as INotifyCollectionChanged;
  43. Ensure.IsTrue(notifyCollectionChanged != null);
  44. Ensure.IsTrue(notifyPropertyChanged != null);
  45. notifyPropertyChanged.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged);
  46. notifyCollectionChanged.CollectionChanged += new NotifyCollectionChangedEventHandler(OnCollectionChanged);
  47. this.list = list;
  48. this.selector = selector;
  49. }
  50. /// <summary>
  51. /// This method detaches the events from the original list
  52. /// </summary>
  53. public void Detach()
  54. {
  55. var notifyPropertyChanged = this.list as INotifyPropertyChanged;
  56. var notifyCollectionChanged = this.list as INotifyCollectionChanged;
  57. notifyPropertyChanged.PropertyChanged -= new PropertyChangedEventHandler(OnPropertyChanged);
  58. notifyCollectionChanged.CollectionChanged -= new NotifyCollectionChangedEventHandler(OnCollectionChanged);
  59. }
  60. /// <summary>
  61. /// Called, if a property has been changed
  62. /// </summary>
  63. /// <param name="sender">Sender of the event</param>
  64. /// <param name="e">Arguments of event</param>
  65. void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  66. {
  67. return;
  68. /*
  69. var ev = this.CollectionChanged;
  70. if (ev != null)
  71. {
  72. switch (e.Action)
  73. {
  74. case NotifyCollectionChangedAction.Add:
  75. ev(
  76. this,
  77. new NotifyCollectionChangedEventArgs(
  78. NotifyCollectionChangedAction.Add,
  79. e.NewItems
  80. .OfType<T>()
  81. .Select(x => this.selector(x))
  82. .ToList(),
  83. e.NewStartingIndex));
  84. break;
  85. case NotifyCollectionChangedAction.Move:
  86. ev(
  87. this,
  88. new NotifyCollectionChangedEventArgs(
  89. NotifyCollectionChangedAction.Move,
  90. e.NewItems
  91. .OfType<T>()
  92. .Select(x => this.selector(x))
  93. .ToList(),
  94. e.NewStartingIndex,
  95. e.OldStartingIndex));
  96. break;
  97. case NotifyCollectionChangedAction.Remove:
  98. ev(
  99. this,
  100. new NotifyCollectionChangedEventArgs(
  101. NotifyCollectionChangedAction.Remove,
  102. e.OldItems
  103. .OfType<T>()
  104. .Select(x => this.selector(x))
  105. .ToList(),
  106. e.OldStartingIndex));
  107. break;
  108. case NotifyCollectionChangedAction.Replace:
  109. ev(
  110. this,
  111. new NotifyCollectionChangedEventArgs(
  112. NotifyCollectionChangedAction.Replace,
  113. e.OldItems
  114. .OfType<T>()
  115. .Select(x => this.selector(x))
  116. .ToList(),
  117. e.NewItems
  118. .OfType<T>()
  119. .Select(x => this.selector(x))
  120. .ToList()));
  121. break;
  122. case NotifyCollectionChangedAction.Reset:
  123. ev(
  124. this,
  125. new NotifyCollectionChangedEventArgs(
  126. NotifyCollectionChangedAction.Replace));
  127. break;
  128. default:
  129. break;
  130. }
  131. }
  132. */
  133. }
  134. /// <summary>
  135. /// Called, if a property has been changed
  136. /// </summary>
  137. /// <param name="sender">Sender of the event</param>
  138. /// <param name="e">Arguments of event</param>
  139. void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
  140. {
  141. var ev = this.PropertyChanged;
  142. if (ev != null)
  143. {
  144. ev(sender, e);
  145. }
  146. }
  147. /// <summary>
  148. /// Gets the index of a specific item
  149. /// </summary>
  150. /// <param name="item">Item to be queried</param>
  151. /// <returns>Index of the item</returns>
  152. public int IndexOf(Q item)
  153. {
  154. var found = -1;
  155. foreach (var element in this.list.Select(x => this.selector(x)))
  156. {
  157. found++;
  158. if (element == null && item == null)
  159. {
  160. return found;
  161. }
  162. if (element == null)
  163. {
  164. continue;
  165. }
  166. if (element.Equals(item))
  167. {
  168. return found;
  169. }
  170. }
  171. return -1;
  172. }
  173. /// <summary>
  174. /// This method is not implemented
  175. /// </summary>
  176. /// <param name="index">Index of the element</param>
  177. /// <param name="item">Element to be added</param>
  178. public void Insert(int index, Q item)
  179. {
  180. throw new NotImplementedException();
  181. }
  182. /// <summary>
  183. /// This method is not implemented
  184. /// </summary>
  185. /// <param name="index">Item to be removed</param>
  186. public void RemoveAt(int index)
  187. {
  188. throw new NotImplementedException();
  189. }
  190. /// <summary>
  191. /// Gets or sets an item.
  192. /// The setting of items is not implemented
  193. /// </summary>
  194. /// <param name="index">Index of the element</param>
  195. /// <returns>Element to be retrieved</returns>
  196. public Q this[int index]
  197. {
  198. get
  199. {
  200. return this.selector(this.list[index]);
  201. }
  202. set
  203. {
  204. throw new NotImplementedException();
  205. }
  206. }
  207. /// <summary>
  208. /// This method is not implemented
  209. /// </summary>
  210. /// <param name="item">Item to be added</param>
  211. public void Add(Q item)
  212. {
  213. throw new NotImplementedException();
  214. }
  215. /// <summary>
  216. /// This method is not implemented
  217. /// </summary>
  218. public void Clear()
  219. {
  220. throw new NotImplementedException();
  221. }
  222. /// <summary>
  223. /// Checks if an element is contained
  224. /// </summary>
  225. /// <param name="item">Item to be checked</param>
  226. /// <returns>True, if item is in list</returns>
  227. public bool Contains(Q item)
  228. {
  229. return this.IndexOf(item) != -1;
  230. }
  231. /// <summary>
  232. /// Copies the elements to an array
  233. /// </summary>
  234. /// <param name="array">Array to be used</param>
  235. /// <param name="arrayIndex">Position where the data shall be copied</param>
  236. public void CopyTo(Q[] array, int arrayIndex)
  237. {
  238. if (array == null)
  239. {
  240. throw new ArgumentNullException();
  241. }
  242. if (arrayIndex < 0)
  243. {
  244. throw new ArgumentOutOfRangeException();
  245. }
  246. var pos = arrayIndex;
  247. foreach (var element in this)
  248. {
  249. array[pos] = element;
  250. pos++;
  251. if (pos >= array.Length)
  252. {
  253. throw new ArgumentException();
  254. }
  255. }
  256. }
  257. /// <summary>
  258. /// Gets the number of elements
  259. /// </summary>
  260. public int Count
  261. {
  262. get { return this.list.Count; }
  263. }
  264. /// <summary>
  265. /// Gets a value indicating whether the list is read only
  266. /// </summary>
  267. public bool IsReadOnly
  268. {
  269. get { return true; }
  270. }
  271. /// <summary>
  272. /// Method is not implemented
  273. /// </summary>
  274. /// <param name="item">Item to be removed</param>
  275. /// <returns>true, if item has been removed</returns>
  276. public bool Remove(Q item)
  277. {
  278. throw new NotImplementedException();
  279. }
  280. /// <summary>
  281. /// Gets the enumerator
  282. /// </summary>
  283. /// <returns>Enumerator for the instance</returns>
  284. public IEnumerator<Q> GetEnumerator()
  285. {
  286. foreach (var item in this.list)
  287. {
  288. yield return this.selector(item);
  289. }
  290. }
  291. /// <summary>
  292. /// Gets the enumerator
  293. /// </summary>
  294. /// <returns>Enumerator for the instance</returns>
  295. IEnumerator IEnumerable.GetEnumerator()
  296. {
  297. foreach (var item in this.list)
  298. {
  299. yield return this.selector(item);
  300. }
  301. }
  302. /// <summary>
  303. /// This method is not implemented
  304. /// </summary>
  305. /// <param name="value">Value to be added</param>
  306. /// <returns>Position of new item</returns>
  307. public int Add(object value)
  308. {
  309. throw new NotImplementedException();
  310. }
  311. /// <summary>
  312. /// Checks if the item is inclued
  313. /// </summary>
  314. /// <param name="value">Value to be checked</param>
  315. /// <returns>true, if item is included</returns>
  316. public bool Contains(object value)
  317. {
  318. return this.IndexOf(value) != -1;
  319. }
  320. /// <summary>
  321. /// Gets the index of the item within the array
  322. /// </summary>
  323. /// <param name="value">Item whose index is required</param>
  324. /// <returns>Index of item or -1 if not existing</returns>
  325. public int IndexOf(object value)
  326. {
  327. var realValue = value is Q;
  328. if (!realValue && value != null)
  329. {
  330. // Not null, but not of type value
  331. return -1;
  332. }
  333. return this.IndexOf((Q) value);
  334. }
  335. /// <summary>
  336. /// Method not implemented
  337. /// </summary>
  338. /// <param name="index">Index of the new element</param>
  339. /// <param name="value">Value of the element</param>
  340. public void Insert(int index, object value)
  341. {
  342. throw new NotImplementedException();
  343. }
  344. /// <summary>
  345. /// True, if this has a fixed size
  346. /// </summary>
  347. public bool IsFixedSize
  348. {
  349. get { return false; }
  350. }
  351. /// <summary>
  352. /// Not implemented
  353. /// </summary>
  354. /// <param name="value">Item to be removed</param>
  355. public void Remove(object value)
  356. {
  357. throw new NotImplementedException();
  358. }
  359. /// <summary>
  360. /// Gets or sets a specific item. The setting of items is not implemented
  361. /// </summary>
  362. /// <param name="index">Index of the item</param>
  363. /// <returns>Requested object</returns>
  364. object IList.this[int index]
  365. {
  366. get
  367. {
  368. return this[index];
  369. }
  370. set
  371. {
  372. throw new NotImplementedException();
  373. }
  374. }
  375. /// <summary>
  376. /// Copies the elements to an array
  377. /// </summary>
  378. /// <param name="array">Array to be filled</param>
  379. /// <param name="index">Index within the array</param>
  380. public void CopyTo(Array array, int index)
  381. {
  382. if (array == null)
  383. {
  384. throw new ArgumentNullException();
  385. }
  386. if (index < 0)
  387. {
  388. throw new ArgumentOutOfRangeException();
  389. }
  390. var pos = index;
  391. foreach (var element in this)
  392. {
  393. array.SetValue(element, pos);
  394. pos++;
  395. if (pos >= array.Length)
  396. {
  397. throw new ArgumentException();
  398. }
  399. }
  400. }
  401. /// <summary>
  402. /// True, if the instance is synchronized.
  403. /// </summary>
  404. public bool IsSynchronized
  405. {
  406. get { return false; }
  407. }
  408. /// <summary>
  409. /// Gets the synchronisation root
  410. /// </summary>
  411. public object SyncRoot
  412. {
  413. get { return this.syncRoot; }
  414. }
  415. /// <summary>
  416. /// This event is called, when a property has been changed
  417. /// </summary>
  418. public event PropertyChangedEventHandler PropertyChanged;
  419. /// <summary>
  420. /// This event is called, when a collection has been changed.
  421. /// This method is not implemented in Mono
  422. /// </summary>
  423. //public event NotifyCollectionChangedEventHandler CollectionChanged;
  424. }
  425. }