comparison Source/ComponentModel/BindingListImpl.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
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 }