CSLA.NET 5.4.2
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
FilteredBindingList.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="FilteredBindingList.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>Provides a filtered view into an existing IList(Of T).</summary>
7//-----------------------------------------------------------------------
8using System;
9using System.ComponentModel;
10using System.Collections.Generic;
11using System.Collections;
12using Csla.Properties;
13
14namespace Csla
15{
21 public class FilteredBindingList<T> :
22 IList<T>, IBindingList, IEnumerable<T>,
23 ICancelAddNew
24 {
25
26 #region ListItem class
27
28 private class ListItem
29 {
30 private object _key;
31 private int _baseIndex;
32
33 public object Key
34 {
35 get { return _key; }
36 }
37
38 public int BaseIndex
39 {
40 get { return _baseIndex; }
41 set { _baseIndex = value; }
42 }
43
44 public ListItem(object key, int baseIndex)
45 {
46 _key = key;
47 _baseIndex = baseIndex;
48 }
49
50 public override string ToString()
51 {
52 return Key.ToString();
53 }
54
55 }
56
57 #endregion
58
59 #region Filtered enumerator
60
61 private class FilteredEnumerator : IEnumerator<T>
62 {
63 private IList<T> _list;
64 private List<ListItem> _filterIndex;
65 private int _index;
66
67 public FilteredEnumerator(
68 IList<T> list,
69 List<ListItem> filterIndex)
70 {
71 _list = list;
72 _filterIndex = filterIndex;
73 Reset();
74 }
75
76 public T Current
77 {
78 get { return _list[_filterIndex[_index].BaseIndex]; }
79 }
80
81 Object System.Collections.IEnumerator.Current
82 {
83 get { return _list[_filterIndex[_index].BaseIndex]; }
84 }
85
86 public bool MoveNext()
87 {
88 if (_index < _filterIndex.Count - 1)
89 {
90 _index++;
91 return true;
92 }
93 else
94 return false;
95 }
96
97 public void Reset()
98 {
99 _index = -1;
100 }
101
102 #region IDisposable Support
103
104 private bool _disposedValue = false; // To detect redundant calls.
105
106 // IDisposable
107 protected virtual void Dispose(bool disposing)
108 {
109 if (!_disposedValue)
110 {
111 if (disposing)
112 {
113 // free unmanaged resources when explicitly called
114 }
115 // free shared unmanaged resources
116 }
117 _disposedValue = true;
118 }
119
120 // this code added to correctly implement the disposable pattern.
121 public void Dispose()
122 {
123 // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
124 Dispose(true);
125 GC.SuppressFinalize(this);
126 }
127
128 ~FilteredEnumerator()
129 {
130 Dispose(false);
131 }
132
133 #endregion
134
135 }
136
137 #endregion
138
139 #region Filter/Unfilter
140
141 private void DoFilter()
142 {
143 int index = 0;
144 _filterIndex.Clear();
145
146 if (_provider == null)
147 _provider = DefaultFilter.Filter;
148
149 if (_filterBy == null)
150 {
151 foreach (T obj in _list)
152 {
153 if (_provider.Invoke(obj, _filter))
154 _filterIndex.Add(new ListItem(obj, index));
155 index++;
156 }
157 }
158 else
159 {
160 foreach (T obj in _list)
161 {
162 object tmp = _filterBy.GetValue(obj);
163 if (_provider.Invoke(tmp, _filter))
164 _filterIndex.Add(new ListItem(tmp, index));
165 index++;
166 }
167 }
168
169 _filtered = true;
170
171 OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, 0));
172
173 }
174
175 private void UnDoFilter()
176 {
177 _filterIndex.Clear();
178 _filterBy = null;
179 _filter = null;
180 _filtered = false;
181
182 OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, 0));
183
184 }
185
186 #endregion
187
188 #region IEnumerable<T>
189
194 public IEnumerator<T> GetEnumerator()
195 {
196 if (_filtered)
197 return new FilteredEnumerator(_list, _filterIndex);
198 else
199 return _list.GetEnumerator();
200 }
201
202 #endregion
203
204 #region IBindingList, IList<T>
205
211 public void AddIndex(PropertyDescriptor property)
212 {
213 if (_supportsBinding)
214 _bindingList.AddIndex(property);
215 }
216
220 public object AddNew()
221 {
222 T result;
223 if (_supportsBinding)
224 result = (T)_bindingList.AddNew();
225 else
226 result = default(T);
227
228 //_newItem = (T)result;
229 return result;
230 }
231
235 public bool AllowEdit
236 {
237 get
238 {
239 if (_supportsBinding)
240 return _bindingList.AllowEdit;
241 else
242 return false;
243 }
244 }
245
249 public bool AllowNew
250 {
251 get
252 {
253 if (_supportsBinding)
254 return _bindingList.AllowNew;
255 else
256 return false;
257 }
258 }
259
263 public bool AllowRemove
264 {
265 get
266 {
267 if (_supportsBinding)
268 return _bindingList.AllowRemove;
269 else
270 return false;
271 }
272 }
273
280 public void ApplySort(
281 PropertyDescriptor property, ListSortDirection direction)
282 {
283 if (SupportsSorting)
284 _bindingList.ApplySort(property, direction);
285 else
286 throw new NotSupportedException(Resources.SortingNotSupported);
287 }
288
295 public void ApplySort(
296 string propertyName, ListSortDirection direction)
297 {
298 if (SupportsSorting)
299 {
300 var property = GetPropertyDescriptor(propertyName);
301 _bindingList.ApplySort(property, direction);
302 }
303 else
304 throw new NotSupportedException(Resources.SortingNotSupported);
305 }
306
312 private static PropertyDescriptor GetPropertyDescriptor(string propertyName)
313 {
314 PropertyDescriptor property = null;
315
316 if (!String.IsNullOrEmpty(propertyName))
317 {
318 Type itemType = typeof(T);
319 foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(itemType))
320 {
321 if (prop.Name == propertyName)
322 {
323 property = prop;
324 break;
325 }
326 }
327
328 // throw exception if propertyDescriptor could not be found
329 if (property == null)
330 throw new ArgumentException(string.Format(Resources.SortedBindingListPropertyNameNotFound, propertyName), propertyName);
331 }
332
333 return property;
334 }
340 public int Find(string propertyName, object key)
341 {
342 PropertyDescriptor findProperty = null;
343
344 if (!String.IsNullOrEmpty(propertyName))
345 {
346 Type itemType = typeof(T);
347 foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(itemType))
348 {
349 if (prop.Name == propertyName)
350 {
351 findProperty = prop;
352 break;
353 }
354 }
355 }
356
357 return Find(findProperty, key);
358
359 }
360
367 public int Find(PropertyDescriptor property, object key)
368 {
369 if (_supportsBinding)
370 return FilteredIndex(_bindingList.Find(property, key));
371 else
372 return -1;
373 }
374
378 public bool IsSorted
379 {
380 get
381 {
382 if (SupportsSorting)
383 return _bindingList.IsSorted;
384 else
385 return false;
386 }
387 }
388
398 public event ListChangedEventHandler ListChanged;
399
404 protected void OnListChanged(ListChangedEventArgs e)
405 {
406 if (ListChanged != null)
407 ListChanged(this, e);
408 }
409
415 public void RemoveIndex(PropertyDescriptor property)
416 {
417 if (_supportsBinding)
418 _bindingList.RemoveIndex(property);
419 }
420
424 public void RemoveSort()
425 {
426 if (SupportsSorting)
427 _bindingList.RemoveSort();
428 else
429 throw new NotSupportedException(Resources.SortingNotSupported);
430 }
431
435 public ListSortDirection SortDirection
436 {
437 get
438 {
439 if (SupportsSorting)
440 return _bindingList.SortDirection;
441 else
442 return ListSortDirection.Ascending;
443 }
444 }
445
449 public PropertyDescriptor SortProperty
450 {
451 get
452 {
453 if (SupportsSorting)
454 return _bindingList.SortProperty;
455 else
456 return null;
457 }
458 }
459
465 {
466 get { return true; }
467 }
468
473 {
474 get
475 {
476 if (_supportsBinding)
477 return _bindingList.SupportsSearching;
478 else
479 return false;
480 }
481 }
482
486 public bool SupportsSorting
487 {
488 get
489 {
490 if (_supportsBinding)
491 return _bindingList.SupportsSorting;
492 else
493 return false;
494 }
495 }
496
503 public void CopyTo(T[] array, int arrayIndex)
504 {
505 int pos = arrayIndex;
506 foreach (T child in this)
507 {
508 array[pos] = child;
509 pos++;
510 }
511 }
512
513 void System.Collections.ICollection.CopyTo(System.Array array, int index)
514 {
515 T[] tmp = new T[array.Length];
516 CopyTo(tmp, index);
517 Array.Copy(tmp, 0, array, index, array.Length);
518 }
519
523 public int Count
524 {
525 get
526 {
527 if (_filtered)
528 return _filterIndex.Count;
529 else
530 return _list.Count;
531 }
532 }
533
534 bool System.Collections.ICollection.IsSynchronized
535 {
536 get { return false; }
537 }
538
539 object System.Collections.ICollection.SyncRoot
540 {
541 get { return _list; }
542 }
543
544 IEnumerator System.Collections.IEnumerable.GetEnumerator()
545 {
546 return GetEnumerator();
547 }
548
553 public void Add(T item)
554 {
555 _list.Add(item);
556 }
557
558 int System.Collections.IList.Add(object value)
559 {
560 Add((T)value);
561 int index = FilteredIndex(_list.Count - 1);
562 if (index > -1)
563 return index;
564 else
565 return 0;
566 }
567
571 public void Clear()
572 {
573 if (_filtered)
574 for (int index = Count - 1; index >= 0; index--)
575 RemoveAt(index);
576 else
577 _list.Clear();
578 }
579
587 public bool Contains(T item)
588 {
589 return _list.Contains(item);
590 }
591
592 bool System.Collections.IList.Contains(object value)
593 {
594 return Contains((T)value);
595 }
596
604 public int IndexOf(T item)
605 {
606 return FilteredIndex(_list.IndexOf(item));
607 }
608
609 int System.Collections.IList.IndexOf(object value)
610 {
611 return IndexOf((T)value);
612 }
613
620 public void Insert(int index, T item)
621 {
622 _list.Insert(index, item);
623 }
624
625 void System.Collections.IList.Insert(int index, object value)
626 {
627 Insert(index, (T)value);
628 }
629
630 bool System.Collections.IList.IsFixedSize
631 {
632 get { return false; }
633 }
634
639 public bool IsReadOnly
640 {
641 get { return _list.IsReadOnly; }
642 }
643
644 object System.Collections.IList.this[int index]
645 {
646 get
647 {
648 return this[index];
649 }
650 set
651 {
652 this[index] = (T)value;
653 }
654 }
655
662 public bool Remove(T item)
663 {
664 return _list.Remove(item);
665 }
666
667 void System.Collections.IList.Remove(object value)
668 {
669 Remove((T)value);
670 }
671
677 public void RemoveAt(int index)
678 {
679 if (_filtered)
680 {
681 _list.RemoveAt(OriginalIndex(index));
682 }
683 else
684 _list.RemoveAt(index);
685 }
686
693 public T this[int index]
694 {
695 get
696 {
697 if (_filtered)
698 {
699 int src = OriginalIndex(index);
700 return _list[src];
701 }
702 else
703 return _list[index];
704 }
705 set
706 {
707 if (_filtered)
708 _list[OriginalIndex(index)] = value;
709 else
710 _list[index] = value;
711 }
712 }
713
714 #endregion
715
716 #region SourceList
717
722 [EditorBrowsable(EditorBrowsableState.Advanced)]
723 public IList<T> SourceList
724 {
725 get
726 {
727 return _list;
728 }
729 }
730
731 #endregion
732
733 private IList<T> _list;
734 private bool _supportsBinding;
735 private IBindingList _bindingList;
736 private bool _filtered;
737 private PropertyDescriptor _filterBy;
738 private object _filter;
739 FilterProvider _provider = null;
740 private List<ListItem> _filterIndex =
741 new List<ListItem>();
742
747 public FilteredBindingList(IList<T> list)
748 {
749 _list = list;
750
751 if (_list is IBindingList)
752 {
753 _supportsBinding = true;
754 _bindingList = (IBindingList)_list;
755 _bindingList.ListChanged +=
756 new ListChangedEventHandler(SourceChanged);
757 }
758 }
759
767 public FilteredBindingList(IList<T> list, FilterProvider filterProvider) : this(list)
768 {
769 _provider = filterProvider;
770 }
771
786 {
787 get
788 {
789 return _provider;
790 }
791 set
792 {
793 _provider = value;
794 }
795 }
796
804 public PropertyDescriptor FilterProperty
805 {
806 get { return _filterBy; }
807 }
808
812 public bool IsFiltered
813 {
814 get { return _filtered; }
815 }
816
822 public void ApplyFilter()
823 {
824 if (_filterBy == null || _filter == null)
825 throw new ArgumentNullException(Resources.FilterRequiredException);
826 DoFilter();
827 }
828
834 public void ApplyFilter(string propertyName, object filter)
835 {
836 _filterBy = null;
837 _filter = filter;
838
839 if (!String.IsNullOrEmpty(propertyName))
840 {
841 Type itemType = typeof(T);
842 foreach (PropertyDescriptor prop in
843 TypeDescriptor.GetProperties(itemType))
844 {
845 if (prop.Name == propertyName)
846 {
847 _filterBy = prop;
848 break;
849 }
850 }
851 }
852
853 ApplyFilter(_filterBy, filter);
854
855 }
856
862 public void ApplyFilter(
863 PropertyDescriptor property, object filter)
864 {
865 _filterBy = property;
866 _filter = filter;
867 DoFilter();
868 }
869
875 public void RemoveFilter()
876 {
877 UnDoFilter();
878 }
879
880 private void SourceChanged(
881 object sender, ListChangedEventArgs e)
882 {
883 if (_filtered)
884 {
885 int listIndex;
886 int filteredIndex = -1;
887 T newItem;
888 object newKey;
889 switch (e.ListChangedType)
890 {
891 case ListChangedType.ItemAdded:
892 listIndex = e.NewIndex;
893 // add new value to index
894 newItem = _list[listIndex];
895 if (_filterBy != null)
896 newKey = _filterBy.GetValue(newItem);
897 else
898 newKey = newItem;
899 _filterIndex.Add(
900 new ListItem(newKey, listIndex));
901 filteredIndex = _filterIndex.Count - 1;
902 // raise event
904 new ListChangedEventArgs(
905 e.ListChangedType, filteredIndex));
906 break;
907
908 case ListChangedType.ItemChanged:
909 listIndex = e.NewIndex;
910 // update index value
911 filteredIndex = FilteredIndex(listIndex);
912 if (filteredIndex != -1)
913 {
914 newItem = _list[listIndex];
915 if (_filterBy != null)
916 newKey = _filterBy.GetValue(newItem);
917 else
918 newKey = newItem;
919 _filterIndex[filteredIndex] =
920 new ListItem(newKey, listIndex);
921 }
922 // raise event if appropriate
923 if (filteredIndex > -1)
925 new ListChangedEventArgs(
926 e.ListChangedType, filteredIndex, e.PropertyDescriptor));
927 break;
928
929 case ListChangedType.ItemDeleted:
930 listIndex = e.NewIndex;
931 // delete corresponding item from index
932 // (if any)
933 filteredIndex = FilteredIndex(listIndex);
934 if (filteredIndex != -1)
935 _filterIndex.RemoveAt(filteredIndex);
936 // adjust index xref values
937 foreach (ListItem item in _filterIndex)
938 if (item.BaseIndex > e.NewIndex)
939 item.BaseIndex--;
940 // raise event if appropriate
941 if (filteredIndex > -1)
943 new ListChangedEventArgs(
944 e.ListChangedType, filteredIndex));
945 break;
946
947 case ListChangedType.PropertyDescriptorAdded:
948 case ListChangedType.PropertyDescriptorChanged:
949 case ListChangedType.PropertyDescriptorDeleted:
950 OnListChanged(e);
951 break;
952
953 default:
954 DoFilter();
956 new ListChangedEventArgs(
957 ListChangedType.Reset, 0));
958 break;
959 }
960 }
961 else
962 OnListChanged(e);
963 }
964
965 private int OriginalIndex(int filteredIndex)
966 {
967 if (_filtered)
968 return _filterIndex[filteredIndex].BaseIndex;
969 else
970 return filteredIndex;
971 }
972
973 private int FilteredIndex(int originalIndex)
974 {
975 int result = -1;
976 if (_filtered)
977 {
978 for (int index = 0; index < _filterIndex.Count; index++)
979 {
980 if (_filterIndex[index].BaseIndex == originalIndex)
981 {
982 result = index;
983 break;
984 }
985 }
986 }
987 else
988 result = originalIndex;
989 return result;
990 }
991
992 #region ICancelAddNew Members
993
994 //private T _newItem;
995
996 //void ICancelAddNew.CancelNew(int itemIndex)
997 //{
998 // if (_newItem != null)
999 // Remove(_newItem);
1000 //}
1001
1002 //void ICancelAddNew.EndNew(int itemIndex)
1003 //{
1004 // // do nothing
1005 //}
1006
1007 void ICancelAddNew.CancelNew(int itemIndex)
1008 {
1009 if (itemIndex <= -1) return;
1010
1011 ICancelAddNew can = _list as ICancelAddNew;
1012 if (can != null)
1013 can.CancelNew(OriginalIndex(itemIndex));
1014 else
1015 _list.RemoveAt(OriginalIndex(itemIndex));
1016 }
1017
1018 void ICancelAddNew.EndNew(int itemIndex)
1019 {
1020 ICancelAddNew can = _list as ICancelAddNew;
1021 if (can != null)
1022 can.EndNew(OriginalIndex(itemIndex));
1023 }
1024
1025 #endregion
1026
1027 #region ToArray
1028
1032 public T[] ToArray()
1033 {
1034 List<T> result = new List<T>();
1035 foreach (T item in this)
1036 result.Add(item);
1037 return result.ToArray();
1038 }
1039
1040 #endregion
1041
1042 }
1043}
Provides a filtered view into an existing IList(Of T).
int Find(string propertyName, object key)
Finds an item in the view
void ApplyFilter()
Applies a filter to the view using the most recently used property name and filter provider.
void OnListChanged(ListChangedEventArgs e)
Raises the ListChanged event.
void ApplyFilter(string propertyName, object filter)
Applies a filter to the view.
bool IsFiltered
Returns True if the view is currently filtered.
void RemoveAt(int index)
Removes an item from the list.
bool SupportsSearching
Implemented by IList source object.
void RemoveFilter()
Removes the filter from the list, so the view reflects the state of the original list.
PropertyDescriptor FilterProperty
The property on which the items will be filtered.
ListSortDirection SortDirection
Returns the direction of the current sort.
void Clear()
Clears the list.
void RemoveIndex(PropertyDescriptor property)
Implemented by IList source object.
void Insert(int index, T item)
Inserts an item into the list.
T[] ToArray()
Get an array containing all items in the list.
IList< T > SourceList
Gets the source list over which this SortedBindingList is a view.
bool SupportsSorting
Returns True.
IEnumerator< T > GetEnumerator()
Gets an enumerator object.
bool AllowEdit
Implemented by IList source object.
bool AllowRemove
Implemented by IList source object.
bool IsReadOnly
Gets a value indicating whether the list is read-only.
void Add(T item)
Adds an item to the list.
void ApplySort(string propertyName, ListSortDirection direction)
Sorts the list if the original list supports sorting.
void AddIndex(PropertyDescriptor property)
Implemented by IList source object.
ListChangedEventHandler ListChanged
Raised to indicate that the list's data has changed.
void RemoveSort()
Removes any sort currently applied to the view.
bool Contains(T item)
Determines whether the specified item is contained in the list.
bool Remove(T item)
Removes an item from the list.
void CopyTo(T[] array, int arrayIndex)
Copies the contents of the list to an array.
int IndexOf(T item)
Gets the 0-based index of an item in the list.
bool SupportsChangeNotification
Returns True since this object does raise the ListChanged event.
PropertyDescriptor SortProperty
Returns the PropertyDescriptor of the current sort.
object AddNew()
Implemented by IList source object.
FilteredBindingList(IList< T > list, FilterProvider filterProvider)
Creates a new view based on the provided IList object.
int Count
Gets the number of items in the list.
FilterProvider FilterProvider
Gets or sets the filter provider method.
void ApplyFilter(PropertyDescriptor property, object filter)
Applies a filter to the view.
void ApplySort(PropertyDescriptor property, ListSortDirection direction)
Sorts the list if the original list supports sorting.
int Find(PropertyDescriptor property, object key)
Implemented by IList source object.
bool IsSorted
Returns True if the view is currently sorted.
bool AllowNew
Implemented by IList source object.
FilteredBindingList(IList< T > list)
Creates a new view based on the provided IList object.
A strongly-typed resource class, for looking up localized strings, etc.
static string SortingNotSupported
Looks up a localized string similar to Sorting not supported.
static string FilterRequiredException
Looks up a localized string similar to Filter parameter and filter provider are required.
static string SortedBindingListPropertyNameNotFound
Looks up a localized string similar to PropertyName '{0}' not found in list.