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:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
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.
19 //
20 // Copyright (c) 2007 Novell, Inc.
21 //
22 
23 using System.ComponentModel;
24 using System.Collections;
25 using System.Collections.Generic;
26 using System.Reflection;
27 using System.Text;
28 using System.Text.RegularExpressions;
29 
30 namespace System.Windows.Forms {
31 
32 	[ComplexBindingProperties ("DataSource", "DataMember")]
33 	[DefaultEvent ("CurrentChanged")]
34 	[DefaultProperty ("DataSource")]
35 	[Designer("System.Windows.Forms.Design.BindingSourceDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
36 	public class BindingSource : Component,
37 		ICancelAddNew, IDisposable, ISupportInitialize,
38 		IBindingListView, IBindingList, ITypedList,
39 		IList, ISupportInitializeNotification, ICollection,
40 		IComponent, ICurrencyManagerProvider, IEnumerable
41 	{
42 		bool is_initialized = true;
43 
44 		IList list;
45 		CurrencyManager currency_manager;
46 		Dictionary<string,CurrencyManager> related_currency_managers = new Dictionary<string,CurrencyManager> ();
47 		//bool list_defaulted;
48 		internal Type item_type;
49 		bool item_has_default_ctor;
50 		bool list_is_ibinding;
51 
52 		object datasource;
53 		string datamember;
54 
55 		bool raise_list_changed_events;
56 
57 		bool allow_new_set;
58 		bool allow_new;
59 
60 		bool add_pending;
61 		int pending_add_index;
62 
63 		string filter;
64 		string sort;
65 
BindingSource(IContainer container)66 		public BindingSource (IContainer container) : this ()
67 		{
68 			container.Add (this);
69 		}
70 
BindingSource(object dataSource, string dataMember)71 		public BindingSource (object dataSource, string dataMember)
72 		{
73 			datasource = dataSource;
74 			datamember = dataMember;
75 
76 			raise_list_changed_events = true;
77 
78 			ResetList ();
79 			ConnectCurrencyManager ();
80 		}
81 
BindingSource()82 		public BindingSource () : this (null, String.Empty)
83 		{
84 		}
85 
GetListFromEnumerable(IEnumerable enumerable)86 		IList GetListFromEnumerable (IEnumerable enumerable)
87 		{
88 			IList l = null;
89 
90 			IEnumerator e = enumerable.GetEnumerator();
91 
92 			if (enumerable is string) {
93 				/* special case this.. seems to be the only one .net special cases? */
94 				l = new BindingList<char> ();
95 			}
96 			else {
97 				/* try to figure out the type based on
98 				 * the first element, if there is
99 				 * one */
100 				object first = null;
101 				if (e.MoveNext ()) {
102 					first = e.Current;
103 				}
104 
105 				if (first == null) {
106 					return null;
107 				}
108 				else {
109 					Type t = typeof (BindingList<>).MakeGenericType (new Type[] { first.GetType() });
110 					l = (IList)Activator.CreateInstance (t);
111 				}
112 			}
113 
114 			e.Reset ();
115 			while (e.MoveNext ()) {
116 				l.Add (e.Current);
117 			}
118 
119 			return l;
120 		}
121 
ConnectCurrencyManager()122 		void ConnectCurrencyManager ()
123 		{
124 			currency_manager = new CurrencyManager (this);
125 
126 			currency_manager.PositionChanged += delegate (object o, EventArgs args) { OnPositionChanged (args); };
127 			currency_manager.CurrentChanged += delegate (object o, EventArgs args) { OnCurrentChanged (args); };
128 			currency_manager.BindingComplete += delegate (object o, BindingCompleteEventArgs args) { OnBindingComplete (args); };
129 			currency_manager.DataError += delegate (object o, BindingManagerDataErrorEventArgs args) { OnDataError (args); };
130 			currency_manager.CurrentChanged += delegate (object o, EventArgs args) { OnCurrentChanged (args); };
131 			currency_manager.CurrentItemChanged += delegate (object o, EventArgs args) { OnCurrentItemChanged (args); };
132 		}
133 
ResetList()134 		void ResetList ()
135 		{
136 			if (!is_initialized)
137 				return;
138 
139 			IList l;
140 			object source = ListBindingHelper.GetList (datasource, datamember);
141 
142 			//
143 			// If original source is null, then create a new object list
144 			// Otherwise, try to infer the list item type
145 			//
146 
147 			if (datasource == null) {
148 				l = new BindingList<object>();
149 				//list_defaulted = true;
150 			} else if (source == null) {
151 				//Infer type based on datasource and datamember,
152 				// where datasource is an empty IEnumerable
153 				// and need to find out the datamember type
154 
155 				Type property_type = ListBindingHelper.GetListItemProperties (datasource) [datamember].PropertyType;
156 				Type t = typeof (BindingList<>).MakeGenericType (new Type [] { property_type } );
157 				l = (IList)Activator.CreateInstance (t);
158 			} else if (source is IList) {
159 				l = (IList)source;
160 			} else if (source is IEnumerable) {
161 				IList new_list = GetListFromEnumerable ((IEnumerable)source);
162 				l = new_list == null ? list : new_list;
163 			} else if (source is Type) {
164 				Type t = typeof (BindingList<>).MakeGenericType (new Type [] { (Type)source });
165 				l = (IList)Activator.CreateInstance (t);
166 			} else {
167 				Type t = typeof (BindingList<>).MakeGenericType (new Type[] { source.GetType() });
168 				l = (IList)Activator.CreateInstance (t);
169 				l.Add (source);
170 			}
171 
172 			SetList (l);
173 		}
174 
SetList(IList l)175 		void SetList (IList l)
176 		{
177 			if (list is IBindingList)
178 				((IBindingList) list).ListChanged -= IBindingListChangedHandler;
179 
180 			list = l;
181 			item_type = ListBindingHelper.GetListItemType (list);
182 			item_has_default_ctor = item_type.GetConstructor (Type.EmptyTypes) != null;
183 
184 			list_is_ibinding = list is IBindingList;
185 			if (list_is_ibinding) {
186 				((IBindingList) list).ListChanged += IBindingListChangedHandler;
187 
188 				if (list is IBindingListView)
189 					((IBindingListView)list).Filter = filter;
190 			}
191 
192 			ResetBindings (true);
193 		}
194 
ConnectDataSourceEvents(object dataSource)195 		private void ConnectDataSourceEvents (object dataSource)
196 		{
197 			if (dataSource == null)
198 				return;
199 
200 			ICurrencyManagerProvider currencyManagerProvider = dataSource as ICurrencyManagerProvider;
201 			if (currencyManagerProvider != null && currencyManagerProvider.CurrencyManager != null) {
202 				currencyManagerProvider.CurrencyManager.CurrentItemChanged += OnParentCurrencyManagerChanged;
203 				currencyManagerProvider.CurrencyManager.MetaDataChanged += OnParentCurrencyManagerChanged;
204 			}
205 		}
206 
OnParentCurrencyManagerChanged(object sender, EventArgs args)207 		private void OnParentCurrencyManagerChanged (object sender, EventArgs args)
208 		{
209 			// Essentially handles chained data sources (e.g. chained BindingSource)
210 			ResetDataMemberIfInvalid ();
211 			ResetList ();
212 		}
213 
DisconnectDataSourceEvents(object dataSource)214 		private void DisconnectDataSourceEvents (object dataSource)
215 		{
216 			if (dataSource == null)
217 				return;
218 
219 			ICurrencyManagerProvider currencyManagerProvider = dataSource as ICurrencyManagerProvider;
220 			if (currencyManagerProvider != null && currencyManagerProvider.CurrencyManager != null) {
221 				currencyManagerProvider.CurrencyManager.CurrentItemChanged -= OnParentCurrencyManagerChanged;
222 				currencyManagerProvider.CurrencyManager.MetaDataChanged -= OnParentCurrencyManagerChanged;
223 			}
224 		}
225 
IBindingListChangedHandler(object o, ListChangedEventArgs args)226 		void IBindingListChangedHandler (object o, ListChangedEventArgs args)
227 		{
228 			if (raise_list_changed_events)
229 				OnListChanged (args);
230 		}
231 
232 		[Browsable (false)]
233 		public virtual bool AllowEdit {
234 			get {
235 				if (list == null)
236 					return false;
237 
238 				if (list.IsReadOnly)
239 					return false;
240 
241 				if (list is IBindingList)
242 					return ((IBindingList)list).AllowEdit;
243 
244 				return true;
245 			}
246 		}
247 
248 		public virtual bool AllowNew {
249 			get {
250 				if (allow_new_set)
251 					return allow_new;
252 
253 				if (list is IBindingList)
254 					return ((IBindingList)list).AllowNew;
255 
256 				if (list.IsFixedSize || list.IsReadOnly || !item_has_default_ctor)
257 					return false;
258 
259 				return true;
260 			}
261 			set {
262 				if (value == allow_new && allow_new_set)
263 					return;
264 
265 				if (value && (list.IsReadOnly || list.IsFixedSize))
266 					throw new InvalidOperationException ();
267 
268 				allow_new_set = true;
269 				allow_new = value;
270 
271 				if (raise_list_changed_events)
272 					OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
273 			}
274 		}
275 
276 		bool IsAddingNewHandled {
277 			get {
278 				return Events [AddingNewEvent] != null;
279 			}
280 		}
281 
282 		[Browsable (false)]
283 		public virtual bool AllowRemove {
284 			get {
285 				if (list == null)
286 					return false;
287 
288 				if (list.IsFixedSize || list.IsReadOnly)
289 					return false;
290 
291 				if (list is IBindingList)
292 					return ((IBindingList)list).AllowRemove;
293 
294 				return true;
295 			}
296 		}
297 
298 		[Browsable (false)]
299 		public virtual int Count {
300 			get {
301 				return list.Count;
302 			}
303 		}
304 
305 		[Browsable (false)]
306 		public virtual CurrencyManager CurrencyManager {
307 			get {
308 				return currency_manager;
309 			}
310 		}
311 
312 		[Browsable (false)]
313 		public object Current {
314 			get {
315 				if (currency_manager.Count > 0)
316 					return currency_manager.Current;
317 				return null;
318 			}
319 		}
320 
321 		[DefaultValue ("")]
322 		[Editor("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
323 		[RefreshProperties (RefreshProperties.Repaint)]
324 		public string DataMember {
325 			get { return datamember; }
326 			set {
327 				/* we don't allow null DataMembers */
328 				if (value == null)
329 					value = String.Empty;
330 
331 				if (datamember != value) {
332 					this.datamember = value;
333 
334 					ResetList ();
335 
336 					OnDataMemberChanged (EventArgs.Empty);
337 				}
338 			}
339 		}
340 
341 		[AttributeProvider (typeof(IListSource))]
342 		[RefreshProperties (RefreshProperties.Repaint)]
343 		[DefaultValue (null)]
344 		public object DataSource {
345 			get { return datasource; }
346 			set {
347 				if (datasource != value) {
348 					if (value == null)
349 						datamember = String.Empty;
350 
351 					DisconnectDataSourceEvents (datasource);
352 					datasource = value;
353 					ResetDataMemberIfInvalid ();
354 					ConnectDataSourceEvents (datasource);
355 					ResetList ();
356 
357 					OnDataSourceChanged (EventArgs.Empty);
358 				}
359 			}
360 		}
361 
362 		[DefaultValue (null)]
363 		public virtual string Filter {
364 			get {
365 				return filter;
366 			}
367 			set {
368 				if (SupportsFiltering)
369 					((IBindingListView)list).Filter = value;
370 
371 				filter = value;
372 			}
373 		}
374 
375 		[Browsable (false)]
376 		public bool IsBindingSuspended {
377 			get { return currency_manager.IsBindingSuspended; }
378 		}
379 
380 		[Browsable (false)]
381 		public virtual bool IsFixedSize {
382 			get { return list.IsFixedSize; }
383 		}
384 
385 		[Browsable (false)]
386 		public virtual bool IsReadOnly {
387 			get { return list.IsReadOnly; }
388 		}
389 
390 		[Browsable (false)]
391 		public virtual bool IsSorted {
392 			get { return (list is IBindingList) && ((IBindingList)list).IsSorted; }
393 		}
394 
395 		[Browsable (false)]
396 		public virtual bool IsSynchronized {
397 			get {
398 				return list.IsSynchronized;
399 			}
400 		}
401 
402 		[Browsable (false)]
403 		public virtual object this [int index] {
404 			get { return list[index]; }
405 			set
406 			{
407 				list[index] = value;
408 			}
409 		}
410 
411 		[Browsable (false)]
412 		public IList List {
413 			get { return list; }
414 		}
415 
416 		[DefaultValue (-1)]
417 		[Browsable (false)]
418 		public int Position {
419 			get {
420 				return currency_manager.Position;
421 			}
422 			set {
423 				if (value >= Count) value = Count - 1;
424 				if (value < 0) value = 0;
425 
426 				currency_manager.Position = value;
427 			}
428 		}
429 
430 		[Browsable (false)]
431 		[DefaultValue (true)]
432 		public bool RaiseListChangedEvents {
433 			get { return raise_list_changed_events; }
434 			set { raise_list_changed_events = value; }
435 		}
436 
437 		[DefaultValue (null)]
438 		public string Sort {
439 			get {
440 				return sort;
441 			}
442 			set {
443 				if (value == null || value.Length == 0) {
444 					if (list_is_ibinding && SupportsSorting)
445 						RemoveSort ();
446 
447 					sort = value;
448 					return;
449 				}
450 
451 				if (!list_is_ibinding || !SupportsSorting)
452 					throw new ArgumentException ("value");
453 
454 				ProcessSortString (value);
455 				sort = value;
456 			}
457 		}
458 
ResetDataMemberIfInvalid()459 		void ResetDataMemberIfInvalid ()
460 		{
461 			if (datamember == String.Empty)
462 				return;
463 
464 			// if dataMember doesn't refer to a valid property of dataSource, we need to reset it
465 			var property = ListBindingHelper.GetListItemProperties (datasource).Find (datamember, true);
466 			if (property == null) {
467 				datamember = String.Empty;
468 				OnDataMemberChanged (EventArgs.Empty);
469 			}
470 		}
471 
472 		// NOTE: Probably the parsing can be improved
ProcessSortString(string sort)473 		void ProcessSortString (string sort)
474 		{
475 			// Only keep simple whitespaces in the middle
476 			sort = Regex.Replace (sort, "( )+", " ");
477 
478 			string [] properties = sort.Split (',');
479 			PropertyDescriptorCollection prop_descs = GetItemProperties (null);
480 			if (properties.Length == 1) {
481 				ListSortDescription sort_desc = GetListSortDescription (prop_descs, properties [0]);
482 				ApplySort (sort_desc.PropertyDescriptor, sort_desc.SortDirection);
483 			} else {
484 				if (!SupportsAdvancedSorting)
485 					throw new ArgumentException ("value");
486 
487 				ListSortDescription [] sort_descs = new ListSortDescription [properties.Length];
488 				for (int i = 0; i < properties.Length; i++)
489 					sort_descs [i] = GetListSortDescription (prop_descs, properties [i]);
490 
491 				ApplySort (new ListSortDescriptionCollection (sort_descs));
492 			}
493 
494 		}
495 
GetListSortDescription(PropertyDescriptorCollection prop_descs, string property)496 		ListSortDescription GetListSortDescription (PropertyDescriptorCollection prop_descs, string property)
497 		{
498 			property = property.Trim ();
499 			string [] p = property.Split (new char [] {' '}, 2);
500 
501 			string prop_name = p [0];
502 			PropertyDescriptor prop_desc = prop_descs [prop_name];
503 			if (prop_desc == null)
504 				throw new ArgumentException ("value");
505 
506 			ListSortDirection sort_direction = ListSortDirection.Ascending;
507 			if (p.Length > 1) {
508 				string dir_s = p [1];
509 				if (String.Compare (dir_s, "ASC", true) == 0)
510 					sort_direction = ListSortDirection.Ascending;
511 				else if (String.Compare (dir_s, "DESC", true) == 0)
512 					sort_direction = ListSortDirection.Descending;
513 				else
514 					throw new ArgumentException ("value");
515 			}
516 
517 			return new ListSortDescription (prop_desc, sort_direction);
518 		}
519 
520 		[Browsable (false)]
521 		[EditorBrowsable (EditorBrowsableState.Never)]
522 		public virtual ListSortDescriptionCollection SortDescriptions {
523 			get {
524 				if (list is IBindingListView)
525 					return ((IBindingListView)list).SortDescriptions;
526 
527 				return null;
528 			}
529 		}
530 
531 		[Browsable (false)]
532 		[EditorBrowsable (EditorBrowsableState.Never)]
533 		public virtual ListSortDirection SortDirection {
534 			get {
535 				if (list is IBindingList)
536 					return ((IBindingList)list).SortDirection;
537 
538 				return ListSortDirection.Ascending;
539 			}
540 		}
541 
542 		[Browsable (false)]
543 		[EditorBrowsable (EditorBrowsableState.Never)]
544 		public virtual PropertyDescriptor SortProperty {
545 			get {
546 				if (list is IBindingList)
547 					return ((IBindingList)list).SortProperty;
548 
549 				return null;
550 			}
551 		}
552 
553 		[Browsable (false)]
554 		public virtual bool SupportsAdvancedSorting {
555 			get { return (list is IBindingListView) && ((IBindingListView)list).SupportsAdvancedSorting; }
556 		}
557 
558 		[Browsable (false)]
559 		public virtual bool SupportsChangeNotification {
560 			get { return true; }
561 		}
562 
563 		[Browsable (false)]
564 		public virtual bool SupportsFiltering {
565 			get { return (list is IBindingListView) && ((IBindingListView)list).SupportsFiltering; }
566 		}
567 
568 		[Browsable (false)]
569 		public virtual bool SupportsSearching {
570 			get {
571 				return (list is IBindingList) && ((IBindingList)list).SupportsSearching;
572 			}
573 		}
574 
575 		[Browsable (false)]
576 		public virtual bool SupportsSorting {
577 			get { return (list is IBindingList) && ((IBindingList)list).SupportsSorting; }
578 		}
579 
580 		[Browsable (false)]
581 		public virtual object SyncRoot {
582 			get {
583 				return list.SyncRoot;
584 			}
585 		}
586 
587 		static object AddingNewEvent = new object ();
588 		static object BindingCompleteEvent = new object ();
589 		static object CurrentChangedEvent = new object ();
590 		static object CurrentItemChangedEvent = new object ();
591 		static object DataErrorEvent = new object ();
592 		static object DataMemberChangedEvent = new object ();
593 		static object DataSourceChangedEvent = new object ();
594 		static object ListChangedEvent = new object ();
595 		static object PositionChangedEvent= new object ();
596 
597 		public event AddingNewEventHandler AddingNew {
598 			add { Events.AddHandler (AddingNewEvent, value); }
599 			remove { Events.RemoveHandler (AddingNewEvent, value); }
600 		}
601 
602 		public event BindingCompleteEventHandler BindingComplete {
603 			add { Events.AddHandler (BindingCompleteEvent, value); }
604 			remove { Events.RemoveHandler (BindingCompleteEvent, value); }
605 		}
606 
607 		public event EventHandler CurrentChanged {
608 			add { Events.AddHandler (CurrentChangedEvent, value); }
609 			remove { Events.RemoveHandler (CurrentChangedEvent, value); }
610 		}
611 
612 		public event EventHandler CurrentItemChanged {
613 			add { Events.AddHandler (CurrentItemChangedEvent, value); }
614 			remove { Events.RemoveHandler (CurrentItemChangedEvent, value); }
615 		}
616 
617 		public event BindingManagerDataErrorEventHandler DataError {
618 			add { Events.AddHandler (DataErrorEvent, value); }
619 			remove { Events.RemoveHandler (DataErrorEvent, value); }
620 		}
621 
622 		public event EventHandler DataMemberChanged {
623 			add { Events.AddHandler (DataMemberChangedEvent, value); }
624 			remove { Events.RemoveHandler (DataMemberChangedEvent, value); }
625 		}
626 
627 		public event EventHandler DataSourceChanged {
628 			add { Events.AddHandler (DataSourceChangedEvent, value); }
629 			remove { Events.RemoveHandler (DataSourceChangedEvent, value); }
630 		}
631 
632 		public event ListChangedEventHandler ListChanged {
633 			add { Events.AddHandler (ListChangedEvent, value); }
634 			remove { Events.RemoveHandler (ListChangedEvent, value); }
635 		}
636 
637 		public event EventHandler PositionChanged {
638 			add { Events.AddHandler (PositionChangedEvent, value); }
639 			remove { Events.RemoveHandler (PositionChangedEvent, value); }
640 		}
641 
Add(object value)642 		public virtual int Add (object value)
643 		{
644 			//
645 			// First (re)create the BindingList<T> based on value
646 			// if datasource is null and the current list is empty
647 			//
648 			if (datasource == null && list.Count == 0 && value != null) {
649 				Type t = typeof (BindingList<>).MakeGenericType (new Type [] { value.GetType () } );
650 				IList l = (IList) Activator.CreateInstance (t);
651 				SetList (l);
652 			}
653 
654 			if (value != null && !item_type.IsAssignableFrom (value.GetType ()))
655 				throw new InvalidOperationException ("Objects added to the list must all be of the same type.");
656 			if (list.IsReadOnly)
657 				throw new NotSupportedException ("Collection is read-only.");
658 			if (list.IsFixedSize)
659 				throw new NotSupportedException ("Collection has a fixed size.");
660 
661 			int idx = list.Add (value);
662 			if (raise_list_changed_events && !list_is_ibinding)
663 				OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, idx));
664 
665 			return idx;
666 		}
667 
AddNew()668 		public virtual object AddNew ()
669 		{
670 			if (!AllowEdit)
671 				throw new InvalidOperationException ("Item cannot be added to a read-only or fixed-size list.");
672 			if (!AllowNew)
673 				throw new InvalidOperationException ("AddNew is set to false.");
674 
675 			EndEdit ();
676 
677 			AddingNewEventArgs args = new AddingNewEventArgs ();
678 			OnAddingNew (args);
679 
680 			object new_object = args.NewObject;
681 			if (new_object != null) {
682 				if (!item_type.IsAssignableFrom (new_object.GetType ()))
683 					throw new InvalidOperationException ("Objects added to the list must all be of the same type.");
684 			} else if (list is IBindingList) {
685 				object newObj = ((IBindingList)list).AddNew ();
686 				add_pending = true;
687 				pending_add_index = list.IndexOf (newObj);
688 				return newObj;
689 			} else if (!item_has_default_ctor)
690 				throw new InvalidOperationException ("AddNew cannot be called on '" + item_type.Name +
691 						", since it does not have a public default ctor. Set AllowNew to true " +
692 						", handling AddingNew and creating the appropriate object.");
693 			else // fallback to default .ctor
694 				new_object = Activator.CreateInstance (item_type);
695 
696 			int idx = list.Add (new_object);
697 			if (raise_list_changed_events && !list_is_ibinding)
698 				OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, idx));
699 
700 			add_pending = true;
701 			pending_add_index = idx;
702 
703 			return new_object;
704 		}
705 
706 		[EditorBrowsable (EditorBrowsableState.Never)]
ApplySort(PropertyDescriptor property, ListSortDirection sort)707 		public virtual void ApplySort (PropertyDescriptor property, ListSortDirection sort)
708 		{
709 			if (!list_is_ibinding)
710 				throw new NotSupportedException ("This operation requires an IBindingList.");
711 
712 			IBindingList iblist = (IBindingList)list;
713 			iblist.ApplySort (property, sort);
714 		}
715 
716 		[EditorBrowsable (EditorBrowsableState.Never)]
ApplySort(ListSortDescriptionCollection sorts)717 		public virtual void ApplySort (ListSortDescriptionCollection sorts)
718 		{
719 			if (!(list is IBindingListView))
720 				throw new NotSupportedException ("This operation requires an IBindingListView.");
721 
722 			IBindingListView iblist_view = (IBindingListView)list;
723 			iblist_view.ApplySort (sorts);
724 		}
725 
CancelEdit()726 		public void CancelEdit ()
727 		{
728 			currency_manager.CancelCurrentEdit ();
729 		}
730 
Clear()731 		public virtual void Clear ()
732 		{
733 			if (list.IsReadOnly)
734 				throw new NotSupportedException ("Collection is read-only.");
735 
736 			list.Clear ();
737 			if (raise_list_changed_events && !list_is_ibinding)
738 				OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
739 		}
740 
Contains(object value)741 		public virtual bool Contains (object value)
742 		{
743 			return list.Contains (value);
744 		}
745 
CopyTo(Array arr, int index)746 		public virtual void CopyTo (Array arr, int index)
747 		{
748 			list.CopyTo (arr, index);
749 		}
750 
Dispose(bool disposing)751 		protected override void Dispose (bool disposing)
752 		{
753 			base.Dispose (disposing);
754 		}
755 
EndEdit()756 		public void EndEdit ()
757 		{
758 			currency_manager.EndCurrentEdit ();
759 		}
760 
Find(string propertyName, object key)761 		public int Find (string propertyName, object key)
762 		{
763 			PropertyDescriptor property = GetItemProperties (null).Find (propertyName, true);
764 			if (property == null)
765 				throw new ArgumentException ("propertyName");
766 
767 			return Find (property, key);
768 		}
769 
Find(PropertyDescriptor prop, object key)770 		public virtual int Find (PropertyDescriptor prop, object key)
771 		{
772 			if (!list_is_ibinding)
773 				throw new NotSupportedException ();
774 
775 			return ((IBindingList)list).Find (prop, key);
776 		}
777 
GetEnumerator()778 		public virtual IEnumerator GetEnumerator ()
779 		{
780 			return this.List.GetEnumerator ();
781 		}
782 
GetItemProperties(PropertyDescriptor[] listAccessors)783 		public virtual PropertyDescriptorCollection GetItemProperties (PropertyDescriptor[] listAccessors)
784 		{
785 			return ListBindingHelper.GetListItemProperties (list, listAccessors);
786 		}
787 
GetListName(PropertyDescriptor[] listAccessors)788 		public virtual string GetListName (PropertyDescriptor[] listAccessors)
789 		{
790 			return ListBindingHelper.GetListName (list, listAccessors);
791 		}
792 
GetRelatedCurrencyManager(string dataMember)793 		public virtual CurrencyManager GetRelatedCurrencyManager (string dataMember)
794 		{
795 			if (dataMember == null || dataMember.Length == 0)
796 				return currency_manager;
797 
798 			if (related_currency_managers.ContainsKey (dataMember))
799 				return related_currency_managers [dataMember];
800 
801 			// FIXME - Why passing invalid dataMembers containing a . return
802 			// a null value?
803 			if (dataMember.IndexOf ('.') != -1)
804 				return null;
805 
806 			BindingSource source = new BindingSource (this, dataMember);
807 			related_currency_managers [dataMember] = source.CurrencyManager;
808 
809 			return source.CurrencyManager;
810 		}
811 
IndexOf(object value)812 		public virtual int IndexOf (object value)
813 		{
814 			return list.IndexOf (value);
815 		}
816 
Insert(int index, object value)817 		public virtual void Insert (int index, object value)
818 		{
819 			if (index < 0 || index > list.Count)
820 				throw new ArgumentOutOfRangeException ("index");
821 			if (list.IsReadOnly || list.IsFixedSize)
822 				throw new NotSupportedException ();
823 			if (!item_type.IsAssignableFrom (value.GetType ()))
824 				throw new ArgumentException ("value");
825 
826 			list.Insert (index, value);
827 			if (raise_list_changed_events && !list_is_ibinding)
828 				OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, index));
829 		}
830 
MoveFirst()831 		public void MoveFirst ()
832 		{
833 			Position = 0;
834 		}
835 
MoveLast()836 		public void MoveLast ()
837 		{
838 			Position = Count - 1;
839 		}
840 
MoveNext()841 		public void MoveNext ()
842 		{
843 			Position ++;
844 		}
845 
MovePrevious()846 		public void MovePrevious ()
847 		{
848 			Position --;
849 		}
850 
OnAddingNew(AddingNewEventArgs e)851 		protected virtual void OnAddingNew (AddingNewEventArgs e)
852 		{
853 			AddingNewEventHandler eh = (AddingNewEventHandler)Events[AddingNewEvent];
854 			if (eh != null)
855 				eh (this, e);
856 		}
857 
OnBindingComplete(BindingCompleteEventArgs e)858 		protected virtual void OnBindingComplete (BindingCompleteEventArgs e)
859 		{
860 			BindingCompleteEventHandler eh = (BindingCompleteEventHandler) Events[BindingCompleteEvent];
861 			if (eh != null)
862 				eh (this, e);
863 		}
864 
OnCurrentChanged(EventArgs e)865 		protected virtual void OnCurrentChanged (EventArgs e)
866 		{
867 			EventHandler eh = (EventHandler) Events[CurrentChangedEvent];
868 			if (eh != null)
869 				eh (this, e);
870 		}
871 
OnCurrentItemChanged(EventArgs e)872 		protected virtual void OnCurrentItemChanged (EventArgs e)
873 		{
874 			EventHandler eh = (EventHandler) Events[CurrentItemChangedEvent];
875 			if (eh != null)
876 				eh (this, e);
877 		}
878 
OnDataError(BindingManagerDataErrorEventArgs e)879 		protected virtual void OnDataError (BindingManagerDataErrorEventArgs e)
880 		{
881 			BindingManagerDataErrorEventHandler eh = (BindingManagerDataErrorEventHandler) Events[DataErrorEvent];
882 			if (eh != null)
883 				eh (this, e);
884 		}
885 
OnDataMemberChanged(EventArgs e)886 		protected virtual void OnDataMemberChanged (EventArgs e)
887 		{
888 			EventHandler eh = (EventHandler) Events[DataMemberChangedEvent];
889 			if (eh != null)
890 				eh (this, e);
891 		}
892 
OnDataSourceChanged(EventArgs e)893 		protected virtual void OnDataSourceChanged (EventArgs e)
894 		{
895 			EventHandler eh = (EventHandler) Events[DataSourceChangedEvent];
896 			if (eh != null)
897 				eh (this, e);
898 		}
899 
OnListChanged(ListChangedEventArgs e)900 		protected virtual void OnListChanged (ListChangedEventArgs e)
901 		{
902 			ListChangedEventHandler eh = (ListChangedEventHandler) Events[ListChangedEvent];
903 			if (eh != null)
904 				eh (this, e);
905 		}
906 
OnPositionChanged(EventArgs e)907 		protected virtual void OnPositionChanged (EventArgs e)
908 		{
909 			EventHandler eh = (EventHandler) Events[PositionChangedEvent];
910 			if (eh != null)
911 				eh (this, e);
912 		}
913 
Remove(object value)914 		public virtual void Remove (object value)
915 		{
916 			if (list.IsReadOnly)
917 				throw new NotSupportedException ("Collection is read-only.");
918 			if (list.IsFixedSize)
919 				throw new NotSupportedException ("Collection has a fixed size.");
920 
921 			int idx = list_is_ibinding ? - 1 : list.IndexOf (value);
922 			list.Remove (value);
923 
924 			if (idx != -1 && raise_list_changed_events)
925 				OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, idx));
926 		}
927 
RemoveAt(int index)928 		public virtual void RemoveAt (int index)
929 		{
930 			if (index < 0 || index > list.Count)
931 				throw new ArgumentOutOfRangeException ("index");
932 			if (list.IsReadOnly || list.IsFixedSize)
933 				throw new InvalidOperationException ();
934 
935 			list.RemoveAt (index);
936 			if (raise_list_changed_events && !list_is_ibinding)
937 				OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, index));
938 		}
939 
RemoveCurrent()940 		public void RemoveCurrent ()
941 		{
942 			if (Position < 0)
943 				throw new InvalidOperationException ("Cannot remove item because there is no current item.");
944 			if (!AllowRemove)
945 				throw new InvalidOperationException ("Cannot remove item because list does not allow removal of items.");
946 
947 			RemoveAt (Position);
948 		}
949 
RemoveFilter()950 		public virtual void RemoveFilter ()
951 		{
952 			Filter = null;
953 		}
954 
RemoveSort()955 		public virtual void RemoveSort ()
956 		{
957 			if (!list_is_ibinding)
958 				return;
959 
960 			sort = null;
961 			((IBindingList)list).RemoveSort ();
962 		}
963 
964 		[EditorBrowsable (EditorBrowsableState.Advanced)]
ResetAllowNew()965 		public virtual void ResetAllowNew ()
966 		{
967 			allow_new_set = false;
968 		}
969 
ResetBindings(bool metadataChanged)970 		public void ResetBindings (bool metadataChanged)
971 		{
972 			if (metadataChanged)
973 				OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged, null));
974 
975 			OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
976 		}
977 
ResetCurrentItem()978 		public void ResetCurrentItem ()
979 		{
980 			OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, Position, -1));
981 		}
982 
ResetItem(int itemIndex)983 		public void ResetItem (int itemIndex)
984 		{
985 			OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, itemIndex, -1));
986 		}
987 
ResumeBinding()988 		public void ResumeBinding ()
989 		{
990 			currency_manager.ResumeBinding ();
991 		}
992 
SuspendBinding()993 		public void SuspendBinding ()
994 		{
995 			currency_manager.SuspendBinding ();
996 		}
997 
998 		/* explicit interface implementations */
999 
ICancelAddNew.CancelNew(int position)1000 		void ICancelAddNew.CancelNew (int position)
1001 		{
1002 			if (!add_pending)
1003 				return;
1004 
1005 			if (position != pending_add_index)
1006 				return;
1007 
1008 			add_pending = false;
1009 			list.RemoveAt (position);
1010 
1011 			if (raise_list_changed_events && !list_is_ibinding)
1012 				OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, position));
1013 		}
1014 
ICancelAddNew.EndNew(int position)1015 		void ICancelAddNew.EndNew (int position)
1016 		{
1017 			if (!add_pending)
1018 				return;
1019 
1020 			if (position != pending_add_index)
1021 				return;
1022 
1023 			add_pending = false;
1024 		}
1025 
ISupportInitialize.BeginInit()1026 		void ISupportInitialize.BeginInit ()
1027 		{
1028 			is_initialized = false;
1029 		}
1030 
DataSourceEndInitHandler(object o, EventArgs args)1031 		void DataSourceEndInitHandler (object o, EventArgs args)
1032 		{
1033 			((ISupportInitializeNotification)datasource).Initialized -= DataSourceEndInitHandler;
1034 
1035 			ISupportInitializeNotification inotif = (ISupportInitializeNotification)this;
1036 			inotif.EndInit ();
1037 		}
1038 
ISupportInitialize.EndInit()1039 		void ISupportInitialize.EndInit ()
1040 		{
1041 			if (datasource != null && datasource is ISupportInitializeNotification) {
1042 				ISupportInitializeNotification inotif = (ISupportInitializeNotification)datasource;
1043 				if (!inotif.IsInitialized) {
1044 					inotif.Initialized += DataSourceEndInitHandler;
1045 					return;
1046 				}
1047 			}
1048 
1049 			is_initialized = true;
1050 			ResetList ();
1051 
1052 			EventHandler eh = (EventHandler) Events [InitializedEvent];
1053 			if (eh != null)
1054 				eh (this, EventArgs.Empty);
1055 		}
1056 
IBindingList.AddIndex(PropertyDescriptor property)1057 		void IBindingList.AddIndex (PropertyDescriptor property)
1058 		{
1059 			if (!(list is IBindingList))
1060 				throw new NotSupportedException();
1061 
1062 			((IBindingList)list).AddIndex (property);
1063 		}
1064 
IBindingList.RemoveIndex(PropertyDescriptor prop)1065 		void IBindingList.RemoveIndex (PropertyDescriptor prop)
1066 		{
1067 			if (!(list is IBindingList))
1068 				throw new NotSupportedException();
1069 
1070 			((IBindingList)list).RemoveIndex (prop);
1071 		}
1072 
1073 		bool ISupportInitializeNotification.IsInitialized {
1074 			get {
1075 				return is_initialized;
1076 			}
1077 		}
1078 
1079 		static object InitializedEvent = new object ();
1080 
1081 		event EventHandler ISupportInitializeNotification.Initialized {
1082 			add { Events.AddHandler (InitializedEvent, value); }
1083 			remove { Events.RemoveHandler (InitializedEvent, value); }
1084 		}
1085 	}
1086 }
1087