PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/class/System.Windows/System.Windows.Data/StandardCollectionView.cs

http://github.com/mono/moon
C# | 699 lines | 549 code | 111 blank | 39 comment | 202 complexity | 5d79e067071bc3553f61e9f92611a041 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, MIT, LGPL-2.1, MPL-2.0-no-copyleft-exception, GPL-3.0
  1. using System;
  2. using System.ComponentModel;
  3. using System.Collections.Specialized;
  4. using System.Globalization;
  5. using System.Collections.ObjectModel;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Reflection;
  10. using Mono;
  11. namespace System.Windows.Data {
  12. sealed class ListCollectionView : EditableCollectionView, IComparer<object> {
  13. public IList ActiveList {
  14. get {
  15. if (Filter == null && GroupDescriptions.Count == 0 && SortDescriptions.Count == 0)
  16. return SourceCollection;
  17. return filteredList;
  18. }
  19. }
  20. PropertyComparer Comparer {
  21. get { return new PropertyComparer (SortDescriptions); }
  22. }
  23. bool DeferCurrentChanged {
  24. get; set;
  25. }
  26. ObservableList<object> filteredList {
  27. get; set;
  28. }
  29. bool Grouping {
  30. get { return Groups != null; }
  31. }
  32. bool IgnoreFilteredListChanges {
  33. get; set;
  34. }
  35. bool IsValidSelection {
  36. get { return CurrentPosition >= 0 && CurrentPosition < ActiveList.Count; }
  37. }
  38. ConstructorInfo ItemConstructor {
  39. get; set;
  40. }
  41. RootCollectionViewGroup RootGroup {
  42. get; set;
  43. }
  44. public new IList SourceCollection {
  45. get { return (IList) base.SourceCollection; }
  46. }
  47. public ListCollectionView (IList collection)
  48. : base (collection)
  49. {
  50. var interfaces = SourceCollection.GetType ().GetInterfaces ();
  51. foreach (var t in interfaces) {
  52. if (t.IsGenericType && t.GetGenericTypeDefinition () == typeof (IList<>)) {
  53. Type type = t.GetGenericArguments () [0];
  54. ItemConstructor = type.GetConstructor (Type.EmptyTypes);
  55. }
  56. }
  57. UpdateCanAddNewAndRemove ();
  58. filteredList = new ObservableList<object> ();
  59. RootGroup = new RootCollectionViewGroup (SourceCollection, null, null, 0, false, SortDescriptions);
  60. CurrentPosition = -1;
  61. IsEmpty = ActiveList.Count == 0;
  62. MoveCurrentToPosition (0);
  63. if (SourceCollection is INotifyCollectionChanged)
  64. ((INotifyCollectionChanged) SourceCollection).CollectionChanged += HandleSourceCollectionChanged;
  65. GroupDescriptions.CollectionChanged += (o, e) => Refresh ();
  66. ((INotifyCollectionChanged) SortDescriptions).CollectionChanged += (o, e) => {
  67. if (IsAddingNew || IsEditingItem)
  68. throw new InvalidOperationException ("Cannot modify SortDescriptions while adding or editing an item");
  69. Refresh ();
  70. };
  71. filteredList.CollectionChanged += HandleFilteredListCollectionChanged;
  72. RootGroup.CollectionChanged += HandleRootGroupCollectionChanged;
  73. }
  74. void HandleRootGroupCollectionChanged (object sender, NotifyCollectionChangedEventArgs e)
  75. {
  76. if (DeferLevel == 0 && Grouping)
  77. RaiseCollectionChanged (e);
  78. }
  79. void HandleFilteredListCollectionChanged (object sender, NotifyCollectionChangedEventArgs e)
  80. {
  81. if (DeferLevel == 0 && ActiveList == filteredList && !Grouping && !IgnoreFilteredListChanges)
  82. RaiseCollectionChanged (e);
  83. }
  84. void HandleSourceCollectionChanged (object sender, NotifyCollectionChangedEventArgs e)
  85. {
  86. // Firstly if we are copying the source collection into our filtered list, update
  87. // the copy with the new changes and compute the actual index of our item in the
  88. // sorted/grouped/filtered list.
  89. int actualOldIndex = -1;
  90. int actualNewIndex = -1;
  91. bool originalList = ActiveList == SourceCollection;
  92. if (!originalList) {
  93. switch (e.Action) {
  94. case NotifyCollectionChangedAction.Add:
  95. foreach (object o in e.NewItems)
  96. AddToFilteredAndGroupSorted (o);
  97. break;
  98. case NotifyCollectionChangedAction.Remove:
  99. actualOldIndex = IndexOf (e.OldItems [0]);
  100. foreach (object o in e.OldItems)
  101. RemoveFromFilteredAndGroup (o);
  102. break;
  103. case NotifyCollectionChangedAction.Replace:
  104. foreach (object o in e.OldItems)
  105. RemoveFromFilteredAndGroup (o);
  106. foreach (object o in e.NewItems)
  107. AddToFilteredAndGroupSorted (o);
  108. break;
  109. case NotifyCollectionChangedAction.Reset:
  110. filteredList.Clear ();
  111. RootGroup.ClearSubtree ();
  112. foreach (var o in SourceCollection)
  113. AddToFilteredAndGroup (o);
  114. break;
  115. }
  116. } else {
  117. // Raise the collection changed event
  118. RaiseCollectionChanged (e);
  119. }
  120. IsEmpty = ActiveList.Count == 0;
  121. IsCurrentAfterLast = CurrentPosition == ActiveList.Count || ActiveList.Count == 0;
  122. IsCurrentBeforeFirst = CurrentPosition == -1 || ActiveList.Count == 0;
  123. }
  124. protected override void RaiseCollectionChanged (NotifyCollectionChangedEventArgs e)
  125. {
  126. RaiseCollectionChanged (e, true);
  127. }
  128. void RaiseCollectionChanged (NotifyCollectionChangedEventArgs e, bool moveOnReset)
  129. {
  130. base.RaiseCollectionChanged (e);
  131. // Finally update the selected item if needed.
  132. switch (e.Action) {
  133. case NotifyCollectionChangedAction.Add:
  134. int actualNewIndex = e.NewStartingIndex;
  135. if (actualNewIndex <= CurrentPosition)
  136. MoveCurrentTo (CurrentPosition + 1);
  137. break;
  138. case NotifyCollectionChangedAction.Remove:
  139. int actualOldIndex = e.OldStartingIndex;
  140. if (actualOldIndex < CurrentPosition) {
  141. MoveCurrentTo (CurrentPosition - 1);
  142. } else if (actualOldIndex == CurrentPosition) {
  143. if (CurrentAddItem == CurrentItem || CurrentPosition >= ActiveList.Count)
  144. MoveCurrentTo (CurrentPosition - 1);
  145. else
  146. MoveCurrentTo (CurrentPosition);
  147. }
  148. break;
  149. case NotifyCollectionChangedAction.Replace:
  150. MoveCurrentTo (IndexOf (CurrentItem));
  151. break;
  152. case NotifyCollectionChangedAction.Reset:
  153. if (moveOnReset)
  154. MoveCurrentTo (IndexOf (CurrentItem));
  155. break;
  156. }
  157. }
  158. void AddToFilteredAndGroup (object item)
  159. {
  160. // If we're adding an item because of a call to the 'AddNew' method, we
  161. //
  162. if (AddToFiltered (item, false) && Grouping && CurrentAddItem == null)
  163. RootGroup.AddInSubtree (item, Culture, GroupDescriptions);
  164. }
  165. void AddToFilteredAndGroupSorted (object item)
  166. {
  167. // If we're adding an item because of a call to the 'AddNew' method, we
  168. //
  169. if (AddToFiltered (item, true) && Grouping && CurrentAddItem == null)
  170. RootGroup.AddInSubtree (item, Culture, GroupDescriptions);
  171. }
  172. void RemoveFromFilteredAndGroup (object item)
  173. {
  174. if (RemoveFromFiltered (item) || true) {
  175. RootGroup.RemoveInSubtree (item);
  176. }
  177. }
  178. bool AddToFiltered (object item, bool sorted)
  179. {
  180. // If we are not adding a new item and we have a filter, see if the item passes the filter
  181. if (CurrentAddItem == null && Filter != null)
  182. if (!Filter (item))
  183. return false;
  184. // Only do a sorted insert if we are not adding a new item
  185. if (CurrentAddItem == null && sorted && SortDescriptions.Count > 0) {
  186. int index = filteredList.BinarySearch (item, new PropertyComparer (SortDescriptions));
  187. if (index < 0)
  188. index = ~index;
  189. filteredList.Insert (index, item);
  190. } else {
  191. // If we're not sorting we need to keep the items in the filtered list
  192. // in the same order as they are in the SourceCollection.
  193. int insertIndex;
  194. if (Filter == null) {
  195. insertIndex = SourceCollection.IndexOf (item);
  196. } else {
  197. insertIndex = -1;
  198. for (int i = 0; i < SourceCollection.Count; i ++) {
  199. if (Filter (SourceCollection [i]))
  200. insertIndex ++;
  201. if (SourceCollection [i] == item)
  202. break;
  203. }
  204. // If everything is filtered out except for this item, we insert at 0.
  205. // This can happen if the Filter returns false for everything and we use 'AddNew'.
  206. if (insertIndex == -1)
  207. insertIndex = 0;
  208. // If some items are filtered out, SourceCollection.Count will be greater than filteredList.Count
  209. // so ensure that if we are inserting at the end of the list we don't exceed the filteredList Count.
  210. insertIndex = Math.Min (insertIndex, filteredList.Count);
  211. }
  212. filteredList.Insert (Math.Min (insertIndex, filteredList.Count), item);
  213. }
  214. return true;
  215. }
  216. bool RemoveFromFiltered (object item)
  217. {
  218. return filteredList.Remove (item);
  219. }
  220. int IComparer<object>.Compare (object x, object y)
  221. {
  222. return IndexOf (x) - IndexOf (y);
  223. }
  224. public override bool Contains (object item)
  225. {
  226. ThrowIfDeferred ();
  227. return ActiveList.Contains (item);
  228. }
  229. public override IDisposable DeferRefresh ()
  230. {
  231. if (IsAddingNew || IsEditingItem)
  232. throw new InvalidOperationException ("Cannot defer refresh while adding or editing");
  233. return new Deferrer (this);
  234. }
  235. public override IEnumerator GetEnumerator ()
  236. {
  237. if (GroupDescriptions.Count > 0 && RootGroup != null)
  238. return new GroupEnumerator (RootGroup);
  239. return ActiveList.GetEnumerator ();
  240. }
  241. int IndexOf (object item)
  242. {
  243. if (Grouping)
  244. return RootGroup.IndexOfSubtree (item);
  245. else
  246. return ActiveList.IndexOf (item);
  247. }
  248. public override bool MoveCurrentTo (object item)
  249. {
  250. return MoveCurrentTo (IndexOf (item));
  251. }
  252. bool MoveCurrentTo (int position)
  253. {
  254. return MoveCurrentTo (position, false);
  255. }
  256. object ItemAtIndex (int index)
  257. {
  258. if (Groups == null)
  259. return index < 0 || index >= ActiveList.Count ? null : ActiveList [index];
  260. foreach (var o in this) {
  261. if (index == 0)
  262. return o;
  263. index --;
  264. }
  265. return null;
  266. }
  267. bool MoveCurrentTo (int position, bool force)
  268. {
  269. return MoveCurrentTo (position, force, true);
  270. }
  271. bool MoveCurrentTo (int position, bool force, bool cancellable)
  272. {
  273. if (DeferCurrentChanged)
  274. return false;
  275. object newItem = ItemAtIndex (position);
  276. bool raiseEvents = force || CurrentItem != newItem;
  277. if (raiseEvents) {
  278. CurrentChangingEventArgs e = new CurrentChangingEventArgs (cancellable && ActiveList.Contains (CurrentItem));
  279. RaiseCurrentChanging (e);
  280. if (e.Cancel)
  281. return true;
  282. }
  283. IsCurrentAfterLast = position == ActiveList.Count || ActiveList.Count == 0;
  284. IsCurrentBeforeFirst = position == -1 || ActiveList.Count == 0;
  285. UpdateCurrentPositionAndItem (position, newItem);
  286. if (raiseEvents) {
  287. RaiseCurrentChanged (EventArgs.Empty);
  288. }
  289. return IsValidSelection;
  290. }
  291. public override bool MoveCurrentToFirst ()
  292. {
  293. ThrowIfDeferred ();
  294. return MoveCurrentTo (0);
  295. }
  296. public override bool MoveCurrentToLast ()
  297. {
  298. ThrowIfDeferred ();
  299. return MoveCurrentTo (ActiveList.Count - 1);
  300. }
  301. public override bool MoveCurrentToNext ()
  302. {
  303. ThrowIfDeferred ();
  304. return CurrentPosition != ActiveList.Count && MoveCurrentTo (CurrentPosition + 1);
  305. }
  306. public override bool MoveCurrentToPosition (int position)
  307. {
  308. ThrowIfDeferred ();
  309. return MoveCurrentTo (position);
  310. }
  311. public override bool MoveCurrentToPrevious ()
  312. {
  313. ThrowIfDeferred ();
  314. return CurrentPosition != -1 && MoveCurrentTo (CurrentPosition - 1);
  315. }
  316. public override void Refresh ()
  317. {
  318. if (IsAddingNew || IsEditingItem)
  319. throw new InvalidOperationException ("Cannot refresh while adding or editing an item");
  320. if (DeferLevel != 0)
  321. return;
  322. Groups = null;
  323. RootGroup.ClearItems ();
  324. if (ActiveList != SourceCollection) {
  325. try {
  326. IgnoreFilteredListChanges = true;
  327. filteredList.Clear ();
  328. foreach (var item in SourceCollection)
  329. AddToFiltered (item, false);
  330. if (SortDescriptions.Count > 0)
  331. filteredList.Sort (new PropertyComparer (SortDescriptions));
  332. } finally {
  333. IgnoreFilteredListChanges = false;
  334. }
  335. if (GroupDescriptions.Count > 0 && filteredList.Count > 0) {
  336. foreach (var item in filteredList)
  337. RootGroup.AddInSubtree (item, Culture, GroupDescriptions, false);
  338. Groups = RootGroup.Items;
  339. }
  340. }
  341. IsEmpty = ActiveList.Count == 0;
  342. IsCurrentAfterLast = CurrentPosition == ActiveList.Count || ActiveList.Count == 0;
  343. IsCurrentBeforeFirst = CurrentPosition == -1 || ActiveList.Count == 0;
  344. int index = IndexOf (CurrentItem);
  345. if (index < 0 && CurrentPosition != -1 && !IsEmpty)
  346. index = 0;
  347. RaiseCollectionChanged (new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Reset), false);
  348. MoveCurrentTo (index, true, false);
  349. }
  350. public override object AddNew ()
  351. {
  352. ThrowIfDeferred ();
  353. if (ItemConstructor == null)
  354. throw new InvalidOperationException ("The underlying collection does not support adding new items");
  355. if (SourceCollection.IsFixedSize)
  356. throw new InvalidOperationException ("The source collection is of fixed size");
  357. // If there's an existing AddNew or Edit, we commit it. Commit the edit first because
  358. // we're not allowed CommitNew if we're in the middle of an edit.
  359. if (IsEditingItem)
  360. CommitEdit ();
  361. if (IsAddingNew)
  362. CommitNew ();
  363. var newObject = ItemConstructor.Invoke (null);
  364. // FIXME: I need to check the ordering on the events when the source is INCC
  365. CurrentAddItem = newObject;
  366. IsAddingNew = true;
  367. if (Grouping) {
  368. RootGroup.AddItem (newObject, false, SourceCollection);
  369. HandleRootGroupCollectionChanged (RootGroup, new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Add, newObject, RootGroup.IndexOfSubtree (newObject)));
  370. }
  371. AddToSourceCollection (newObject);
  372. MoveCurrentTo (newObject);
  373. if (newObject is IEditableObject)
  374. ((IEditableObject) newObject).BeginEdit ();
  375. UpdateCanAddNewAndRemove ();
  376. return newObject;
  377. }
  378. void AddToSourceCollection (object item)
  379. {
  380. SourceCollection.Add (item);
  381. if (!(SourceCollection is INotifyCollectionChanged)) {
  382. HandleSourceCollectionChanged (SourceCollection, new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Add, item, SourceCollection.Count - 1));
  383. }
  384. }
  385. void RemoveFromSourceCollection (int index)
  386. {
  387. var item = SourceCollection [index];
  388. SourceCollection.RemoveAt (index);
  389. if (!(SourceCollection is INotifyCollectionChanged)) {
  390. HandleSourceCollectionChanged (SourceCollection, new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Remove, item, index));
  391. }
  392. }
  393. public override void CancelEdit ()
  394. {
  395. if (IsAddingNew)
  396. throw new InvalidOperationException ("Cannot cancel edit while adding new");
  397. if (IsEditingItem) {
  398. if (!CanCancelEdit)
  399. throw new InvalidOperationException ("Cannot cancel edit when CanCancelEdit is false");
  400. ((IEditableObject) CurrentEditItem).CancelEdit ();
  401. CurrentEditItem = null;
  402. IsEditingItem = false;
  403. CanCancelEdit = false;
  404. UpdateCanAddNewAndRemove ();
  405. }
  406. }
  407. public override void CancelNew ()
  408. {
  409. if (IsEditingItem)
  410. throw new InvalidOperationException ("Cannot CancelNew while editing an item");
  411. if (IsAddingNew) {
  412. if (CurrentAddItem is IEditableObject)
  413. ((IEditableObject) CurrentAddItem).CancelEdit ();
  414. if (Grouping) {
  415. RootGroup.RemoveItem (CurrentAddItem);
  416. }
  417. RemoveFromSourceCollection (SourceCollection.IndexOf (CurrentAddItem));
  418. CurrentAddItem = null;
  419. IsAddingNew = false;
  420. UpdateCanAddNewAndRemove ();
  421. }
  422. }
  423. public override void CommitEdit ()
  424. {
  425. if (IsAddingNew)
  426. throw new InvalidOperationException ("Cannot cancel edit while adding new");
  427. if (IsEditingItem) {
  428. var editItem = CurrentEditItem;
  429. CurrentEditItem = null;
  430. IsEditingItem = false;
  431. if (CanCancelEdit) {
  432. ((IEditableObject) editItem).EndEdit ();
  433. CanCancelEdit = false;
  434. }
  435. UpdateCanAddNewAndRemove ();
  436. int originalIndex = IndexOf (editItem);
  437. int newIndex;
  438. // If we're filtering the item out just nuke it
  439. if (Filter != null && !Filter (editItem)) {
  440. RemoveFromFilteredAndGroup (editItem);
  441. if (CurrentItem == editItem)
  442. MoveCurrentTo (CurrentPosition);
  443. return;
  444. }
  445. // We could also have changed the property which sorts it
  446. if (SortDescriptions.Count > 0) {
  447. // We can't just remove the item and binary search for the correct place as that will change the
  448. // order of elements which compare as equal and breaks more tests than it fixes. We need to first
  449. // check to see if the editItem is >= than the previous one and <= the next one. If that is true
  450. // we need to do nothing. Otherwise we need to binary search either the upper or lower half and
  451. // find the new index where the editItem should be placed.
  452. if (originalIndex > 0 && Comparer.Compare (filteredList [originalIndex - 1], editItem) > 0) {
  453. newIndex = filteredList.BinarySearch (0, originalIndex, editItem, Comparer);
  454. } else if (originalIndex < (filteredList.Count - 1) && Comparer.Compare (filteredList [originalIndex + 1], editItem) < 0) {
  455. newIndex = filteredList.BinarySearch (originalIndex + 1, filteredList.Count - (originalIndex + 1), editItem, Comparer);
  456. } else {
  457. // We're already in the right place.
  458. newIndex = originalIndex;
  459. }
  460. } else {
  461. // No sorting == no index change
  462. newIndex = originalIndex;
  463. }
  464. var currentSelection = CurrentItem;
  465. if (newIndex != originalIndex) {
  466. if (newIndex < 0)
  467. newIndex = ~newIndex;
  468. // When we remove the element from the original index, our newIndex will be off by 1 as everything
  469. // gets shuffled down so decrement it here.
  470. if (newIndex > originalIndex)
  471. newIndex --;
  472. DeferCurrentChanged = true;
  473. filteredList.RemoveAt (originalIndex);
  474. filteredList.Insert (newIndex, editItem);
  475. DeferCurrentChanged = false;
  476. }
  477. // We may have edited the property which controls which group the item is in
  478. // so re-seat it
  479. if (Grouping) {
  480. DeferCurrentChanged = true;
  481. RootGroup.RemoveInSubtree (editItem);
  482. RootGroup.AddInSubtree (editItem, Culture, GroupDescriptions);
  483. DeferCurrentChanged = false;
  484. MoveCurrentTo (IndexOf (currentSelection) + 1);
  485. } else if (originalIndex != newIndex) {
  486. MoveCurrentTo (IndexOf (currentSelection));
  487. }
  488. }
  489. }
  490. public override void CommitNew ()
  491. {
  492. if (IsEditingItem)
  493. throw new InvalidOperationException ("Cannot CommitNew while editing an item");
  494. if (IsAddingNew) {
  495. if (CurrentAddItem is IEditableObject)
  496. ((IEditableObject) CurrentAddItem).EndEdit ();
  497. RootGroup.RemoveInSubtree (CurrentAddItem);
  498. if (Filter != null && !Filter (CurrentAddItem)) {
  499. RemoveFromSourceCollection (SourceCollection.IndexOf (CurrentAddItem));
  500. } else {
  501. // When adding a new item, we initially put it in the root group. Once it's committed
  502. // we need to place it in the correct subtree group.
  503. if (Grouping) {
  504. RootGroup.AddInSubtree (CurrentAddItem, Culture, GroupDescriptions);
  505. }
  506. // The item was not filtered out of the tree. Do we need to resort it?
  507. if (SortDescriptions.Count > 0) {
  508. // The newly added item is at the end of the array. If we're sorting, we may have to move it.
  509. // Use a binary search to figure out where the item should be in the list and put it in there.
  510. int actualIndex = filteredList.IndexOf (CurrentAddItem);
  511. int sortedIndex = filteredList.BinarySearch (0, filteredList.Count - 1, CurrentAddItem, new PropertyComparer (SortDescriptions));
  512. if (sortedIndex < 0)
  513. sortedIndex = ~sortedIndex;
  514. if (actualIndex != sortedIndex) {
  515. MoveAndSelectFromSorted (actualIndex, sortedIndex, CurrentItem);
  516. }
  517. }
  518. }
  519. CurrentAddItem = null;
  520. IsAddingNew = false;
  521. UpdateCanAddNewAndRemove ();
  522. }
  523. }
  524. void MoveAndSelectFromSorted (int removeIndex, int addIndex, object item)
  525. {
  526. DeferCurrentChanged = true;
  527. filteredList.RemoveAt (removeIndex);
  528. filteredList.Insert (addIndex, item);
  529. DeferCurrentChanged = false;
  530. UpdateCurrentPositionAndItem (IndexOf (item), item);
  531. }
  532. public override void EditItem (object item)
  533. {
  534. // We can't edit an item which hasn't been comitted.
  535. if (IsAddingNew && item == CurrentAddItem)
  536. return;
  537. if (IsAddingNew)
  538. CommitNew ();
  539. if (IsEditingItem)
  540. CommitEdit ();
  541. CurrentEditItem = item;
  542. IsEditingItem = true;
  543. if (item is IEditableObject) {
  544. CanCancelEdit = true;
  545. ((IEditableObject) item).BeginEdit ();
  546. }
  547. UpdateCanAddNewAndRemove ();
  548. }
  549. public override void Remove (object item)
  550. {
  551. if (!CanRemove)
  552. throw new InvalidOperationException ("Removing is not supported by this collection");
  553. if (IsAddingNew || IsEditingItem)
  554. throw new InvalidOperationException ("Cannot remove an item when adding or editing an item");
  555. int index = SourceCollection.IndexOf (item);
  556. if (index != -1)
  557. RemoveFromSourceCollection (index);
  558. }
  559. public override void RemoveAt (int index)
  560. {
  561. if (!CanRemove)
  562. throw new InvalidOperationException ("Removing is not supported by this collection");
  563. if (IsAddingNew || IsEditingItem)
  564. throw new InvalidOperationException ("Cannot remove an item when adding or editing an item");
  565. RemoveFromSourceCollection (SourceCollection.IndexOf (ItemAtIndex (index)));
  566. }
  567. void UpdateCanAddNewAndRemove ()
  568. {
  569. var value = ItemConstructor != null && !SourceCollection.IsFixedSize && !IsEditingItem;
  570. if (value != CanAddNew)
  571. CanAddNew = value;
  572. value = !SourceCollection.IsFixedSize && !IsEditingItem && !IsAddingNew;
  573. if (value != CanRemove)
  574. CanRemove = value;
  575. }
  576. void UpdateCurrentPositionAndItem (int position, object item)
  577. {
  578. bool emitPositionChanged = CurrentPosition != position;
  579. bool emitItemChanged = CurrentItem != item;
  580. CurrentPosition = position;
  581. CurrentItem = item;
  582. if (emitPositionChanged)
  583. RaisePropertyChanged ("CurrentPosition");
  584. if (emitItemChanged)
  585. RaisePropertyChanged ("CurrentItem");
  586. }
  587. }
  588. }