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 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, base.IndexOf ((T) item)) );
254 protected virtual void OnAddingNew (AddingNewEventArgs e)
256 if (AddingNew != null)
260 protected virtual void OnListChanged (ListChangedEventArgs e)
262 if (ListChanged != null)
263 ListChanged (this, e);
266 protected override void RemoveItem (int index)
269 throw new NotSupportedException ();
271 EndNew (pending_add_index);
272 if (type_raises_item_changed_events) {
273 (base[index] as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
275 base.RemoveItem (index);
277 if (raise_list_changed_events)
278 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, index));
281 protected virtual void RemoveSortCore ()
283 throw new NotSupportedException ();
286 public void ResetBindings ()
288 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
291 public void ResetItem (int position)
293 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, position));
296 protected override void SetItem (int index, T item)
298 if (type_raises_item_changed_events) {
299 (base[index] as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
300 (item as INotifyPropertyChanged).PropertyChanged += Item_PropertyChanged;
302 base.SetItem (index, item);
304 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, index));
307 void IBindingList.AddIndex (PropertyDescriptor index)
309 /* no implementation by default */
312 object IBindingList.AddNew ()
317 void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction)
319 ApplySortCore (property, direction);
322 int IBindingList.Find (PropertyDescriptor property, object key)
324 return FindCore (property, key);
327 void IBindingList.RemoveIndex (PropertyDescriptor property)
329 /* no implementation by default */
332 void IBindingList.RemoveSort ()
337 bool IBindingList.IsSorted {
338 get { return IsSortedCore; }
341 ListSortDirection IBindingList.SortDirection {
342 get { return SortDirectionCore; }
345 PropertyDescriptor IBindingList.SortProperty {
346 get { return SortPropertyCore; }
349 bool IBindingList.AllowEdit {
350 get { return AllowEdit; }
353 bool IBindingList.AllowNew {
354 get { return AllowNew; }
357 bool IBindingList.AllowRemove {
358 get { return AllowRemove; }
361 bool IBindingList.SupportsChangeNotification {
362 get { return SupportsChangeNotificationCore; }
365 bool IBindingList.SupportsSearching {
366 get { return SupportsSearchingCore; }
369 bool IBindingList.SupportsSorting {
370 get { return SupportsSortingCore; }
373 bool IRaiseItemChangedEvents.RaisesItemChangedEvents {
374 get { return type_raises_item_changed_events; }