fe777c5c82
Former-commit-id: 6a76a29bd07d86e57c6c8da45c65ed5447d38a61
1087 lines
29 KiB
C#
1087 lines
29 KiB
C#
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
// Copyright (c) 2007 Novell, Inc.
|
|
//
|
|
|
|
using System.ComponentModel;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace System.Windows.Forms {
|
|
|
|
[ComplexBindingProperties ("DataSource", "DataMember")]
|
|
[DefaultEvent ("CurrentChanged")]
|
|
[DefaultProperty ("DataSource")]
|
|
[Designer("System.Windows.Forms.Design.BindingSourceDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
|
|
public class BindingSource : Component,
|
|
ICancelAddNew, IDisposable, ISupportInitialize,
|
|
IBindingListView, IBindingList, ITypedList,
|
|
IList, ISupportInitializeNotification, ICollection,
|
|
IComponent, ICurrencyManagerProvider, IEnumerable
|
|
{
|
|
bool is_initialized = true;
|
|
|
|
IList list;
|
|
CurrencyManager currency_manager;
|
|
Dictionary<string,CurrencyManager> related_currency_managers = new Dictionary<string,CurrencyManager> ();
|
|
//bool list_defaulted;
|
|
internal Type item_type;
|
|
bool item_has_default_ctor;
|
|
bool list_is_ibinding;
|
|
|
|
object datasource;
|
|
string datamember;
|
|
|
|
bool raise_list_changed_events;
|
|
|
|
bool allow_new_set;
|
|
bool allow_new;
|
|
|
|
bool add_pending;
|
|
int pending_add_index;
|
|
|
|
string filter;
|
|
string sort;
|
|
|
|
public BindingSource (IContainer container) : this ()
|
|
{
|
|
container.Add (this);
|
|
}
|
|
|
|
public BindingSource (object dataSource, string dataMember)
|
|
{
|
|
datasource = dataSource;
|
|
datamember = dataMember;
|
|
|
|
raise_list_changed_events = true;
|
|
|
|
ResetList ();
|
|
ConnectCurrencyManager ();
|
|
}
|
|
|
|
public BindingSource () : this (null, String.Empty)
|
|
{
|
|
}
|
|
|
|
IList GetListFromEnumerable (IEnumerable enumerable)
|
|
{
|
|
IList l = null;
|
|
|
|
IEnumerator e = enumerable.GetEnumerator();
|
|
|
|
if (enumerable is string) {
|
|
/* special case this.. seems to be the only one .net special cases? */
|
|
l = new BindingList<char> ();
|
|
}
|
|
else {
|
|
/* try to figure out the type based on
|
|
* the first element, if there is
|
|
* one */
|
|
object first = null;
|
|
if (e.MoveNext ()) {
|
|
first = e.Current;
|
|
}
|
|
|
|
if (first == null) {
|
|
return null;
|
|
}
|
|
else {
|
|
Type t = typeof (BindingList<>).MakeGenericType (new Type[] { first.GetType() });
|
|
l = (IList)Activator.CreateInstance (t);
|
|
}
|
|
}
|
|
|
|
e.Reset ();
|
|
while (e.MoveNext ()) {
|
|
l.Add (e.Current);
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
void ConnectCurrencyManager ()
|
|
{
|
|
currency_manager = new CurrencyManager (this);
|
|
|
|
currency_manager.PositionChanged += delegate (object o, EventArgs args) { OnPositionChanged (args); };
|
|
currency_manager.CurrentChanged += delegate (object o, EventArgs args) { OnCurrentChanged (args); };
|
|
currency_manager.BindingComplete += delegate (object o, BindingCompleteEventArgs args) { OnBindingComplete (args); };
|
|
currency_manager.DataError += delegate (object o, BindingManagerDataErrorEventArgs args) { OnDataError (args); };
|
|
currency_manager.CurrentChanged += delegate (object o, EventArgs args) { OnCurrentChanged (args); };
|
|
currency_manager.CurrentItemChanged += delegate (object o, EventArgs args) { OnCurrentItemChanged (args); };
|
|
}
|
|
|
|
void ResetList ()
|
|
{
|
|
if (!is_initialized)
|
|
return;
|
|
|
|
IList l;
|
|
object source = ListBindingHelper.GetList (datasource, datamember);
|
|
|
|
//
|
|
// If original source is null, then create a new object list
|
|
// Otherwise, try to infer the list item type
|
|
//
|
|
|
|
if (datasource == null) {
|
|
l = new BindingList<object>();
|
|
//list_defaulted = true;
|
|
} else if (source == null) {
|
|
//Infer type based on datasource and datamember,
|
|
// where datasource is an empty IEnumerable
|
|
// and need to find out the datamember type
|
|
|
|
Type property_type = ListBindingHelper.GetListItemProperties (datasource) [datamember].PropertyType;
|
|
Type t = typeof (BindingList<>).MakeGenericType (new Type [] { property_type } );
|
|
l = (IList)Activator.CreateInstance (t);
|
|
} else if (source is IList) {
|
|
l = (IList)source;
|
|
} else if (source is IEnumerable) {
|
|
IList new_list = GetListFromEnumerable ((IEnumerable)source);
|
|
l = new_list == null ? list : new_list;
|
|
} else if (source is Type) {
|
|
Type t = typeof (BindingList<>).MakeGenericType (new Type [] { (Type)source });
|
|
l = (IList)Activator.CreateInstance (t);
|
|
} else {
|
|
Type t = typeof (BindingList<>).MakeGenericType (new Type[] { source.GetType() });
|
|
l = (IList)Activator.CreateInstance (t);
|
|
l.Add (source);
|
|
}
|
|
|
|
SetList (l);
|
|
}
|
|
|
|
void SetList (IList l)
|
|
{
|
|
if (list is IBindingList)
|
|
((IBindingList) list).ListChanged -= IBindingListChangedHandler;
|
|
|
|
list = l;
|
|
item_type = ListBindingHelper.GetListItemType (list);
|
|
item_has_default_ctor = item_type.GetConstructor (Type.EmptyTypes) != null;
|
|
|
|
list_is_ibinding = list is IBindingList;
|
|
if (list_is_ibinding) {
|
|
((IBindingList) list).ListChanged += IBindingListChangedHandler;
|
|
|
|
if (list is IBindingListView)
|
|
((IBindingListView)list).Filter = filter;
|
|
}
|
|
|
|
ResetBindings (true);
|
|
}
|
|
|
|
private void ConnectDataSourceEvents (object dataSource)
|
|
{
|
|
if (dataSource == null)
|
|
return;
|
|
|
|
ICurrencyManagerProvider currencyManagerProvider = dataSource as ICurrencyManagerProvider;
|
|
if (currencyManagerProvider != null && currencyManagerProvider.CurrencyManager != null) {
|
|
currencyManagerProvider.CurrencyManager.CurrentItemChanged += OnParentCurrencyManagerChanged;
|
|
currencyManagerProvider.CurrencyManager.MetaDataChanged += OnParentCurrencyManagerChanged;
|
|
}
|
|
}
|
|
|
|
private void OnParentCurrencyManagerChanged (object sender, EventArgs args)
|
|
{
|
|
// Essentially handles chained data sources (e.g. chained BindingSource)
|
|
ResetDataMemberIfInvalid ();
|
|
ResetList ();
|
|
}
|
|
|
|
private void DisconnectDataSourceEvents (object dataSource)
|
|
{
|
|
if (dataSource == null)
|
|
return;
|
|
|
|
ICurrencyManagerProvider currencyManagerProvider = dataSource as ICurrencyManagerProvider;
|
|
if (currencyManagerProvider != null && currencyManagerProvider.CurrencyManager != null) {
|
|
currencyManagerProvider.CurrencyManager.CurrentItemChanged -= OnParentCurrencyManagerChanged;
|
|
currencyManagerProvider.CurrencyManager.MetaDataChanged -= OnParentCurrencyManagerChanged;
|
|
}
|
|
}
|
|
|
|
void IBindingListChangedHandler (object o, ListChangedEventArgs args)
|
|
{
|
|
if (raise_list_changed_events)
|
|
OnListChanged (args);
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool AllowEdit {
|
|
get {
|
|
if (list == null)
|
|
return false;
|
|
|
|
if (list.IsReadOnly)
|
|
return false;
|
|
|
|
if (list is IBindingList)
|
|
return ((IBindingList)list).AllowEdit;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public virtual bool AllowNew {
|
|
get {
|
|
if (allow_new_set)
|
|
return allow_new;
|
|
|
|
if (list is IBindingList)
|
|
return ((IBindingList)list).AllowNew;
|
|
|
|
if (list.IsFixedSize || list.IsReadOnly || !item_has_default_ctor)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
set {
|
|
if (value == allow_new && allow_new_set)
|
|
return;
|
|
|
|
if (value && (list.IsReadOnly || list.IsFixedSize))
|
|
throw new InvalidOperationException ();
|
|
|
|
allow_new_set = true;
|
|
allow_new = value;
|
|
|
|
if (raise_list_changed_events)
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
|
|
}
|
|
}
|
|
|
|
bool IsAddingNewHandled {
|
|
get {
|
|
return Events [AddingNewEvent] != null;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool AllowRemove {
|
|
get {
|
|
if (list == null)
|
|
return false;
|
|
|
|
if (list.IsFixedSize || list.IsReadOnly)
|
|
return false;
|
|
|
|
if (list is IBindingList)
|
|
return ((IBindingList)list).AllowRemove;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual int Count {
|
|
get {
|
|
return list.Count;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual CurrencyManager CurrencyManager {
|
|
get {
|
|
return currency_manager;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public object Current {
|
|
get {
|
|
if (currency_manager.Count > 0)
|
|
return currency_manager.Current;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
[DefaultValue ("")]
|
|
[Editor("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
|
|
[RefreshProperties (RefreshProperties.Repaint)]
|
|
public string DataMember {
|
|
get { return datamember; }
|
|
set {
|
|
/* we don't allow null DataMembers */
|
|
if (value == null)
|
|
value = String.Empty;
|
|
|
|
if (datamember != value) {
|
|
this.datamember = value;
|
|
|
|
ResetList ();
|
|
|
|
OnDataMemberChanged (EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
[AttributeProvider (typeof(IListSource))]
|
|
[RefreshProperties (RefreshProperties.Repaint)]
|
|
[DefaultValue (null)]
|
|
public object DataSource {
|
|
get { return datasource; }
|
|
set {
|
|
if (datasource != value) {
|
|
if (value == null)
|
|
datamember = String.Empty;
|
|
|
|
DisconnectDataSourceEvents (datasource);
|
|
datasource = value;
|
|
ResetDataMemberIfInvalid ();
|
|
ConnectDataSourceEvents (datasource);
|
|
ResetList ();
|
|
|
|
OnDataSourceChanged (EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
[DefaultValue (null)]
|
|
public virtual string Filter {
|
|
get {
|
|
return filter;
|
|
}
|
|
set {
|
|
if (SupportsFiltering)
|
|
((IBindingListView)list).Filter = value;
|
|
|
|
filter = value;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public bool IsBindingSuspended {
|
|
get { return currency_manager.IsBindingSuspended; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool IsFixedSize {
|
|
get { return list.IsFixedSize; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool IsReadOnly {
|
|
get { return list.IsReadOnly; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool IsSorted {
|
|
get { return (list is IBindingList) && ((IBindingList)list).IsSorted; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool IsSynchronized {
|
|
get {
|
|
return list.IsSynchronized;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual object this [int index] {
|
|
get { return list[index]; }
|
|
set
|
|
{
|
|
list[index] = value;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public IList List {
|
|
get { return list; }
|
|
}
|
|
|
|
[DefaultValue (-1)]
|
|
[Browsable (false)]
|
|
public int Position {
|
|
get {
|
|
return currency_manager.Position;
|
|
}
|
|
set {
|
|
if (value >= Count) value = Count - 1;
|
|
if (value < 0) value = 0;
|
|
|
|
currency_manager.Position = value;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
[DefaultValue (true)]
|
|
public bool RaiseListChangedEvents {
|
|
get { return raise_list_changed_events; }
|
|
set { raise_list_changed_events = value; }
|
|
}
|
|
|
|
[DefaultValue (null)]
|
|
public string Sort {
|
|
get {
|
|
return sort;
|
|
}
|
|
set {
|
|
if (value == null || value.Length == 0) {
|
|
if (list_is_ibinding && SupportsSorting)
|
|
RemoveSort ();
|
|
|
|
sort = value;
|
|
return;
|
|
}
|
|
|
|
if (!list_is_ibinding || !SupportsSorting)
|
|
throw new ArgumentException ("value");
|
|
|
|
ProcessSortString (value);
|
|
sort = value;
|
|
}
|
|
}
|
|
|
|
void ResetDataMemberIfInvalid ()
|
|
{
|
|
if (datamember == String.Empty)
|
|
return;
|
|
|
|
// if dataMember doesn't refer to a valid property of dataSource, we need to reset it
|
|
var property = ListBindingHelper.GetListItemProperties (datasource).Find (datamember, true);
|
|
if (property == null) {
|
|
datamember = String.Empty;
|
|
OnDataMemberChanged (EventArgs.Empty);
|
|
}
|
|
}
|
|
|
|
// NOTE: Probably the parsing can be improved
|
|
void ProcessSortString (string sort)
|
|
{
|
|
// Only keep simple whitespaces in the middle
|
|
sort = Regex.Replace (sort, "( )+", " ");
|
|
|
|
string [] properties = sort.Split (',');
|
|
PropertyDescriptorCollection prop_descs = GetItemProperties (null);
|
|
if (properties.Length == 1) {
|
|
ListSortDescription sort_desc = GetListSortDescription (prop_descs, properties [0]);
|
|
ApplySort (sort_desc.PropertyDescriptor, sort_desc.SortDirection);
|
|
} else {
|
|
if (!SupportsAdvancedSorting)
|
|
throw new ArgumentException ("value");
|
|
|
|
ListSortDescription [] sort_descs = new ListSortDescription [properties.Length];
|
|
for (int i = 0; i < properties.Length; i++)
|
|
sort_descs [i] = GetListSortDescription (prop_descs, properties [i]);
|
|
|
|
ApplySort (new ListSortDescriptionCollection (sort_descs));
|
|
}
|
|
|
|
}
|
|
|
|
ListSortDescription GetListSortDescription (PropertyDescriptorCollection prop_descs, string property)
|
|
{
|
|
property = property.Trim ();
|
|
string [] p = property.Split (new char [] {' '}, 2);
|
|
|
|
string prop_name = p [0];
|
|
PropertyDescriptor prop_desc = prop_descs [prop_name];
|
|
if (prop_desc == null)
|
|
throw new ArgumentException ("value");
|
|
|
|
ListSortDirection sort_direction = ListSortDirection.Ascending;
|
|
if (p.Length > 1) {
|
|
string dir_s = p [1];
|
|
if (String.Compare (dir_s, "ASC", true) == 0)
|
|
sort_direction = ListSortDirection.Ascending;
|
|
else if (String.Compare (dir_s, "DESC", true) == 0)
|
|
sort_direction = ListSortDirection.Descending;
|
|
else
|
|
throw new ArgumentException ("value");
|
|
}
|
|
|
|
return new ListSortDescription (prop_desc, sort_direction);
|
|
}
|
|
|
|
[Browsable (false)]
|
|
[EditorBrowsable (EditorBrowsableState.Never)]
|
|
public virtual ListSortDescriptionCollection SortDescriptions {
|
|
get {
|
|
if (list is IBindingListView)
|
|
return ((IBindingListView)list).SortDescriptions;
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
[EditorBrowsable (EditorBrowsableState.Never)]
|
|
public virtual ListSortDirection SortDirection {
|
|
get {
|
|
if (list is IBindingList)
|
|
return ((IBindingList)list).SortDirection;
|
|
|
|
return ListSortDirection.Ascending;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
[EditorBrowsable (EditorBrowsableState.Never)]
|
|
public virtual PropertyDescriptor SortProperty {
|
|
get {
|
|
if (list is IBindingList)
|
|
return ((IBindingList)list).SortProperty;
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool SupportsAdvancedSorting {
|
|
get { return (list is IBindingListView) && ((IBindingListView)list).SupportsAdvancedSorting; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool SupportsChangeNotification {
|
|
get { return true; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool SupportsFiltering {
|
|
get { return (list is IBindingListView) && ((IBindingListView)list).SupportsFiltering; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool SupportsSearching {
|
|
get {
|
|
return (list is IBindingList) && ((IBindingList)list).SupportsSearching;
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool SupportsSorting {
|
|
get { return (list is IBindingList) && ((IBindingList)list).SupportsSorting; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual object SyncRoot {
|
|
get {
|
|
return list.SyncRoot;
|
|
}
|
|
}
|
|
|
|
static object AddingNewEvent = new object ();
|
|
static object BindingCompleteEvent = new object ();
|
|
static object CurrentChangedEvent = new object ();
|
|
static object CurrentItemChangedEvent = new object ();
|
|
static object DataErrorEvent = new object ();
|
|
static object DataMemberChangedEvent = new object ();
|
|
static object DataSourceChangedEvent = new object ();
|
|
static object ListChangedEvent = new object ();
|
|
static object PositionChangedEvent= new object ();
|
|
|
|
public event AddingNewEventHandler AddingNew {
|
|
add { Events.AddHandler (AddingNewEvent, value); }
|
|
remove { Events.RemoveHandler (AddingNewEvent, value); }
|
|
}
|
|
|
|
public event BindingCompleteEventHandler BindingComplete {
|
|
add { Events.AddHandler (BindingCompleteEvent, value); }
|
|
remove { Events.RemoveHandler (BindingCompleteEvent, value); }
|
|
}
|
|
|
|
public event EventHandler CurrentChanged {
|
|
add { Events.AddHandler (CurrentChangedEvent, value); }
|
|
remove { Events.RemoveHandler (CurrentChangedEvent, value); }
|
|
}
|
|
|
|
public event EventHandler CurrentItemChanged {
|
|
add { Events.AddHandler (CurrentItemChangedEvent, value); }
|
|
remove { Events.RemoveHandler (CurrentItemChangedEvent, value); }
|
|
}
|
|
|
|
public event BindingManagerDataErrorEventHandler DataError {
|
|
add { Events.AddHandler (DataErrorEvent, value); }
|
|
remove { Events.RemoveHandler (DataErrorEvent, value); }
|
|
}
|
|
|
|
public event EventHandler DataMemberChanged {
|
|
add { Events.AddHandler (DataMemberChangedEvent, value); }
|
|
remove { Events.RemoveHandler (DataMemberChangedEvent, value); }
|
|
}
|
|
|
|
public event EventHandler DataSourceChanged {
|
|
add { Events.AddHandler (DataSourceChangedEvent, value); }
|
|
remove { Events.RemoveHandler (DataSourceChangedEvent, value); }
|
|
}
|
|
|
|
public event ListChangedEventHandler ListChanged {
|
|
add { Events.AddHandler (ListChangedEvent, value); }
|
|
remove { Events.RemoveHandler (ListChangedEvent, value); }
|
|
}
|
|
|
|
public event EventHandler PositionChanged {
|
|
add { Events.AddHandler (PositionChangedEvent, value); }
|
|
remove { Events.RemoveHandler (PositionChangedEvent, value); }
|
|
}
|
|
|
|
public virtual int Add (object value)
|
|
{
|
|
//
|
|
// First (re)create the BindingList<T> based on value
|
|
// if datasource is null and the current list is empty
|
|
//
|
|
if (datasource == null && list.Count == 0 && value != null) {
|
|
Type t = typeof (BindingList<>).MakeGenericType (new Type [] { value.GetType () } );
|
|
IList l = (IList) Activator.CreateInstance (t);
|
|
SetList (l);
|
|
}
|
|
|
|
if (value != null && !item_type.IsAssignableFrom (value.GetType ()))
|
|
throw new InvalidOperationException ("Objects added to the list must all be of the same type.");
|
|
if (list.IsReadOnly)
|
|
throw new NotSupportedException ("Collection is read-only.");
|
|
if (list.IsFixedSize)
|
|
throw new NotSupportedException ("Collection has a fixed size.");
|
|
|
|
int idx = list.Add (value);
|
|
if (raise_list_changed_events && !list_is_ibinding)
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, idx));
|
|
|
|
return idx;
|
|
}
|
|
|
|
public virtual object AddNew ()
|
|
{
|
|
if (!AllowEdit)
|
|
throw new InvalidOperationException ("Item cannot be added to a read-only or fixed-size list.");
|
|
if (!AllowNew)
|
|
throw new InvalidOperationException ("AddNew is set to false.");
|
|
|
|
EndEdit ();
|
|
|
|
AddingNewEventArgs args = new AddingNewEventArgs ();
|
|
OnAddingNew (args);
|
|
|
|
object new_object = args.NewObject;
|
|
if (new_object != null) {
|
|
if (!item_type.IsAssignableFrom (new_object.GetType ()))
|
|
throw new InvalidOperationException ("Objects added to the list must all be of the same type.");
|
|
} else if (list is IBindingList) {
|
|
object newObj = ((IBindingList)list).AddNew ();
|
|
add_pending = true;
|
|
pending_add_index = list.IndexOf (newObj);
|
|
return newObj;
|
|
} else if (!item_has_default_ctor)
|
|
throw new InvalidOperationException ("AddNew cannot be called on '" + item_type.Name +
|
|
", since it does not have a public default ctor. Set AllowNew to true " +
|
|
", handling AddingNew and creating the appropriate object.");
|
|
else // fallback to default .ctor
|
|
new_object = Activator.CreateInstance (item_type);
|
|
|
|
int idx = list.Add (new_object);
|
|
if (raise_list_changed_events && !list_is_ibinding)
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, idx));
|
|
|
|
add_pending = true;
|
|
pending_add_index = idx;
|
|
|
|
return new_object;
|
|
}
|
|
|
|
[EditorBrowsable (EditorBrowsableState.Never)]
|
|
public virtual void ApplySort (PropertyDescriptor property, ListSortDirection sort)
|
|
{
|
|
if (!list_is_ibinding)
|
|
throw new NotSupportedException ("This operation requires an IBindingList.");
|
|
|
|
IBindingList iblist = (IBindingList)list;
|
|
iblist.ApplySort (property, sort);
|
|
}
|
|
|
|
[EditorBrowsable (EditorBrowsableState.Never)]
|
|
public virtual void ApplySort (ListSortDescriptionCollection sorts)
|
|
{
|
|
if (!(list is IBindingListView))
|
|
throw new NotSupportedException ("This operation requires an IBindingListView.");
|
|
|
|
IBindingListView iblist_view = (IBindingListView)list;
|
|
iblist_view.ApplySort (sorts);
|
|
}
|
|
|
|
public void CancelEdit ()
|
|
{
|
|
currency_manager.CancelCurrentEdit ();
|
|
}
|
|
|
|
public virtual void Clear ()
|
|
{
|
|
if (list.IsReadOnly)
|
|
throw new NotSupportedException ("Collection is read-only.");
|
|
|
|
list.Clear ();
|
|
if (raise_list_changed_events && !list_is_ibinding)
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
|
|
}
|
|
|
|
public virtual bool Contains (object value)
|
|
{
|
|
return list.Contains (value);
|
|
}
|
|
|
|
public virtual void CopyTo (Array arr, int index)
|
|
{
|
|
list.CopyTo (arr, index);
|
|
}
|
|
|
|
protected override void Dispose (bool disposing)
|
|
{
|
|
base.Dispose (disposing);
|
|
}
|
|
|
|
public void EndEdit ()
|
|
{
|
|
currency_manager.EndCurrentEdit ();
|
|
}
|
|
|
|
public int Find (string propertyName, object key)
|
|
{
|
|
PropertyDescriptor property = GetItemProperties (null).Find (propertyName, true);
|
|
if (property == null)
|
|
throw new ArgumentException ("propertyName");
|
|
|
|
return Find (property, key);
|
|
}
|
|
|
|
public virtual int Find (PropertyDescriptor prop, object key)
|
|
{
|
|
if (!list_is_ibinding)
|
|
throw new NotSupportedException ();
|
|
|
|
return ((IBindingList)list).Find (prop, key);
|
|
}
|
|
|
|
public virtual IEnumerator GetEnumerator ()
|
|
{
|
|
return this.List.GetEnumerator ();
|
|
}
|
|
|
|
public virtual PropertyDescriptorCollection GetItemProperties (PropertyDescriptor[] listAccessors)
|
|
{
|
|
return ListBindingHelper.GetListItemProperties (list, listAccessors);
|
|
}
|
|
|
|
public virtual string GetListName (PropertyDescriptor[] listAccessors)
|
|
{
|
|
return ListBindingHelper.GetListName (list, listAccessors);
|
|
}
|
|
|
|
public virtual CurrencyManager GetRelatedCurrencyManager (string dataMember)
|
|
{
|
|
if (dataMember == null || dataMember.Length == 0)
|
|
return currency_manager;
|
|
|
|
if (related_currency_managers.ContainsKey (dataMember))
|
|
return related_currency_managers [dataMember];
|
|
|
|
// FIXME - Why passing invalid dataMembers containing a . return
|
|
// a null value?
|
|
if (dataMember.IndexOf ('.') != -1)
|
|
return null;
|
|
|
|
BindingSource source = new BindingSource (this, dataMember);
|
|
related_currency_managers [dataMember] = source.CurrencyManager;
|
|
|
|
return source.CurrencyManager;
|
|
}
|
|
|
|
public virtual int IndexOf (object value)
|
|
{
|
|
return list.IndexOf (value);
|
|
}
|
|
|
|
public virtual void Insert (int index, object value)
|
|
{
|
|
if (index < 0 || index > list.Count)
|
|
throw new ArgumentOutOfRangeException ("index");
|
|
if (list.IsReadOnly || list.IsFixedSize)
|
|
throw new NotSupportedException ();
|
|
if (!item_type.IsAssignableFrom (value.GetType ()))
|
|
throw new ArgumentException ("value");
|
|
|
|
list.Insert (index, value);
|
|
if (raise_list_changed_events && !list_is_ibinding)
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, index));
|
|
}
|
|
|
|
public void MoveFirst ()
|
|
{
|
|
Position = 0;
|
|
}
|
|
|
|
public void MoveLast ()
|
|
{
|
|
Position = Count - 1;
|
|
}
|
|
|
|
public void MoveNext ()
|
|
{
|
|
Position ++;
|
|
}
|
|
|
|
public void MovePrevious ()
|
|
{
|
|
Position --;
|
|
}
|
|
|
|
protected virtual void OnAddingNew (AddingNewEventArgs e)
|
|
{
|
|
AddingNewEventHandler eh = (AddingNewEventHandler)Events[AddingNewEvent];
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected virtual void OnBindingComplete (BindingCompleteEventArgs e)
|
|
{
|
|
BindingCompleteEventHandler eh = (BindingCompleteEventHandler) Events[BindingCompleteEvent];
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected virtual void OnCurrentChanged (EventArgs e)
|
|
{
|
|
EventHandler eh = (EventHandler) Events[CurrentChangedEvent];
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected virtual void OnCurrentItemChanged (EventArgs e)
|
|
{
|
|
EventHandler eh = (EventHandler) Events[CurrentItemChangedEvent];
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected virtual void OnDataError (BindingManagerDataErrorEventArgs e)
|
|
{
|
|
BindingManagerDataErrorEventHandler eh = (BindingManagerDataErrorEventHandler) Events[DataErrorEvent];
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected virtual void OnDataMemberChanged (EventArgs e)
|
|
{
|
|
EventHandler eh = (EventHandler) Events[DataMemberChangedEvent];
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected virtual void OnDataSourceChanged (EventArgs e)
|
|
{
|
|
EventHandler eh = (EventHandler) Events[DataSourceChangedEvent];
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected virtual void OnListChanged (ListChangedEventArgs e)
|
|
{
|
|
ListChangedEventHandler eh = (ListChangedEventHandler) Events[ListChangedEvent];
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected virtual void OnPositionChanged (EventArgs e)
|
|
{
|
|
EventHandler eh = (EventHandler) Events[PositionChangedEvent];
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
public virtual void Remove (object value)
|
|
{
|
|
if (list.IsReadOnly)
|
|
throw new NotSupportedException ("Collection is read-only.");
|
|
if (list.IsFixedSize)
|
|
throw new NotSupportedException ("Collection has a fixed size.");
|
|
|
|
int idx = list_is_ibinding ? - 1 : list.IndexOf (value);
|
|
list.Remove (value);
|
|
|
|
if (idx != -1 && raise_list_changed_events)
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, idx));
|
|
}
|
|
|
|
public virtual void RemoveAt (int index)
|
|
{
|
|
if (index < 0 || index > list.Count)
|
|
throw new ArgumentOutOfRangeException ("index");
|
|
if (list.IsReadOnly || list.IsFixedSize)
|
|
throw new InvalidOperationException ();
|
|
|
|
list.RemoveAt (index);
|
|
if (raise_list_changed_events && !list_is_ibinding)
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, index));
|
|
}
|
|
|
|
public void RemoveCurrent ()
|
|
{
|
|
if (Position < 0)
|
|
throw new InvalidOperationException ("Cannot remove item because there is no current item.");
|
|
if (!AllowRemove)
|
|
throw new InvalidOperationException ("Cannot remove item because list does not allow removal of items.");
|
|
|
|
RemoveAt (Position);
|
|
}
|
|
|
|
public virtual void RemoveFilter ()
|
|
{
|
|
Filter = null;
|
|
}
|
|
|
|
public virtual void RemoveSort ()
|
|
{
|
|
if (!list_is_ibinding)
|
|
return;
|
|
|
|
sort = null;
|
|
((IBindingList)list).RemoveSort ();
|
|
}
|
|
|
|
[EditorBrowsable (EditorBrowsableState.Advanced)]
|
|
public virtual void ResetAllowNew ()
|
|
{
|
|
allow_new_set = false;
|
|
}
|
|
|
|
public void ResetBindings (bool metadataChanged)
|
|
{
|
|
if (metadataChanged)
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged, null));
|
|
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
|
|
}
|
|
|
|
public void ResetCurrentItem ()
|
|
{
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, Position, -1));
|
|
}
|
|
|
|
public void ResetItem (int itemIndex)
|
|
{
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, itemIndex, -1));
|
|
}
|
|
|
|
public void ResumeBinding ()
|
|
{
|
|
currency_manager.ResumeBinding ();
|
|
}
|
|
|
|
public void SuspendBinding ()
|
|
{
|
|
currency_manager.SuspendBinding ();
|
|
}
|
|
|
|
/* explicit interface implementations */
|
|
|
|
void ICancelAddNew.CancelNew (int position)
|
|
{
|
|
if (!add_pending)
|
|
return;
|
|
|
|
if (position != pending_add_index)
|
|
return;
|
|
|
|
add_pending = false;
|
|
list.RemoveAt (position);
|
|
|
|
if (raise_list_changed_events && !list_is_ibinding)
|
|
OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, position));
|
|
}
|
|
|
|
void ICancelAddNew.EndNew (int position)
|
|
{
|
|
if (!add_pending)
|
|
return;
|
|
|
|
if (position != pending_add_index)
|
|
return;
|
|
|
|
add_pending = false;
|
|
}
|
|
|
|
void ISupportInitialize.BeginInit ()
|
|
{
|
|
is_initialized = false;
|
|
}
|
|
|
|
void DataSourceEndInitHandler (object o, EventArgs args)
|
|
{
|
|
((ISupportInitializeNotification)datasource).Initialized -= DataSourceEndInitHandler;
|
|
|
|
ISupportInitializeNotification inotif = (ISupportInitializeNotification)this;
|
|
inotif.EndInit ();
|
|
}
|
|
|
|
void ISupportInitialize.EndInit ()
|
|
{
|
|
if (datasource != null && datasource is ISupportInitializeNotification) {
|
|
ISupportInitializeNotification inotif = (ISupportInitializeNotification)datasource;
|
|
if (!inotif.IsInitialized) {
|
|
inotif.Initialized += DataSourceEndInitHandler;
|
|
return;
|
|
}
|
|
}
|
|
|
|
is_initialized = true;
|
|
ResetList ();
|
|
|
|
EventHandler eh = (EventHandler) Events [InitializedEvent];
|
|
if (eh != null)
|
|
eh (this, EventArgs.Empty);
|
|
}
|
|
|
|
void IBindingList.AddIndex (PropertyDescriptor property)
|
|
{
|
|
if (!(list is IBindingList))
|
|
throw new NotSupportedException();
|
|
|
|
((IBindingList)list).AddIndex (property);
|
|
}
|
|
|
|
void IBindingList.RemoveIndex (PropertyDescriptor prop)
|
|
{
|
|
if (!(list is IBindingList))
|
|
throw new NotSupportedException();
|
|
|
|
((IBindingList)list).RemoveIndex (prop);
|
|
}
|
|
|
|
bool ISupportInitializeNotification.IsInitialized {
|
|
get {
|
|
return is_initialized;
|
|
}
|
|
}
|
|
|
|
static object InitializedEvent = new object ();
|
|
|
|
event EventHandler ISupportInitializeNotification.Initialized {
|
|
add { Events.AddHandler (InitializedEvent, value); }
|
|
remove { Events.RemoveHandler (InitializedEvent, value); }
|
|
}
|
|
}
|
|
}
|