0
|
1 using System;
|
|
2 using System.Collections;
|
|
3 using System.Collections.Specialized;
|
|
4 using System.ComponentModel;
|
|
5 using System.Diagnostics;
|
|
6 using System.Reflection;
|
|
7
|
|
8 namespace BLToolkit.EditableObjects
|
|
9 {
|
|
10 using Reflection;
|
|
11 using Mapping;
|
|
12 using ComponentModel;
|
|
13
|
|
14 [DebuggerDisplay("Count = {Count}, ItemType = {ItemType}")]
|
|
15 [Serializable]
|
|
16 public class EditableArrayList : ArrayList, IEditable, ISortable, ISupportMapping,
|
|
17 IDisposable, IPrintDebugState, ITypedList, IBindingListView, ICancelAddNew, INotifyCollectionChanged
|
|
18 {
|
|
19 #region Constructors
|
|
20
|
|
21 public EditableArrayList() : this(typeof(object), new ArrayList(), true)
|
|
22 {
|
|
23 }
|
|
24
|
|
25 public EditableArrayList([JetBrains.Annotations.NotNull] Type itemType, [JetBrains.Annotations.NotNull] ArrayList list, bool trackChanges)
|
|
26 {
|
|
27 if (itemType == null) throw new ArgumentNullException("itemType");
|
|
28 if (list == null) throw new ArgumentNullException("list");
|
|
29
|
|
30 ItemType = itemType;
|
|
31 List = list;
|
|
32
|
|
33 _noTrackingChangesCount++;
|
|
34 AddInternal(List);
|
|
35 _noTrackingChangesCount--;
|
|
36
|
|
37 if (!trackChanges)
|
|
38 {
|
|
39 SetTrackingChanges(false);
|
|
40 _minTrackingChangesCount = 1;
|
|
41 }
|
|
42 }
|
|
43
|
|
44 public EditableArrayList(Type itemType)
|
|
45 : this(itemType, new ArrayList(), true)
|
|
46 {
|
|
47 }
|
|
48
|
|
49 public EditableArrayList(Type itemType, bool trackChanges)
|
|
50 : this(itemType, new ArrayList(), trackChanges)
|
|
51 {
|
|
52 }
|
|
53
|
|
54 public EditableArrayList(Type itemType, int capacity)
|
|
55 : this(itemType, new ArrayList(capacity), true)
|
|
56 {
|
|
57 }
|
|
58
|
|
59 public EditableArrayList(Type itemType, int capacity, bool trackChanges)
|
|
60 : this(itemType, new ArrayList(capacity), trackChanges)
|
|
61 {
|
|
62 }
|
|
63
|
|
64 public EditableArrayList(Type itemType, ICollection c)
|
|
65 : this(itemType, new ArrayList(c), true)
|
|
66 {
|
|
67 }
|
|
68
|
|
69 public EditableArrayList(Type itemType, ICollection c, bool trackChanges)
|
|
70 : this(itemType, new ArrayList(c), trackChanges)
|
|
71 {
|
|
72 }
|
|
73
|
|
74 public EditableArrayList(Type itemType, ArrayList list)
|
|
75 : this(itemType, list, true)
|
|
76 {
|
|
77 }
|
|
78
|
|
79 public EditableArrayList(EditableArrayList list)
|
|
80 : this(list.ItemType, new ArrayList(list), true)
|
|
81 {
|
|
82 }
|
|
83
|
|
84 public EditableArrayList(EditableArrayList list, bool trackChanges)
|
|
85 : this(list.ItemType, new ArrayList(list), trackChanges)
|
|
86 {
|
|
87 }
|
|
88
|
|
89 public EditableArrayList(Type itemType, EditableArrayList list)
|
|
90 : this(itemType, new ArrayList(list), true)
|
|
91 {
|
|
92 }
|
|
93
|
|
94 public EditableArrayList(Type itemType, EditableArrayList list, bool trackChanges)
|
|
95 : this(itemType, new ArrayList(list), trackChanges)
|
|
96 {
|
|
97 }
|
|
98
|
|
99 #endregion
|
|
100
|
|
101 #region Public Members
|
|
102
|
|
103 internal ArrayList List { get; private set; }
|
|
104 public Type ItemType { get; private set; }
|
|
105
|
|
106 private ArrayList _newItems;
|
|
107 public ArrayList NewItems
|
|
108 {
|
|
109 get { return _newItems ?? (_newItems = new ArrayList()); }
|
|
110 }
|
|
111
|
|
112 private ArrayList _delItems;
|
|
113 public ArrayList DelItems
|
|
114 {
|
|
115 get { return _delItems ?? (_delItems = new ArrayList()); }
|
|
116 }
|
|
117
|
|
118 public void Sort(params string[] memberNames)
|
|
119 {
|
|
120 Sort(ListSortDirection.Ascending, memberNames);
|
|
121 }
|
|
122
|
|
123 public void Sort(ListSortDirection direction, params string[] memberNames)
|
|
124 {
|
|
125 if (memberNames == null) throw new ArgumentNullException ("memberNames");
|
|
126 if (memberNames.Length == 0) throw new ArgumentOutOfRangeException("memberNames");
|
|
127
|
|
128 Sort(new SortMemberComparer(TypeAccessor.GetAccessor(ItemType), direction, memberNames));
|
|
129 }
|
|
130
|
|
131 public void SortEx(string sortExpression)
|
|
132 {
|
|
133 var sorts = sortExpression.Split(',');
|
|
134
|
|
135 for (var i = 0; i < sorts.Length; i++)
|
|
136 sorts[i] = sorts[i].Trim();
|
|
137
|
|
138 var last = sorts[sorts.Length - 1];
|
|
139 var desc = last.ToLower().EndsWith(" desc");
|
|
140
|
|
141 if (desc)
|
|
142 sorts[sorts.Length - 1] = last.Substring(0, last.Length - " desc".Length);
|
|
143
|
|
144 Sort(desc? ListSortDirection.Descending: ListSortDirection.Ascending, sorts);
|
|
145 }
|
|
146
|
|
147 public void Move(int newIndex, int oldIndex)
|
|
148 {
|
|
149 BindingListImpl.Move(newIndex, oldIndex);
|
|
150 }
|
|
151
|
|
152 public void Move(int newIndex, object item)
|
|
153 {
|
|
154 lock (SyncRoot)
|
|
155 {
|
|
156 var index = IndexOf(item);
|
|
157
|
|
158 if (index >= 0)
|
|
159 Move(newIndex, index);
|
|
160 }
|
|
161 }
|
|
162
|
|
163 #endregion
|
|
164
|
|
165 #region Change Notification
|
|
166
|
|
167 public bool NotifyChanges
|
|
168 {
|
|
169 get { return BindingListImpl.NotifyChanges; }
|
|
170 set { BindingListImpl.NotifyChanges = value; }
|
|
171 }
|
|
172
|
|
173 protected virtual void OnListChanged(ListChangedEventArgs e)
|
|
174 {
|
|
175 if (!_supressEvent && NotifyChanges && ListChanged != null)
|
|
176 ListChanged(this, e);
|
|
177 }
|
|
178
|
|
179 protected void OnListChanged(ListChangedType listChangedType, int index)
|
|
180 {
|
|
181 OnListChanged(new EditableListChangedEventArgs(listChangedType, index));
|
|
182 }
|
|
183
|
|
184 private void OnResetList()
|
|
185 {
|
|
186 OnListChanged(ListChangedType.Reset, -1);
|
|
187 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
|
188 }
|
|
189
|
|
190 private void OnAddItem(object newObject, int index)
|
|
191 {
|
|
192 OnListChanged(ListChangedType.ItemAdded, index);
|
|
193 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newObject, index));
|
|
194 }
|
|
195
|
|
196 #endregion
|
|
197
|
|
198 #region Add/Remove Internal
|
|
199
|
|
200 void AddInternal(object value)
|
|
201 {
|
|
202 if (IsTrackingChanges)
|
|
203 {
|
|
204 if (DelItems.Contains(value))
|
|
205 DelItems.Remove(value);
|
|
206 else
|
|
207 NewItems.Add(value);
|
|
208 }
|
|
209
|
|
210 OnAdd(value);
|
|
211 }
|
|
212
|
|
213 private void RemoveInternal(object value)
|
|
214 {
|
|
215 if (IsTrackingChanges)
|
|
216 {
|
|
217 if (NewItems.Contains(value))
|
|
218 NewItems.Remove(value);
|
|
219 else
|
|
220 DelItems.Add(value);
|
|
221 }
|
|
222
|
|
223 OnRemove(value);
|
|
224 }
|
|
225
|
|
226 private void AddInternal(IEnumerable e)
|
|
227 {
|
|
228 foreach (var o in e)
|
|
229 AddInternal(o);
|
|
230 }
|
|
231
|
|
232 private void RemoveInternal(IEnumerable e)
|
|
233 {
|
|
234 foreach (var o in e)
|
|
235 RemoveInternal(o);
|
|
236 }
|
|
237
|
|
238 protected virtual void OnAdd(object value)
|
|
239 {
|
|
240 }
|
|
241
|
|
242 protected virtual void OnRemove(object value)
|
|
243 {
|
|
244 }
|
|
245
|
|
246 #endregion
|
|
247
|
|
248 #region Track Changes
|
|
249
|
|
250 private int _noTrackingChangesCount;
|
|
251 private readonly int _minTrackingChangesCount;
|
|
252
|
|
253 public bool IsTrackingChanges
|
|
254 {
|
|
255 get { return _noTrackingChangesCount == 0; }
|
|
256 }
|
|
257
|
|
258 protected void SetTrackingChanges(bool trackChanges)
|
|
259 {
|
|
260 if (trackChanges)
|
|
261 {
|
|
262 _noTrackingChangesCount--;
|
|
263
|
|
264 if (_noTrackingChangesCount < _minTrackingChangesCount)
|
|
265 {
|
|
266 _noTrackingChangesCount = _minTrackingChangesCount;
|
|
267 throw new InvalidOperationException("Tracking Changes Counter can not be negative.");
|
|
268 }
|
|
269 }
|
|
270 else
|
|
271 {
|
|
272 _noTrackingChangesCount++;
|
|
273 }
|
|
274 }
|
|
275
|
|
276 #endregion
|
|
277
|
|
278 #region ISupportMapping Members
|
|
279
|
|
280 public virtual void BeginMapping(InitContext initContext)
|
|
281 {
|
|
282 if (initContext.IsDestination)
|
|
283 _noTrackingChangesCount++;
|
|
284 }
|
|
285
|
|
286 public virtual void EndMapping(InitContext initContext)
|
|
287 {
|
|
288 if (initContext.IsDestination)
|
|
289 {
|
|
290 AcceptChanges();
|
|
291 _noTrackingChangesCount--;
|
|
292 }
|
|
293 }
|
|
294
|
|
295 #endregion
|
|
296
|
|
297 #region IEditable Members
|
|
298
|
|
299 public virtual void AcceptChanges()
|
|
300 {
|
|
301 foreach (var o in List)
|
|
302 {
|
|
303 if (o is EditableObject)
|
|
304 ((EditableObject)o).AcceptChanges();
|
|
305 else if (o is IEditable)
|
|
306 ((IEditable)o).AcceptChanges();
|
|
307 }
|
|
308
|
|
309 _newItems = null;
|
|
310 _delItems = null;
|
|
311 }
|
|
312
|
|
313 public virtual void RejectChanges()
|
|
314 {
|
|
315 _noTrackingChangesCount++;
|
|
316
|
|
317 if (_delItems != null)
|
|
318 foreach (var o in _delItems)
|
|
319 Add(o);
|
|
320
|
|
321 if (_newItems != null)
|
|
322 foreach (var o in _newItems)
|
|
323 Remove(o);
|
|
324
|
|
325 foreach (var o in List)
|
|
326 {
|
|
327 if (o is EditableObject)
|
|
328 ((EditableObject)o).RejectChanges();
|
|
329 else if (o is IEditable)
|
|
330 ((IEditable)o).RejectChanges();
|
|
331 }
|
|
332
|
|
333 _noTrackingChangesCount--;
|
|
334
|
|
335 _newItems = null;
|
|
336 _delItems = null;
|
|
337 }
|
|
338
|
|
339 public virtual bool IsDirty
|
|
340 {
|
|
341 get
|
|
342 {
|
|
343 if (_newItems != null && _newItems.Count > 0 ||
|
|
344 _delItems != null && _delItems.Count > 0)
|
|
345 return true;
|
|
346
|
|
347 foreach (var o in List)
|
|
348 {
|
|
349 if (o is EditableObject)
|
|
350 if (((EditableObject)o).IsDirty)
|
|
351 return true;
|
|
352 else if (o is IEditable)
|
|
353 if (((IEditable)o).IsDirty)
|
|
354 return true;
|
|
355 }
|
|
356
|
|
357 return false;
|
|
358 }
|
|
359 }
|
|
360
|
|
361 void IPrintDebugState.PrintDebugState(PropertyInfo propertyInfo, ref string str)
|
|
362 {
|
|
363 var original = List.Count
|
|
364 - (_newItems == null? 0: _newItems.Count)
|
|
365 + (_delItems == null? 0: _delItems.Count);
|
|
366
|
|
367 str += string.Format("{0,-20} {1} {2,-40} {3,-40} \r\n",
|
|
368 propertyInfo.Name, IsDirty? "*": " ", original, List.Count);
|
|
369 }
|
|
370
|
|
371 #endregion
|
|
372
|
|
373 #region IList Members
|
|
374
|
|
375 public override bool IsFixedSize
|
|
376 {
|
|
377 get { return BindingListImpl.IsFixedSize; }
|
|
378 }
|
|
379
|
|
380 public override bool IsReadOnly
|
|
381 {
|
|
382 get { return BindingListImpl.IsReadOnly; }
|
|
383 }
|
|
384
|
|
385 public override object this[int index]
|
|
386 {
|
|
387 get { return BindingListImpl[index]; }
|
|
388 set
|
|
389 {
|
|
390 var o = BindingListImpl[index];
|
|
391
|
|
392 if (o != value)
|
|
393 {
|
|
394 RemoveInternal(o);
|
|
395 AddInternal(value);
|
|
396 }
|
|
397
|
|
398 BindingListImpl[index] = value;
|
|
399 }
|
|
400 }
|
|
401
|
|
402 public override int Add(object value)
|
|
403 {
|
|
404 AddInternal(value);
|
|
405
|
|
406 return BindingListImpl.Add(value);
|
|
407 }
|
|
408
|
|
409 public override void Clear()
|
|
410 {
|
|
411 if (List.Count > 0)
|
|
412 RemoveInternal(List);
|
|
413
|
|
414 BindingListImpl.Clear();
|
|
415 }
|
|
416
|
|
417 public override bool Contains(object item)
|
|
418 {
|
|
419 return BindingListImpl.Contains(item);
|
|
420 }
|
|
421
|
|
422 public override int IndexOf(object value)
|
|
423 {
|
|
424 return BindingListImpl.IndexOf(value);
|
|
425 }
|
|
426
|
|
427 public override void Insert(int index, object value)
|
|
428 {
|
|
429 AddInternal(value);
|
|
430
|
|
431 BindingListImpl.Insert(index, value);
|
|
432 }
|
|
433
|
|
434 public override void Remove(object value)
|
|
435 {
|
|
436 RemoveInternal(value);
|
|
437
|
|
438 BindingListImpl.Remove(value);
|
|
439 }
|
|
440
|
|
441 public override void RemoveAt(int index)
|
|
442 {
|
|
443 RemoveInternal(BindingListImpl[index]);
|
|
444
|
|
445 BindingListImpl.RemoveAt(index);
|
|
446 }
|
|
447
|
|
448 #endregion
|
|
449
|
|
450 #region ICollection Members
|
|
451
|
|
452 public override int Count
|
|
453 {
|
|
454 get { return BindingListImpl.Count; }
|
|
455 }
|
|
456
|
|
457 public override bool IsSynchronized
|
|
458 {
|
|
459 get { return BindingListImpl.IsSynchronized; }
|
|
460 }
|
|
461
|
|
462 public override object SyncRoot
|
|
463 {
|
|
464 get { return BindingListImpl.SyncRoot; }
|
|
465 }
|
|
466
|
|
467 public override void CopyTo(Array array, int arrayIndex)
|
|
468 {
|
|
469 BindingListImpl.CopyTo(array, arrayIndex);
|
|
470 }
|
|
471
|
|
472 #endregion
|
|
473
|
|
474 #region IEnumerable Members
|
|
475
|
|
476 public override IEnumerator GetEnumerator()
|
|
477 {
|
|
478 return BindingListImpl.GetEnumerator();
|
|
479 }
|
|
480
|
|
481 #endregion
|
|
482
|
|
483 #region Overridden Methods
|
|
484
|
|
485 public int Add(object value, bool trackChanges)
|
|
486 {
|
|
487 if (!trackChanges) _noTrackingChangesCount++;
|
|
488 var idx = Add(value);
|
|
489 if (!trackChanges) _noTrackingChangesCount--;
|
|
490
|
|
491 return idx;
|
|
492 }
|
|
493
|
|
494 public override void AddRange(ICollection c)
|
|
495 {
|
|
496 if (c.Count == 0)
|
|
497 return;
|
|
498
|
|
499 AddInternal(c);
|
|
500
|
|
501 BindingListImpl.AddRange(c);
|
|
502 }
|
|
503
|
|
504 public void AddRange(ICollection c, bool trackChanges)
|
|
505 {
|
|
506 if (c.Count == 0)
|
|
507 return;
|
|
508
|
|
509 if (!trackChanges) _noTrackingChangesCount++;
|
|
510 AddRange(c);
|
|
511 if (!trackChanges) _noTrackingChangesCount--;
|
|
512 }
|
|
513
|
|
514 public override int BinarySearch(int index, int count, object value, IComparer comparer)
|
|
515 {
|
|
516 return List.BinarySearch(index, count, value, comparer);
|
|
517 }
|
|
518
|
|
519 public override int BinarySearch(object value)
|
|
520 {
|
|
521 return List.BinarySearch(value);
|
|
522 }
|
|
523
|
|
524 public override int BinarySearch(object value, IComparer comparer)
|
|
525 {
|
|
526 return List.BinarySearch(value, comparer);
|
|
527 }
|
|
528
|
|
529 public override int Capacity
|
|
530 {
|
|
531 get { return List.Capacity; }
|
|
532 set { List.Capacity = value; }
|
|
533 }
|
|
534
|
|
535 public void Clear(bool trackChanges)
|
|
536 {
|
|
537 if (!trackChanges) _noTrackingChangesCount++;
|
|
538 Clear();
|
|
539 if (!trackChanges) _noTrackingChangesCount--;
|
|
540 }
|
|
541
|
|
542 protected EditableArrayList Clone(EditableArrayList el)
|
|
543 {
|
|
544 if (_newItems != null) el._newItems = (ArrayList)_newItems.Clone();
|
|
545 if (_delItems != null) el._delItems = (ArrayList)_delItems.Clone();
|
|
546
|
|
547 el.NotifyChanges = NotifyChanges;
|
|
548 el._noTrackingChangesCount = _noTrackingChangesCount;
|
|
549
|
|
550 return el;
|
|
551 }
|
|
552
|
|
553 public override object Clone()
|
|
554 {
|
|
555 return Clone(new EditableArrayList(ItemType, (ArrayList)List.Clone()));
|
|
556 }
|
|
557
|
|
558 public override void CopyTo(int index, Array array, int arrayIndex, int count)
|
|
559 {
|
|
560 List.CopyTo(index, array, arrayIndex, count);
|
|
561 }
|
|
562
|
|
563 public override void CopyTo(Array array)
|
|
564 {
|
|
565 List.CopyTo(array);
|
|
566 }
|
|
567
|
|
568 public override bool Equals(object obj)
|
|
569 {
|
|
570 return List.Equals(obj);
|
|
571 }
|
|
572
|
|
573 public override IEnumerator GetEnumerator(int index, int count)
|
|
574 {
|
|
575 return List.GetEnumerator(index, count);
|
|
576 }
|
|
577
|
|
578 public override int GetHashCode()
|
|
579 {
|
|
580 return List.GetHashCode();
|
|
581 }
|
|
582
|
|
583 public override ArrayList GetRange(int index, int count)
|
|
584 {
|
|
585 return List.GetRange(index, count);
|
|
586 }
|
|
587
|
|
588 public override int IndexOf(object value, int startIndex)
|
|
589 {
|
|
590 return List.IndexOf(value, startIndex);
|
|
591 }
|
|
592
|
|
593 public override int IndexOf(object value, int startIndex, int count)
|
|
594 {
|
|
595 return List.IndexOf(value, startIndex, count);
|
|
596 }
|
|
597
|
|
598 public void Insert(int index, object value, bool trackChanges)
|
|
599 {
|
|
600 if (!trackChanges) _noTrackingChangesCount++;
|
|
601 Insert(index, value);
|
|
602 if (!trackChanges) _noTrackingChangesCount--;
|
|
603 }
|
|
604
|
|
605 public override void InsertRange(int index, ICollection c)
|
|
606 {
|
|
607 BindingListImpl.InsertRange(index, c);
|
|
608 }
|
|
609
|
|
610 public void InsertRange(int index, ICollection c, bool trackChanges)
|
|
611 {
|
|
612 if (!trackChanges) _noTrackingChangesCount++;
|
|
613 InsertRange(index, c);
|
|
614 if (!trackChanges) _noTrackingChangesCount--;
|
|
615 }
|
|
616
|
|
617 public override int LastIndexOf(object value)
|
|
618 {
|
|
619 return List.LastIndexOf(value);
|
|
620 }
|
|
621
|
|
622 public override int LastIndexOf(object value, int startIndex)
|
|
623 {
|
|
624 return List.LastIndexOf(value, startIndex);
|
|
625 }
|
|
626
|
|
627 public override int LastIndexOf(object value, int startIndex, int count)
|
|
628 {
|
|
629 return List.LastIndexOf(value, startIndex, count);
|
|
630 }
|
|
631
|
|
632 public void Remove(object obj, bool trackChanges)
|
|
633 {
|
|
634 if (!trackChanges) _noTrackingChangesCount++;
|
|
635 Remove(obj);
|
|
636 if (!trackChanges) _noTrackingChangesCount--;
|
|
637 }
|
|
638
|
|
639 public void RemoveAt(int index, bool trackChanges)
|
|
640 {
|
|
641 if (!trackChanges) _noTrackingChangesCount++;
|
|
642 RemoveAt(index);
|
|
643 if (!trackChanges) _noTrackingChangesCount--;
|
|
644 }
|
|
645
|
|
646 public override void RemoveRange(int index, int count)
|
|
647 {
|
|
648 RemoveInternal(GetRange(index, count));
|
|
649
|
|
650 BindingListImpl.RemoveRange(index, count);
|
|
651 }
|
|
652
|
|
653 public void RemoveRange(int index, int count, bool trackChanges)
|
|
654 {
|
|
655 if (!trackChanges) _noTrackingChangesCount++;
|
|
656 RemoveRange(index, count);
|
|
657 if (!trackChanges) _noTrackingChangesCount--;
|
|
658 }
|
|
659
|
|
660 public override void Reverse()
|
|
661 {
|
|
662 BindingListImpl.EndNew();
|
|
663
|
|
664 if (!BindingListImpl.IsSorted)
|
|
665 List.Reverse();
|
|
666 else
|
|
667 throw new InvalidOperationException("Reverse is not supported for already sorted arrays. Invoke IBindingList.RemoveSort() first or provide reverse sort direction.");
|
|
668
|
|
669 if (List.Count > 1)
|
|
670 OnResetList();
|
|
671 }
|
|
672
|
|
673 public override void Reverse(int index, int count)
|
|
674 {
|
|
675 BindingListImpl.EndNew();
|
|
676
|
|
677 if (!BindingListImpl.IsSorted)
|
|
678 List.Reverse(index, count);
|
|
679 else
|
|
680 throw new InvalidOperationException("Range Reverse is not supported for already sorted arrays. Invoke IBindingList.RemoveSort() first.");
|
|
681
|
|
682 if (count > 1)
|
|
683 OnResetList();
|
|
684 }
|
|
685
|
|
686 public override void SetRange(int index, ICollection c)
|
|
687 {
|
|
688 if (c.Count == 0)
|
|
689 return;
|
|
690
|
|
691 AddInternal(c);
|
|
692
|
|
693 BindingListImpl.SetRange(index, c);
|
|
694 }
|
|
695
|
|
696 public override void Sort()
|
|
697 {
|
|
698 BindingListImpl.EndNew();
|
|
699
|
|
700 if (!BindingListImpl.IsSorted)
|
|
701 {
|
|
702 List.Sort();
|
|
703
|
|
704 if (List.Count > 1)
|
|
705 OnResetList();
|
|
706 }
|
|
707 else
|
|
708 {
|
|
709 if (BindingListImpl.SortProperty != null)
|
|
710 BindingListImpl.ApplySort(BindingListImpl.SortProperty, BindingListImpl.SortDirection);
|
|
711 else if (BindingListImpl.SortDescriptions != null)
|
|
712 BindingListImpl.ApplySort(BindingListImpl.SortDescriptions);
|
|
713 else
|
|
714 throw new InvalidOperationException("Currently applied sort method is not recognized/supported by EditableArrayList.");
|
|
715 }
|
|
716 }
|
|
717
|
|
718 public override void Sort(int index, int count, IComparer comparer)
|
|
719 {
|
|
720 BindingListImpl.EndNew();
|
|
721
|
|
722 if (!BindingListImpl.IsSorted)
|
|
723 List.Sort(index, count, comparer);
|
|
724 else
|
|
725 throw new InvalidOperationException("Custom sorting is not supported on already sorted arrays. Invoke IBindingList.RemoveSort first.");
|
|
726
|
|
727 if (count > 1)
|
|
728 OnResetList();
|
|
729 }
|
|
730
|
|
731 public override void Sort(IComparer comparer)
|
|
732 {
|
|
733 BindingListImpl.EndNew();
|
|
734
|
|
735 if (!BindingListImpl.IsSorted)
|
|
736 List.Sort(comparer);
|
|
737 else
|
|
738 throw new InvalidOperationException("Custom sorting is not supported on already sorted arrays. Invoke IBindingList.RemoveSort first.");
|
|
739
|
|
740 if (List.Count > 1)
|
|
741 OnResetList();
|
|
742 }
|
|
743
|
|
744 public override object[] ToArray()
|
|
745 {
|
|
746 return List.ToArray();
|
|
747 }
|
|
748
|
|
749 public override Array ToArray(Type type)
|
|
750 {
|
|
751 return List.ToArray(type);
|
|
752 }
|
|
753
|
|
754 public override string ToString()
|
|
755 {
|
|
756 return List.ToString();
|
|
757 }
|
|
758
|
|
759 public override void TrimToSize()
|
|
760 {
|
|
761 List.TrimToSize();
|
|
762 }
|
|
763
|
|
764 #endregion
|
|
765
|
|
766 #region Static Methods
|
|
767
|
|
768 public static EditableArrayList Adapter(Type itemType, IList list)
|
|
769 {
|
|
770 if (list == null) throw new ArgumentNullException("list");
|
|
771
|
|
772 if (list.IsFixedSize)
|
|
773 return new EditableArrayList(itemType, new ArrayList(list));
|
|
774
|
|
775 return list is ArrayList?
|
|
776 new EditableArrayList(itemType, (ArrayList)list):
|
|
777 new EditableArrayList(itemType, ArrayList.Adapter(list));
|
|
778 }
|
|
779
|
|
780 public static new EditableArrayList Adapter(IList list)
|
|
781 {
|
|
782 return Adapter(TypeHelper.GetListItemType(list), list);
|
|
783 }
|
|
784
|
|
785 #endregion
|
|
786
|
|
787 #region IDisposable
|
|
788
|
|
789 public void Dispose()
|
|
790 {
|
|
791 Clear();
|
|
792 }
|
|
793
|
|
794 #endregion
|
|
795
|
|
796 #region SortMemberComparer
|
|
797
|
|
798 class SortMemberComparer : IComparer
|
|
799 {
|
|
800 readonly ListSortDirection _direction;
|
|
801 readonly string[] _memberNames;
|
|
802 readonly TypeAccessor _typeAccessor;
|
|
803 readonly MemberAccessor[] _members;
|
|
804 readonly MemberAccessor _member;
|
|
805
|
|
806 public SortMemberComparer(TypeAccessor typeAccessor, ListSortDirection direction, string[] memberNames)
|
|
807 {
|
|
808 _typeAccessor = typeAccessor;
|
|
809 _direction = direction;
|
|
810 _memberNames = memberNames;
|
|
811 _members = new MemberAccessor[memberNames.Length];
|
|
812
|
|
813 _member = _members[0] = _typeAccessor[memberNames[0]];
|
|
814
|
|
815 if (_member == null)
|
|
816 throw new InvalidOperationException(
|
|
817 string.Format("Field '{0}.{1}' not found.",
|
|
818 _typeAccessor.OriginalType.Name, _memberNames[0]));
|
|
819 }
|
|
820
|
|
821 public int Compare(object x, object y)
|
|
822 {
|
|
823 var a = _member.GetValue(x);
|
|
824 var b = _member.GetValue(y);
|
|
825 var n = Comparer.Default.Compare(a, b);
|
|
826
|
|
827 if (n == 0) for (var i = 1; n == 0 && i < _members.Length; i++)
|
|
828 {
|
|
829 var member = _members[i];
|
|
830
|
|
831 if (member == null)
|
|
832 {
|
|
833 member = _members[i] = _typeAccessor[_memberNames[i]];
|
|
834
|
|
835 if (member == null)
|
|
836 throw new InvalidOperationException(
|
|
837 string.Format("Field '{0}.{1}' not found.",
|
|
838 _typeAccessor.OriginalType.Name, _memberNames[i]));
|
|
839 }
|
|
840
|
|
841 a = member.GetValue(x);
|
|
842 b = member.GetValue(y);
|
|
843 n = Comparer.Default.Compare(a, b);
|
|
844 }
|
|
845
|
|
846 return _direction == ListSortDirection.Ascending? n: -n;
|
|
847 }
|
|
848 }
|
|
849
|
|
850 #endregion
|
|
851
|
|
852 #region ITypedList Members
|
|
853
|
|
854 [NonSerialized]
|
|
855 private TypedListImpl _typedListImpl;
|
|
856 private TypedListImpl TypedListImpl
|
|
857 {
|
|
858 get { return _typedListImpl ?? (_typedListImpl = new TypedListImpl(ItemType)); }
|
|
859 }
|
|
860
|
|
861 public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
|
|
862 {
|
|
863 return GetItemProperties(listAccessors, null, null, true);
|
|
864 }
|
|
865
|
|
866 public PropertyDescriptorCollection GetItemProperties(
|
|
867 PropertyDescriptor[] listAccessors,
|
|
868 Type objectViewType,
|
|
869 IsNullHandler isNull,
|
|
870 bool cache)
|
|
871 {
|
|
872 return TypedListImpl.GetItemProperties(listAccessors, objectViewType, isNull, cache);
|
|
873 }
|
|
874
|
|
875 public string GetListName(PropertyDescriptor[] listAccessors)
|
|
876 {
|
|
877 return TypedListImpl.GetListName(listAccessors);
|
|
878 }
|
|
879
|
|
880 #endregion
|
|
881
|
|
882 #region IBindingList Members
|
|
883
|
|
884 sealed class BindingListImplInternal : BindingListImpl
|
|
885 {
|
|
886 readonly EditableArrayList _owner;
|
|
887
|
|
888 public BindingListImplInternal(IList list, Type itemType, EditableArrayList owner)
|
|
889 : base(list, itemType)
|
|
890 {
|
|
891 _owner = owner;
|
|
892 }
|
|
893
|
|
894 protected override void OnListChanged(EditableListChangedEventArgs e)
|
|
895 {
|
|
896 _owner.OnListChanged(e);
|
|
897 }
|
|
898
|
|
899 protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs ea)
|
|
900 {
|
|
901 _owner.OnCollectionChanged(ea);
|
|
902 }
|
|
903 }
|
|
904
|
|
905 [NonSerialized]
|
|
906 private BindingListImpl _bindingListImpl;
|
|
907 private BindingListImpl BindingListImpl
|
|
908 {
|
|
909 get { return _bindingListImpl ?? (_bindingListImpl = new BindingListImplInternal(List, ItemType, this)); }
|
|
910 }
|
|
911
|
|
912 public void AddIndex(PropertyDescriptor property)
|
|
913 {
|
|
914 BindingListImpl.AddIndex(property);
|
|
915 }
|
|
916
|
|
917 public object AddNew()
|
|
918 {
|
|
919 object newObject;
|
|
920
|
|
921 try
|
|
922 {
|
|
923 BeginSuppressEvent();
|
|
924 newObject = BindingListImpl.AddNew();
|
|
925 }
|
|
926 finally
|
|
927 {
|
|
928 EndSuppressEvent();
|
|
929 }
|
|
930
|
|
931 AddInternal(newObject);
|
|
932
|
|
933 var index = IndexOf(newObject);
|
|
934
|
|
935 EndSuppressEvent();
|
|
936 OnAddItem(newObject, index);
|
|
937
|
|
938 return newObject;
|
|
939 }
|
|
940
|
|
941 public bool AllowEdit
|
|
942 {
|
|
943 get { return BindingListImpl.AllowEdit; }
|
|
944 }
|
|
945
|
|
946 public bool AllowNew
|
|
947 {
|
|
948 get { return BindingListImpl.AllowNew; }
|
|
949 }
|
|
950
|
|
951 public bool AllowRemove
|
|
952 {
|
|
953 get { return BindingListImpl.AllowRemove; }
|
|
954 }
|
|
955
|
|
956 public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
|
|
957 {
|
|
958 BindingListImpl.ApplySort(property, direction);
|
|
959 }
|
|
960
|
|
961 public int Find(PropertyDescriptor property, object key)
|
|
962 {
|
|
963 return BindingListImpl.Find(property, key);
|
|
964 }
|
|
965
|
|
966 public bool IsSorted
|
|
967 {
|
|
968 get { return BindingListImpl.IsSorted; }
|
|
969 }
|
|
970
|
|
971 public void RemoveIndex(PropertyDescriptor property)
|
|
972 {
|
|
973 BindingListImpl.RemoveIndex(property);
|
|
974 }
|
|
975
|
|
976 public void RemoveSort()
|
|
977 {
|
|
978 BindingListImpl.RemoveSort();
|
|
979 }
|
|
980
|
|
981 public ListSortDirection SortDirection
|
|
982 {
|
|
983 get { return BindingListImpl.SortDirection; }
|
|
984 }
|
|
985
|
|
986 public PropertyDescriptor SortProperty
|
|
987 {
|
|
988 get { return BindingListImpl.SortProperty; }
|
|
989 }
|
|
990
|
|
991 public bool SupportsChangeNotification
|
|
992 {
|
|
993 get { return BindingListImpl.SupportsChangeNotification; }
|
|
994 }
|
|
995
|
|
996 public event ListChangedEventHandler ListChanged;
|
|
997
|
|
998 private bool _supressEvent;
|
|
999
|
|
1000 private void BeginSuppressEvent()
|
|
1001 {
|
|
1002 _supressEvent = true;
|
|
1003 }
|
|
1004
|
|
1005 private void EndSuppressEvent()
|
|
1006 {
|
|
1007 _supressEvent = false;
|
|
1008 }
|
|
1009
|
|
1010 public bool SupportsSearching
|
|
1011 {
|
|
1012 get { return BindingListImpl.SupportsSearching; }
|
|
1013 }
|
|
1014
|
|
1015 public bool SupportsSorting
|
|
1016 {
|
|
1017 get { return BindingListImpl.SupportsSorting; }
|
|
1018 }
|
|
1019
|
|
1020 #endregion
|
|
1021
|
|
1022 #region Sorting Enhancement
|
|
1023
|
|
1024 public void CreateSortSubstitution(string originalProperty, string substituteProperty)
|
|
1025 {
|
|
1026 BindingListImpl.CreateSortSubstitution(originalProperty, substituteProperty);
|
|
1027 }
|
|
1028
|
|
1029 public void RemoveSortSubstitution(string originalProperty)
|
|
1030 {
|
|
1031 BindingListImpl.RemoveSortSubstitution(originalProperty);
|
|
1032 }
|
|
1033
|
|
1034 #endregion
|
|
1035
|
|
1036 #region IBindingListView Members
|
|
1037
|
|
1038 public void ApplySort(ListSortDescriptionCollection sorts)
|
|
1039 {
|
|
1040 BindingListImpl.ApplySort(sorts);
|
|
1041 }
|
|
1042
|
|
1043 public string Filter
|
|
1044 {
|
|
1045 get { return BindingListImpl.Filter; }
|
|
1046 set { BindingListImpl.Filter = value; }
|
|
1047 }
|
|
1048
|
|
1049 public void RemoveFilter()
|
|
1050 {
|
|
1051 BindingListImpl.RemoveFilter();
|
|
1052 }
|
|
1053
|
|
1054 public ListSortDescriptionCollection SortDescriptions
|
|
1055 {
|
|
1056 get { return BindingListImpl.SortDescriptions; }
|
|
1057 }
|
|
1058
|
|
1059 public bool SupportsAdvancedSorting
|
|
1060 {
|
|
1061 get { return BindingListImpl.SupportsAdvancedSorting; }
|
|
1062 }
|
|
1063
|
|
1064 public bool SupportsFiltering
|
|
1065 {
|
|
1066 get { return BindingListImpl.SupportsFiltering; }
|
|
1067 }
|
|
1068
|
|
1069 #endregion
|
|
1070
|
|
1071 #region ICancelAddNew Members
|
|
1072
|
|
1073 public void CancelNew(int itemIndex)
|
|
1074 {
|
|
1075 if (itemIndex >= 0 && itemIndex < List.Count)
|
|
1076 NewItems.Remove(List[itemIndex]);
|
|
1077
|
|
1078 BindingListImpl.CancelNew(itemIndex);
|
|
1079 }
|
|
1080
|
|
1081 public void EndNew(int itemIndex)
|
|
1082 {
|
|
1083 BindingListImpl.EndNew(itemIndex);
|
|
1084 }
|
|
1085
|
|
1086 #endregion
|
|
1087
|
|
1088 #region INotifyCollectionChanged Members
|
|
1089
|
|
1090 public event NotifyCollectionChangedEventHandler CollectionChanged;
|
|
1091
|
|
1092 protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
|
1093 {
|
|
1094 if (!_supressEvent && NotifyChanges && CollectionChanged != null)
|
|
1095 CollectionChanged(this, e);
|
|
1096 }
|
|
1097
|
|
1098 #endregion
|
|
1099 }
|
|
1100 }
|