// Jackson Harper jackson@ximian.com
+using System.Data;
using System.Collections;
using System.Globalization;
using System.ComponentModel;
public class BindingContext : ICollection, IEnumerable {
private Hashtable managers;
+ private EventHandler onCollectionChangedHandler;
- private class ManagerEntry {
+ private class HashKey {
+ public object source;
+ public string member;
- private object source;
- private string member;
-
- private int member_hash;
-
- public ManagerEntry (object source, string member)
+ public HashKey (object source, string member)
{
this.source = source;
- if (member == null)
- member = String.Empty;
- this.member = member.ToLower (CultureInfo.InvariantCulture);
-
-
- member_hash = this.member.GetHashCode ();
- if (member_hash == 0)
- member_hash = 1;
- }
-
- public override bool Equals (object b)
- {
- ManagerEntry o = (ManagerEntry) b;
-
- return (o.source == source && o.member_hash == member_hash);
+ this.member = member;
}
public override int GetHashCode ()
{
- return member_hash * source.GetHashCode ();
+ return source.GetHashCode() ^ member.GetHashCode ();
}
- public override string ToString ()
+ public override bool Equals (object o)
{
- return source.ToString () + " + " + member.ToString ();
+ HashKey hk = o as HashKey;
+ if (hk == null)
+ return false;
+ return hk.source == source && hk.member == member;
}
}
}
public bool IsReadOnly {
- get {
- return false;
- }
+ get { return false; }
}
public BindingManagerBase this [object dataSource] {
- get {
- return this [dataSource, String.Empty];
- }
+ get { return this [dataSource, String.Empty]; }
}
public BindingManagerBase this [object data_source, string data_member] {
get {
- ManagerEntry e = CreateEntry (data_source, data_member);
- BindingManagerBase res = managers [e] as BindingManagerBase;
+ if (data_source == null)
+ throw new ArgumentNullException ("data_source");
+ if (data_member == null)
+ data_member = String.Empty;
+
+ HashKey key = new HashKey (data_source, data_member);
+ BindingManagerBase res = managers [key] as BindingManagerBase;
if (res != null)
return res;
- res = AddManager (data_source, data_member);
+
+ res = CreateBindingManager (data_source, data_member);
+ if (res == null)
+ return null;
+ managers [key] = res;
return res;
}
}
- private BindingManagerBase AddManager (object data_source, string data_member)
+ private BindingManagerBase CreateBindingManager (object data_source, string data_member)
{
- BindingManagerBase res = CreateBindingManager (data_source, data_member);
- managers.Add (CreateEntry (data_source, data_member), res);
- managers.Add (CreateEntry (data_source, String.Empty), res);
+ if (data_member == "") {
+ if (IsListType (data_source.GetType ()))
+ return new CurrencyManager (data_source);
+ else
+ return new PropertyManager (data_source);
+ }
+ else {
+ BindingMemberInfo info = new BindingMemberInfo (data_member);
- return res;
- }
+ BindingManagerBase parent_manager = this[data_source, info.BindingPath];
- private BindingManagerBase CreateBindingManager (object data_source,
- string data_member)
- {
- if (data_source is IList ||
- data_source is IListSource ||
- data_source is IBindingList) {
- CurrencyManager res = new CurrencyManager (data_source);
- return res;
+ PropertyDescriptor pd = parent_manager == null ? null : parent_manager.GetItemProperties ().Find (info.BindingField, true);
+
+ if (pd == null)
+ throw new ArgumentException (String.Format ("Cannot create a child list for field {0}.", info.BindingField));
+
+ if (IsListType (pd.PropertyType))
+ return new RelatedCurrencyManager (parent_manager, pd);
+ else
+ return new RelatedPropertyManager (parent_manager, info.BindingField);
}
+ }
- return new PropertyManager (data_source, data_member);
+ bool IsListType (Type t)
+ {
+ return (typeof (IList).IsAssignableFrom (t)
+ || typeof (IListSource).IsAssignableFrom (t));
}
#region Public Instance Methods
public bool Contains (object dataSource, string dataMember)
{
- ManagerEntry entry = CreateEntry (dataSource, dataMember);
+ if (dataSource == null)
+ throw new ArgumentNullException ("dataSource");
+ if (dataMember == null)
+ dataMember = String.Empty;
- return managers.ContainsKey (entry);
+ HashKey key = new HashKey (dataSource, dataMember);
+ return managers [key] != null;
}
#endregion // Public Instance Methods
throw new ArgumentNullException ("dataSource");
if (listManager == null)
throw new ArgumentNullException ("listManager");
- managers.Add (CreateEntry (dataSource, String.Empty), listManager);
+
+ HashKey key = new HashKey (dataSource, String.Empty);
+ managers [key] = listManager;
}
protected internal void Clear ()
managers.Clear ();
}
- protected virtual void OnCollectionChanged(System.ComponentModel.CollectionChangeEventArgs ccevent)
+ protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent)
{
- if (CollectionChanged != null) {
- CollectionChanged (this, ccevent);
+ if (onCollectionChangedHandler != null) {
+ onCollectionChangedHandler (this, ccevent);
}
}
protected internal void Remove (object dataSource)
{
+ if (dataSource == null)
+ throw new ArgumentNullException ("dataSource");
+
RemoveCore (dataSource);
OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataSource));
}
protected virtual void RemoveCore (object dataSource)
{
- managers.Remove (CreateEntry (dataSource, String.Empty));
+ HashKey[] keys = new HashKey [managers.Keys.Count];
+ managers.Keys.CopyTo (keys, 0);
+
+ for (int i = 0; i < keys.Length; i ++) {
+ if (keys[i].source == dataSource)
+ managers.Remove (keys[i]);
+ }
}
#endregion // Protected Instance Methods
#region Events
- public event CollectionChangeEventHandler CollectionChanged;
+#if NET_2_0
+ [Browsable (false)]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+#endif
+ public event CollectionChangeEventHandler CollectionChanged {
+ add { throw new NotImplementedException (); }
+ remove { /* nothing to do here.. */ }
+ }
#endregion // Events
#region ICollection Interfaces
}
int ICollection.Count {
- get {
- return managers.Count;
- }
+ get { return managers.Count; }
}
bool ICollection.IsSynchronized {
- get {
- return false;
- }
+ get { return false; }
}
object ICollection.SyncRoot {
- get {
- return null;
- }
+ get { return null; }
}
#endregion // ICollection Interfaces
#region IEnumerable Interfaces
- [MonoTODO]
+ [MonoTODO ("our enumerator is slightly different. in MS's implementation the Values are WeakReferences to the managers.")]
IEnumerator IEnumerable.GetEnumerator() {
- throw new NotImplementedException();
+ return managers.GetEnumerator ();
}
#endregion // IEnumerable Interfaces
-
- private ManagerEntry CreateEntry (object dataSource, string dataMember)
- {
- return new ManagerEntry (dataSource, dataMember);
- }
}
}