1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2007 Novell, Inc.
24 using System.Collections;
25 using System.Collections.Generic;
26 using System.Collections.ObjectModel;
27 using System.Reflection;
29 namespace System.ComponentModel {
30 [SerializableAttribute]
31 public class BindingList<T> : Collection<T>,
32 IBindingList, IList, ICollection,
33 IEnumerable, ICancelAddNew, IRaiseItemChangedEvents
35 bool allow_edit = true;
36 bool allow_remove = true;
40 bool raise_list_changed_events = true;
42 bool type_has_default_ctor;
43 bool type_raises_item_changed_events;
46 int pending_add_index;
50 ConstructorInfo ci = typeof (T).GetConstructor (Type.EmptyTypes);
51 type_has_default_ctor = (ci != null);
52 type_raises_item_changed_events = typeof (INotifyPropertyChanged).IsAssignableFrom (typeof (T));
55 public BindingList (IList<T> list) : base(list)
60 public BindingList () : base ()
65 public bool AllowEdit {
66 get { return allow_edit; }
68 if (allow_edit != value) {
71 if (raise_list_changed_events)
72 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 /* XXX */));
77 public bool AllowNew {
79 /* if the user explicitly it, return that value */
83 /* if the list type has a default constructor we allow new */
84 if (type_has_default_ctor)
87 /* if the user adds a delegate, we return true even if
88 the type doesn't have a default ctor */
89 if (AddingNew != null)
95 // this funky check (using AllowNew
96 // instead of allow_new allows us to
97 // keep the logic for the 3 cases in
98 // one place (the getter) instead of
99 // spreading them around the file (in
100 // the ctor, in the AddingNew add
102 if (AllowNew != value) {
103 allow_new_set = true;
107 if (raise_list_changed_events)
108 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 /* XXX */));
113 public bool AllowRemove {
114 get { return allow_remove; }
116 if (allow_remove != value) {
117 allow_remove = value;
119 if (raise_list_changed_events)
120 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 /* XXX */));
125 protected virtual bool IsSortedCore {
126 get { return false; }
129 public bool RaiseListChangedEvents {
130 get { return raise_list_changed_events; }
131 set { raise_list_changed_events = value; }
134 protected virtual ListSortDirection SortDirectionCore {
135 get { return ListSortDirection.Ascending; }
138 protected virtual PropertyDescriptor SortPropertyCore {
142 protected virtual bool SupportsChangeNotificationCore {
146 protected virtual bool SupportsSearchingCore {
147 get { return false; }
150 protected virtual bool SupportsSortingCore {
151 get { return false; }
154 public event AddingNewEventHandler AddingNew;
155 public event ListChangedEventHandler ListChanged;
159 return (T)AddNewCore ();
162 protected virtual object AddNewCore ()
165 throw new InvalidOperationException ();
167 AddingNewEventArgs args = new AddingNewEventArgs ();
171 T new_obj = (T)args.NewObject;
172 if (new_obj == null) {
173 if (!type_has_default_ctor)
174 throw new InvalidOperationException ();
176 new_obj = (T)Activator.CreateInstance (typeof (T));
180 pending_add_index = IndexOf (new_obj);
186 protected virtual void ApplySortCore (PropertyDescriptor prop, ListSortDirection direction)
188 throw new NotSupportedException ();
191 public virtual void CancelNew (int itemIndex)
196 if (itemIndex != pending_add_index)
201 base.RemoveItem (itemIndex);
203 if (raise_list_changed_events)
204 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, itemIndex));
207 protected override void ClearItems ()
209 EndNew (pending_add_index);
210 if (type_raises_item_changed_events) {
211 foreach ( T item in base.Items ) {
212 (item as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
217 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
220 public virtual void EndNew (int itemIndex)
225 if (itemIndex != pending_add_index)
231 protected virtual int FindCore (PropertyDescriptor prop, object key)
233 throw new NotSupportedException ();
236 protected override void InsertItem (int index, T item)
238 EndNew (pending_add_index);
240 base.InsertItem (index, item);
242 if (raise_list_changed_events)
243 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, index));
245 if (item != null && type_raises_item_changed_events)
246 (item as INotifyPropertyChanged).PropertyChanged += Item_PropertyChanged;
249 void Item_PropertyChanged (object item, PropertyChangedEventArgs args)
251 var property_info = item.GetType ().GetProperty (args.PropertyName);
253 if (property_info != null) {
254 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, base.IndexOf ((T) item),
255 new ReflectionPropertyDescriptor (property_info)) );
257 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, base.IndexOf ((T) item)) );
261 protected virtual void OnAddingNew (AddingNewEventArgs e)
263 if (AddingNew != null)
267 protected virtual void OnListChanged (ListChangedEventArgs e)
269 if (ListChanged != null)
270 ListChanged (this, e);
273 protected override void RemoveItem (int index)
276 throw new NotSupportedException ();
278 EndNew (pending_add_index);
279 if (type_raises_item_changed_events) {
280 (base[index] as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
282 base.RemoveItem (index);
284 if (raise_list_changed_events)
285 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, index));
288 protected virtual void RemoveSortCore ()
290 throw new NotSupportedException ();
293 public void ResetBindings ()
295 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
298 public void ResetItem (int position)
300 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, position));
303 protected override void SetItem (int index, T item)
305 if (type_raises_item_changed_events) {
306 (base[index] as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
307 (item as INotifyPropertyChanged).PropertyChanged += Item_PropertyChanged;
309 base.SetItem (index, item);
311 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, index));
314 void IBindingList.AddIndex (PropertyDescriptor index)
316 /* no implementation by default */
319 object IBindingList.AddNew ()
324 void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction)
326 ApplySortCore (property, direction);
329 int IBindingList.Find (PropertyDescriptor property, object key)
331 return FindCore (property, key);
334 void IBindingList.RemoveIndex (PropertyDescriptor property)
336 /* no implementation by default */
339 void IBindingList.RemoveSort ()
344 bool IBindingList.IsSorted {
345 get { return IsSortedCore; }
348 ListSortDirection IBindingList.SortDirection {
349 get { return SortDirectionCore; }
352 PropertyDescriptor IBindingList.SortProperty {
353 get { return SortPropertyCore; }
356 bool IBindingList.AllowEdit {
357 get { return AllowEdit; }
360 bool IBindingList.AllowNew {
361 get { return AllowNew; }
364 bool IBindingList.AllowRemove {
365 get { return AllowRemove; }
368 bool IBindingList.SupportsChangeNotification {
369 get { return SupportsChangeNotificationCore; }
372 bool IBindingList.SupportsSearching {
373 get { return SupportsSearchingCore; }
376 bool IBindingList.SupportsSorting {
377 get { return SupportsSortingCore; }
380 bool IRaiseItemChangedEvents.RaisesItemChangedEvents {
381 get { return type_raises_item_changed_events; }