0
|
1 using System;
|
|
2
|
|
3 using System.Collections;
|
|
4 using System.Collections.Specialized;
|
|
5 using System.ComponentModel;
|
|
6 using System.Diagnostics;
|
|
7
|
|
8 using BLToolkit.EditableObjects;
|
|
9 using BLToolkit.Reflection;
|
|
10
|
|
11 namespace BLToolkit.ComponentModel
|
|
12 {
|
|
13 public class BindingListImpl: IBindingListView, ICancelAddNew, INotifyCollectionChanged
|
|
14 {
|
|
15 #region Init
|
|
16
|
|
17 public BindingListImpl(IList list, Type itemType)
|
|
18 {
|
|
19 if (list == null) throw new ArgumentNullException("list");
|
|
20 if (itemType == null) throw new ArgumentNullException("itemType");
|
|
21
|
|
22 _list = list;
|
|
23 _itemType = itemType;
|
|
24
|
|
25 AddInternal(_list);
|
|
26 }
|
|
27
|
|
28 #endregion
|
|
29
|
|
30 #region Protected Members
|
|
31
|
|
32 private readonly IList _list;
|
|
33 private readonly Type _itemType;
|
|
34
|
|
35 private void ApplySort(IComparer comparer)
|
|
36 {
|
|
37 if (_list is ISortable)
|
|
38 ((ISortable)_list).Sort(0, _list.Count, comparer);
|
|
39 else if (_list is ArrayList)
|
|
40 ((ArrayList)_list).Sort(0, _list.Count, comparer);
|
|
41 else if (_list is Array)
|
|
42 Array.Sort((Array)_list, comparer);
|
|
43 else
|
|
44 {
|
|
45 object[] items = new object[_list.Count];
|
|
46
|
|
47 _list.CopyTo(items, 0);
|
|
48 Array.Sort(items, comparer);
|
|
49
|
|
50 for (int i = 0; i < _list.Count; i++)
|
|
51 _list[i] = items[i];
|
|
52 }
|
|
53
|
|
54 _isSorted = true;
|
|
55 }
|
|
56
|
|
57 #endregion
|
|
58
|
|
59 #region IBindingList Members
|
|
60
|
|
61 #region Command
|
|
62
|
|
63 private int _newItemIndex = -1;
|
|
64 private INotifyObjectEdit _newObject;
|
|
65
|
|
66 public object AddNew()
|
|
67 {
|
|
68 if (AllowNew == false)
|
|
69 throw new NotSupportedException();
|
|
70
|
|
71 EndNew();
|
|
72
|
|
73 object o = TypeAccessor.CreateInstanceEx(_itemType);
|
|
74 _newObject = o as INotifyObjectEdit;
|
|
75
|
|
76 if (_newObject != null)
|
|
77 _newObject.ObjectEdit += NewObject_ObjectEdit;
|
|
78
|
|
79 _newItemIndex = _list.Add(o);
|
|
80 OnAddItem(o, _newItemIndex);
|
|
81
|
|
82 Debug.WriteLine(string.Format("AddNew - ({0})", o.GetType().Name));
|
|
83
|
|
84 return o;
|
|
85 }
|
|
86
|
|
87 void NewObject_ObjectEdit(object sender, ObjectEditEventArgs args)
|
|
88 {
|
|
89 if (sender == _newObject)
|
|
90 {
|
|
91 switch (args.EditType)
|
|
92 {
|
|
93 case ObjectEditType.End: EndNew(); break;
|
|
94 case ObjectEditType.Cancel: CancelNew(_newItemIndex); break;
|
|
95 default: return;
|
|
96 }
|
|
97 }
|
|
98 }
|
|
99
|
|
100 public bool AllowNew
|
|
101 {
|
|
102 get { return !_list.IsFixedSize; }
|
|
103 }
|
|
104
|
|
105 public bool AllowEdit
|
|
106 {
|
|
107 get { return !_list.IsReadOnly; }
|
|
108 }
|
|
109
|
|
110 public bool AllowRemove
|
|
111 {
|
|
112 get { return !_list.IsFixedSize; }
|
|
113 }
|
|
114
|
|
115 #endregion
|
|
116
|
|
117 #region Change Notification
|
|
118
|
|
119 private bool _notifyChanges = true;
|
|
120 public bool NotifyChanges
|
|
121 {
|
|
122 get { return _notifyChanges; }
|
|
123 set { _notifyChanges = value; }
|
|
124 }
|
|
125
|
|
126 public bool SupportsChangeNotification
|
|
127 {
|
|
128 get { return true; }
|
|
129 }
|
|
130
|
|
131 public event ListChangedEventHandler ListChanged;
|
|
132
|
|
133 private void FireListChangedEvent(object sender, ListChangedEventArgs e)
|
|
134 {
|
|
135 if (_notifyChanges && ListChanged != null)
|
|
136 ListChanged(sender, e);
|
|
137 }
|
|
138
|
|
139 protected virtual void OnListChanged(EditableListChangedEventArgs e)
|
|
140 {
|
|
141 FireListChangedEvent(this, e);
|
|
142 }
|
|
143
|
|
144 protected void OnListChanged(ListChangedType listChangedType, int index)
|
|
145 {
|
|
146 OnListChanged(new EditableListChangedEventArgs(listChangedType, index));
|
|
147 }
|
|
148
|
|
149 private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
150 {
|
|
151 if (_notifyChanges && sender != null)
|
|
152 {
|
|
153 int indexOfSender = _list.IndexOf(sender);
|
|
154
|
|
155 if (indexOfSender >= 0)
|
|
156 {
|
|
157 MemberAccessor ma = TypeAccessor.GetAccessor(sender.GetType())[e.PropertyName];
|
|
158
|
|
159 if (ma != null)
|
|
160 OnListChanged(new EditableListChangedEventArgs(indexOfSender, ma.PropertyDescriptor));
|
|
161 else
|
|
162 OnListChanged(new EditableListChangedEventArgs(ListChangedType.ItemChanged, indexOfSender));
|
|
163
|
|
164 // Do not fire an event for OnCollectionChanged here.
|
|
165
|
|
166 if (_isSorted && _list.Count > 1)
|
|
167 {
|
|
168 int newIndex = GetItemSortedPosition(indexOfSender, sender);
|
|
169
|
|
170 if (newIndex != indexOfSender)
|
|
171 {
|
|
172 _list.RemoveAt(indexOfSender);
|
|
173 _list.Insert(newIndex, sender);
|
|
174
|
|
175 OnMoveItem(sender, indexOfSender, newIndex);
|
|
176 }
|
|
177 }
|
|
178 }
|
|
179 }
|
|
180 }
|
|
181
|
|
182 #endregion
|
|
183
|
|
184 #region Sorting
|
|
185
|
|
186 public bool SupportsSorting
|
|
187 {
|
|
188 get { return true; }
|
|
189 }
|
|
190
|
|
191 [NonSerialized]
|
|
192 private bool _isSorted;
|
|
193 public bool IsSorted
|
|
194 {
|
|
195 get { return _isSorted; }
|
|
196 }
|
|
197
|
|
198 [NonSerialized]
|
|
199 private PropertyDescriptor _sortProperty;
|
|
200 public PropertyDescriptor SortProperty
|
|
201 {
|
|
202 get { return _sortProperty; }
|
|
203 }
|
|
204
|
|
205 [NonSerialized]
|
|
206 private ListSortDirection _sortDirection;
|
|
207 public ListSortDirection SortDirection
|
|
208 {
|
|
209 get { return _sortDirection; }
|
|
210 }
|
|
211
|
|
212 public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
|
|
213 {
|
|
214 Debug.WriteLine(string.Format("Begin ApplySort(\"{0}\", {1})", property.Name, direction));
|
|
215
|
|
216 _sortProperty = property;
|
|
217 _sortDirection = direction;
|
|
218 _sortDescriptions = null;
|
|
219
|
|
220 ApplySort(GetSortComparer(_sortProperty, _sortDirection));
|
|
221
|
|
222 if (_list.Count > 0)
|
|
223 OnReset();
|
|
224
|
|
225 Debug.WriteLine(string.Format("End ApplySort(\"{0}\", {1})", property.Name, direction));
|
|
226 }
|
|
227
|
|
228 public void RemoveSort()
|
|
229 {
|
|
230 _isSorted = false;
|
|
231 _sortProperty = null;
|
|
232 _sortDescriptions = null;
|
|
233
|
|
234 OnReset();
|
|
235 }
|
|
236
|
|
237 #endregion
|
|
238
|
|
239 #region Searching
|
|
240
|
|
241 public bool SupportsSearching
|
|
242 {
|
|
243 get { return true; }
|
|
244 }
|
|
245
|
|
246 public int Find(PropertyDescriptor property, object key)
|
|
247 {
|
|
248 if (property == null) throw new ArgumentException("property");
|
|
249
|
|
250 if (key != null)
|
|
251 for (int i = 0; i < _list.Count; i++)
|
|
252 if (key.Equals(property.GetValue(_list[i])))
|
|
253 return i;
|
|
254
|
|
255 return -1;
|
|
256 }
|
|
257
|
|
258 #endregion
|
|
259
|
|
260 #region Indexes
|
|
261
|
|
262 public void AddIndex(PropertyDescriptor property)
|
|
263 {
|
|
264 }
|
|
265
|
|
266 public void RemoveIndex(PropertyDescriptor property)
|
|
267 {
|
|
268 }
|
|
269
|
|
270 #endregion
|
|
271
|
|
272 #endregion
|
|
273
|
|
274 #region ICancelAddNew Members
|
|
275
|
|
276 public void CancelNew(int itemIndex)
|
|
277 {
|
|
278 if (itemIndex >= 0 && itemIndex == _newItemIndex)
|
|
279 {
|
|
280 _list.RemoveAt(itemIndex);
|
|
281 OnRemoveItem(_newObject, itemIndex);
|
|
282 EndNew();
|
|
283 }
|
|
284 }
|
|
285
|
|
286 public void EndNew(int itemIndex)
|
|
287 {
|
|
288 if (itemIndex == _newItemIndex)
|
|
289 EndNew();
|
|
290 }
|
|
291
|
|
292 public void EndNew()
|
|
293 {
|
|
294 _newItemIndex = -1;
|
|
295
|
|
296 if (_newObject != null)
|
|
297 _newObject.ObjectEdit -= NewObject_ObjectEdit;
|
|
298
|
|
299 _newObject = null;
|
|
300 }
|
|
301
|
|
302 #endregion
|
|
303
|
|
304 #region IList Members
|
|
305
|
|
306 public int Add(object value)
|
|
307 {
|
|
308 int index;
|
|
309
|
|
310 if (!_isSorted)
|
|
311 index = _list.Add(value);
|
|
312 else
|
|
313 {
|
|
314 index = GetSortedInsertIndex(value);
|
|
315 _list.Insert(index, value);
|
|
316 }
|
|
317
|
|
318 AddInternal(value);
|
|
319 OnAddItem(value, index);
|
|
320
|
|
321 return index;
|
|
322 }
|
|
323
|
|
324 public void Clear()
|
|
325 {
|
|
326 if (_list.Count > 0)
|
|
327 {
|
|
328 RemoveInternal(_list);
|
|
329
|
|
330 _list.Clear();
|
|
331 OnReset();
|
|
332 }
|
|
333 }
|
|
334
|
|
335 public bool Contains(object value)
|
|
336 {
|
|
337 return _list.Contains(value);
|
|
338 }
|
|
339
|
|
340 public int IndexOf(object value)
|
|
341 {
|
|
342 return _list.IndexOf(value);
|
|
343 }
|
|
344
|
|
345 public void Insert(int index, object value)
|
|
346 {
|
|
347 if (_isSorted)
|
|
348 index = GetSortedInsertIndex(value);
|
|
349
|
|
350 _list.Insert(index, value);
|
|
351 AddInternal(value);
|
|
352
|
|
353 OnAddItem(value, index);
|
|
354 }
|
|
355
|
|
356 public bool IsFixedSize
|
|
357 {
|
|
358 get { return _list.IsFixedSize; }
|
|
359 }
|
|
360
|
|
361 public bool IsReadOnly
|
|
362 {
|
|
363 get { return _list.IsReadOnly; }
|
|
364 }
|
|
365
|
|
366 public void Remove(object value)
|
|
367 {
|
|
368 int index = IndexOf(value);
|
|
369
|
|
370 if (index >= 0)
|
|
371 RemoveInternal(value);
|
|
372
|
|
373 _list.Remove(value);
|
|
374
|
|
375 if (index >= 0)
|
|
376 OnRemoveItem(value, index);
|
|
377 }
|
|
378
|
|
379 public void RemoveAt(int index)
|
|
380 {
|
|
381 object value = this[index];
|
|
382
|
|
383 RemoveInternal(value);
|
|
384
|
|
385 _list.RemoveAt(index);
|
|
386
|
|
387 OnRemoveItem(value, index);
|
|
388 }
|
|
389
|
|
390 public object this[int index]
|
|
391 {
|
|
392 get { return _list[index]; }
|
|
393 set
|
|
394 {
|
|
395 object o = _list[index];
|
|
396
|
|
397 if (o != value)
|
|
398 {
|
|
399 RemoveInternal(o);
|
|
400
|
|
401 _list[index] = value;
|
|
402
|
|
403 AddInternal(value);
|
|
404
|
|
405 OnChangeItem(o, value, index);
|
|
406
|
|
407 if (_isSorted)
|
|
408 {
|
|
409 int newIndex = GetItemSortedPosition(index, value);
|
|
410
|
|
411 if (newIndex != index)
|
|
412 {
|
|
413 _list.RemoveAt(index);
|
|
414 _list.Insert(newIndex, value);
|
|
415 }
|
|
416
|
|
417 OnMoveItem(value, index, newIndex);
|
|
418 }
|
|
419 }
|
|
420 }
|
|
421 }
|
|
422
|
|
423 #endregion
|
|
424
|
|
425 #region ICollection Members
|
|
426
|
|
427 public void CopyTo(Array array, int index)
|
|
428 {
|
|
429 _list.CopyTo(array, index);
|
|
430 }
|
|
431
|
|
432 public int Count
|
|
433 {
|
|
434 get { return _list.Count; }
|
|
435 }
|
|
436
|
|
437 public bool IsSynchronized
|
|
438 {
|
|
439 get { return _list.IsSynchronized; }
|
|
440 }
|
|
441
|
|
442 public object SyncRoot
|
|
443 {
|
|
444 get { return _list.SyncRoot; }
|
|
445 }
|
|
446
|
|
447 #endregion
|
|
448
|
|
449 #region IEnumerable Members
|
|
450
|
|
451 public IEnumerator GetEnumerator()
|
|
452 {
|
|
453 return _list.GetEnumerator();
|
|
454 }
|
|
455
|
|
456 #endregion
|
|
457
|
|
458 #region SortPropertyComparer
|
|
459
|
|
460 class SortPropertyComparer : IComparer
|
|
461 {
|
|
462 readonly PropertyDescriptor _property;
|
|
463 readonly ListSortDirection _direction;
|
|
464
|
|
465 public SortPropertyComparer(PropertyDescriptor property, ListSortDirection direction)
|
|
466 {
|
|
467 _property = property;
|
|
468 _direction = direction;
|
|
469 }
|
|
470
|
|
471 public int Compare(object x, object y)
|
|
472 {
|
|
473 object a = _property.GetValue(x);
|
|
474 object b = _property.GetValue(y);
|
|
475
|
|
476 int n = Comparer.Default.Compare(a, b);
|
|
477
|
|
478 return _direction == ListSortDirection.Ascending? n: -n;
|
|
479 }
|
|
480 }
|
|
481
|
|
482 #endregion
|
|
483
|
|
484 #region IComparer Accessor
|
|
485
|
|
486 public IComparer GetSortComparer()
|
|
487 {
|
|
488 if (_isSorted)
|
|
489 {
|
|
490 if (_sortDescriptions != null)
|
|
491 return GetSortComparer(_sortDescriptions);
|
|
492
|
|
493 return GetSortComparer(_sortProperty, _sortDirection);
|
|
494 }
|
|
495
|
|
496 return null;
|
|
497 }
|
|
498
|
|
499 private IComparer GetSortComparer(PropertyDescriptor sortProperty, ListSortDirection sortDirection)
|
|
500 {
|
|
501 if (_sortSubstitutions.ContainsKey(sortProperty.Name))
|
|
502 sortProperty = ((SortSubstitutionPair)_sortSubstitutions[sortProperty.Name]).Substitute;
|
|
503
|
|
504 return new SortPropertyComparer(sortProperty, sortDirection);
|
|
505 }
|
|
506
|
|
507 private IComparer GetSortComparer(ListSortDescriptionCollection sortDescriptions)
|
|
508 {
|
|
509 bool needSubstitution = false;
|
|
510
|
|
511 if (_sortSubstitutions.Count > 0)
|
|
512 {
|
|
513 foreach (ListSortDescription sortDescription in sortDescriptions)
|
|
514 {
|
|
515 if (_sortSubstitutions.ContainsKey(sortDescription.PropertyDescriptor.Name))
|
|
516 {
|
|
517 needSubstitution = true;
|
|
518 break;
|
|
519 }
|
|
520 }
|
|
521
|
|
522 if (needSubstitution)
|
|
523 {
|
|
524 ListSortDescription[] sorts = new ListSortDescription[sortDescriptions.Count];
|
|
525 sortDescriptions.CopyTo(sorts, 0);
|
|
526
|
|
527 for (int i = 0; i < sorts.Length; i++)
|
|
528 if (_sortSubstitutions.ContainsKey(sorts[i].PropertyDescriptor.Name))
|
|
529 sorts[i] = new ListSortDescription(((SortSubstitutionPair)_sortSubstitutions[sorts[i].PropertyDescriptor.Name]).Substitute,
|
|
530 sorts[i].SortDirection);
|
|
531
|
|
532 sortDescriptions = new ListSortDescriptionCollection(sorts);
|
|
533 }
|
|
534 }
|
|
535
|
|
536 return new SortListPropertyComparer(sortDescriptions);
|
|
537 }
|
|
538
|
|
539 #endregion
|
|
540
|
|
541 #region IBindingListView Members
|
|
542
|
|
543 public bool SupportsAdvancedSorting
|
|
544 {
|
|
545 get { return true; }
|
|
546 }
|
|
547
|
|
548 public void ApplySort(ListSortDescriptionCollection sorts)
|
|
549 {
|
|
550 _sortDescriptions = sorts;
|
|
551
|
|
552 _isSorted = true;
|
|
553 _sortProperty = null;
|
|
554
|
|
555 ApplySort(GetSortComparer(sorts));
|
|
556
|
|
557 if (_list.Count > 0)
|
|
558 OnReset();
|
|
559 }
|
|
560
|
|
561 [NonSerialized]
|
|
562 private ListSortDescriptionCollection _sortDescriptions;
|
|
563 public ListSortDescriptionCollection SortDescriptions
|
|
564 {
|
|
565 get { return _sortDescriptions; }
|
|
566 }
|
|
567
|
|
568 public bool SupportsFiltering
|
|
569 {
|
|
570 get { return false; }
|
|
571 }
|
|
572
|
|
573 public string Filter
|
|
574 {
|
|
575 get { throw new NotImplementedException("The method 'BindingListImpl.get_Filter' is not implemented."); }
|
|
576 set { throw new NotImplementedException("The method 'BindingListImpl.set_Filter' is not implemented."); }
|
|
577 }
|
|
578
|
|
579 public void RemoveFilter()
|
|
580 {
|
|
581 throw new NotImplementedException("The method 'BindingListImpl.RemoveFilter()' is not implemented.");
|
|
582 }
|
|
583
|
|
584 #endregion
|
|
585
|
|
586 #region SortListPropertyComparer
|
|
587
|
|
588 class SortListPropertyComparer : IComparer
|
|
589 {
|
|
590 readonly ListSortDescriptionCollection _sorts;
|
|
591
|
|
592 public SortListPropertyComparer(ListSortDescriptionCollection sorts)
|
|
593 {
|
|
594 _sorts = sorts;
|
|
595 }
|
|
596
|
|
597 public int Compare(object x, object y)
|
|
598 {
|
|
599 for (int i = 0; i < _sorts.Count; i++)
|
|
600 {
|
|
601 PropertyDescriptor property = _sorts[i].PropertyDescriptor;
|
|
602
|
|
603 object a = property.GetValue(x);
|
|
604 object b = property.GetValue(y);
|
|
605
|
|
606 int n = Comparer.Default.Compare(a, b);
|
|
607
|
|
608 if (n != 0)
|
|
609 return _sorts[i].SortDirection == ListSortDirection.Ascending? n: -n;
|
|
610 }
|
|
611
|
|
612 return 0;
|
|
613 }
|
|
614 }
|
|
615
|
|
616 #endregion
|
|
617
|
|
618 #region Sorting enhancement
|
|
619
|
|
620 private readonly Hashtable _sortSubstitutions = new Hashtable();
|
|
621
|
|
622 private class SortSubstitutionPair
|
|
623 {
|
|
624 public SortSubstitutionPair(PropertyDescriptor original, PropertyDescriptor substitute)
|
|
625 {
|
|
626 Original = original;
|
|
627 Substitute = substitute;
|
|
628 }
|
|
629
|
|
630 public readonly PropertyDescriptor Original;
|
|
631 public readonly PropertyDescriptor Substitute;
|
|
632 }
|
|
633
|
|
634 public void CreateSortSubstitution(string originalProperty, string substituteProperty)
|
|
635 {
|
|
636 TypeAccessor typeAccessor = TypeAccessor.GetAccessor(_itemType);
|
|
637
|
|
638 PropertyDescriptor originalDescriptor = typeAccessor.PropertyDescriptors[originalProperty];
|
|
639 PropertyDescriptor substituteDescriptor = typeAccessor.PropertyDescriptors[substituteProperty];
|
|
640
|
|
641 if (originalDescriptor == null) throw new InvalidOperationException("Can not retrieve PropertyDescriptor for original property: " + originalProperty);
|
|
642 if (substituteDescriptor == null) throw new InvalidOperationException("Can not retrieve PropertyDescriptor for substitute property: " + substituteProperty);
|
|
643
|
|
644 _sortSubstitutions[originalProperty] = new SortSubstitutionPair(originalDescriptor, substituteDescriptor);
|
|
645 }
|
|
646
|
|
647 public void RemoveSortSubstitution(string originalProperty)
|
|
648 {
|
|
649 _sortSubstitutions.Remove(originalProperty);
|
|
650 }
|
|
651
|
|
652 #endregion
|
|
653
|
|
654 #region Sort enforcement
|
|
655
|
|
656 public int GetItemSortedPosition(int index, object sender)
|
|
657 {
|
|
658 IComparer comparer = GetSortComparer();
|
|
659
|
|
660 if (comparer == null)
|
|
661 return index;
|
|
662
|
|
663 if ((index > 0 && comparer.Compare(_list[index - 1], sender) > 0) ||
|
|
664 (index < _list.Count - 1 && comparer.Compare(_list[index + 1], sender) < 0))
|
|
665 {
|
|
666 for (int i = 0; i < _list.Count; i++)
|
|
667 {
|
|
668 if (i != index && comparer.Compare(_list[i], sender) > 0)
|
|
669 {
|
|
670 if (i > index)
|
|
671 return i - 1;
|
|
672
|
|
673 return i;
|
|
674 }
|
|
675 }
|
|
676
|
|
677 return _list.Count - 1;
|
|
678 }
|
|
679
|
|
680 return index;
|
|
681 }
|
|
682
|
|
683 public int GetSortedInsertIndex(object value)
|
|
684 {
|
|
685 IComparer comparer = GetSortComparer();
|
|
686
|
|
687 if (comparer == null)
|
|
688 return -1;
|
|
689
|
|
690 for (int i = 0; i < _list.Count; i++)
|
|
691 if (comparer.Compare(_list[i], value) > 0)
|
|
692 return i;
|
|
693
|
|
694 return _list.Count;
|
|
695 }
|
|
696
|
|
697 #endregion
|
|
698
|
|
699 #region Misc/Range Operations
|
|
700
|
|
701 public void Move(int newIndex, int oldIndex)
|
|
702 {
|
|
703 if (oldIndex != newIndex)
|
|
704 {
|
|
705 EndNew();
|
|
706
|
|
707 object o = _list[oldIndex];
|
|
708
|
|
709 _list.RemoveAt(oldIndex);
|
|
710 if (!_isSorted)
|
|
711 _list.Insert(newIndex, o);
|
|
712 else
|
|
713 _list.Insert(newIndex = GetSortedInsertIndex(o), o);
|
|
714
|
|
715 OnMoveItem(o, oldIndex, newIndex);
|
|
716 }
|
|
717 }
|
|
718
|
|
719 public void AddRange(ICollection c)
|
|
720 {
|
|
721 foreach (object o in c)
|
|
722 {
|
|
723 if (!_isSorted)
|
|
724 _list.Add(o);
|
|
725 else
|
|
726 _list.Insert(GetSortedInsertIndex(o), o);
|
|
727 }
|
|
728
|
|
729 AddInternal(c);
|
|
730
|
|
731 OnReset();
|
|
732 }
|
|
733
|
|
734 public void InsertRange(int index, ICollection c)
|
|
735 {
|
|
736 if (c.Count == 0)
|
|
737 return;
|
|
738
|
|
739 foreach (object o in c)
|
|
740 {
|
|
741 if (!_isSorted)
|
|
742 _list.Insert(index++, o);
|
|
743 else
|
|
744 _list.Insert(GetSortedInsertIndex(o), o);
|
|
745 }
|
|
746
|
|
747 AddInternal(c);
|
|
748
|
|
749 OnReset();
|
|
750 }
|
|
751
|
|
752 public void RemoveRange(int index, int count)
|
|
753 {
|
|
754 object[] toRemove = new object[count];
|
|
755
|
|
756 for (int i = index; i < _list.Count && i < index + count; i++)
|
|
757 toRemove[i - index] = _list[i];
|
|
758
|
|
759 RemoveInternal(toRemove);
|
|
760
|
|
761 foreach (object o in toRemove)
|
|
762 _list.Remove(o);
|
|
763
|
|
764 OnReset();
|
|
765 }
|
|
766
|
|
767 public void SetRange(int index, ICollection c)
|
|
768 {
|
|
769 int cCount = c.Count;
|
|
770
|
|
771 if (index < 0 || index >= _list.Count - cCount)
|
|
772 throw new ArgumentOutOfRangeException("index");
|
|
773
|
|
774 bool oldNotifyChanges = _notifyChanges;
|
|
775 _notifyChanges = false;
|
|
776
|
|
777 int i = index;
|
|
778 foreach (object newObject in c)
|
|
779 {
|
|
780 RemoveInternal(_list[i + index]);
|
|
781 _list[i + index] = newObject;
|
|
782 }
|
|
783
|
|
784 AddInternal(c);
|
|
785
|
|
786 if (_isSorted)
|
|
787 ApplySort(GetSortComparer());
|
|
788
|
|
789 _notifyChanges = oldNotifyChanges;
|
|
790 OnReset();
|
|
791 }
|
|
792
|
|
793 #endregion
|
|
794
|
|
795 #region Add/Remove Internal
|
|
796
|
|
797 private void AddInternal(object value)
|
|
798 {
|
|
799 EndNew();
|
|
800
|
|
801 if (value is INotifyPropertyChanged)
|
|
802 ((INotifyPropertyChanged)value).PropertyChanged +=
|
|
803 ItemPropertyChanged;
|
|
804 }
|
|
805
|
|
806 private void RemoveInternal(object value)
|
|
807 {
|
|
808 EndNew();
|
|
809
|
|
810 if (value is INotifyPropertyChanged)
|
|
811 ((INotifyPropertyChanged)value).PropertyChanged -=
|
|
812 ItemPropertyChanged;
|
|
813 }
|
|
814
|
|
815 private void AddInternal(IEnumerable e)
|
|
816 {
|
|
817 foreach (object o in e)
|
|
818 AddInternal(o);
|
|
819 }
|
|
820
|
|
821 private void RemoveInternal(IEnumerable e)
|
|
822 {
|
|
823 foreach (object o in e)
|
|
824 RemoveInternal(o);
|
|
825 }
|
|
826
|
|
827 private void OnAddItem(object item, int index)
|
|
828 {
|
|
829 OnListChanged(new EditableListChangedEventArgs(ListChangedType.ItemAdded, index));
|
|
830 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
|
|
831 }
|
|
832
|
|
833 private void OnRemoveItem(object item, int index)
|
|
834 {
|
|
835 OnListChanged(new EditableListChangedEventArgs(ListChangedType.ItemDeleted, index));
|
|
836 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
|
|
837 }
|
|
838
|
|
839 private void OnMoveItem(object item, int oldIndex, int newIndex)
|
|
840 {
|
|
841 OnListChanged(new EditableListChangedEventArgs(newIndex, oldIndex));
|
|
842 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, item, newIndex, oldIndex));
|
|
843 }
|
|
844
|
|
845 private void OnChangeItem(object oldValue, object newValue, int index)
|
|
846 {
|
|
847 OnListChanged(new EditableListChangedEventArgs(ListChangedType.ItemChanged, index));
|
|
848 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, oldValue, newValue, index));
|
|
849 }
|
|
850
|
|
851 private void OnReset()
|
|
852 {
|
|
853 OnListChanged(new EditableListChangedEventArgs(ListChangedType.Reset));
|
|
854 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
|
855 }
|
|
856
|
|
857 #endregion
|
|
858
|
|
859 #region INotifyCollectionChanged Members
|
|
860
|
|
861 public event NotifyCollectionChangedEventHandler CollectionChanged;
|
|
862
|
|
863 private void FireCollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs ea)
|
|
864 {
|
|
865 if (_notifyChanges && CollectionChanged != null)
|
|
866 CollectionChanged(sender, ea);
|
|
867 }
|
|
868
|
|
869 protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs ea)
|
|
870 {
|
|
871 FireCollectionChangedEvent(this, ea);
|
|
872 }
|
|
873
|
|
874 #endregion
|
|
875 }
|
|
876 }
|