* Application.cs: fix compilation errors when debug is enabled.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / Binding.cs
index a255cc719602278646bc8ad55d8976bd458f5606..7fe7b29b1e89c9b9f6f71ebda8ceb1939cce8e15 100644 (file)
 //
 // Authors:
 //     Peter Bartok    pbartok@novell.com
+//     Jackson Harper  jackson@ximian.com
 //
 
 
-// COMPLETE
-
 using System.ComponentModel;
 
 namespace System.Windows.Forms {
-       [TypeConverter(typeof(ListBindingConverter))]
+
+       [TypeConverter (typeof (ListBindingConverter))]
        public class Binding {
-               internal string                 property_name;
-               internal object                 data_source;
-               internal BindingManagerBase     binding_manager_base;
-               internal BindingMemberInfo      binding_member_info;
-               internal Control                control;
-               internal bool                   is_binding;
+
+               private string property_name;
+               private object data_source;
+               private string data_member;
+
+               private BindingMemberInfo binding_member_info;
+               private Control control;
+
+               private BindingManagerBase manager;
+               private PropertyDescriptor control_property;
+               private PropertyDescriptor is_null_desc;
+
+               private object data;
+               private Type data_type;
 
                #region Public Constructors
-               public Binding(string propertyName, object dataSource, string dataMember) {
-                       this.property_name=propertyName;
-                       this.data_source=dataSource;
-                       this.binding_member_info=new BindingMemberInfo(dataMember);
+               public Binding (string propertyName, object dataSource, string dataMember)
+               {
+                       property_name = propertyName;
+                       data_source = dataSource;
+                       data_member = dataMember;
+                       binding_member_info = new BindingMemberInfo (dataMember);
                }
                #endregion      // Public Constructors
 
                #region Public Instance Properties
                public BindingManagerBase BindingManagerBase {
                        get {
-                               return this.binding_manager_base;
+                               return manager;
                        }
                }
 
                public BindingMemberInfo BindingMemberInfo {
                        get {
-                               return this.binding_member_info;
+                               return binding_member_info;
                        }
                }
 
-               [DefaultValue("")]
+               [DefaultValue (null)]
                public Control Control {
                        get {
-                               return this.control;
+                               return control;
                        }
                }
 
                public object DataSource {
                        get {
-                               return this.data_source;
+                               return data_source;
                        }
                }
 
                public bool IsBinding {
                        get {
-                               return this.is_binding;
+                               if (control == null || !control.Created)
+                                       return false;
+                               if (manager == null || manager.IsSuspended)
+                                       return false;
+                               return true;
                        }
                }
 
-               [DefaultValue("")]
+               [DefaultValue ("")]
                public string PropertyName {
                        get {
-                               return this.property_name;
+                               return property_name;
                        }
                }
                #endregion      // Public Instance Properties
 
                #region Protected Instance Methods
-               protected virtual void OnFormat(ConvertEventArgs cevent) {
-                       if (Format!=null) Format(this, cevent);
+               protected virtual void OnFormat (ConvertEventArgs cevent)
+               {
+                       if (Format!=null)
+                               Format (this, cevent);
                }
 
-               protected virtual void OnParse(ConvertEventArgs cevent) {
-                       if (Parse!=null) Parse(this, cevent);
+               protected virtual void OnParse (ConvertEventArgs cevent)
+               {
+                       if (Parse!=null)
+                               Parse (this, cevent);
                }
                #endregion      // Protected Instance Methods
 
+               
+               internal void SetControl (Control control)
+               {
+                       if (control == this.control)
+                               return;
+
+                       control_property = TypeDescriptor.GetProperties (control).Find (property_name, true);                   
+
+                       if (control_property == null)
+                               throw new ArgumentException (String.Concat ("Cannot bind to property '", property_name, "' on target control."));
+                       if (control_property.IsReadOnly)
+                               throw new ArgumentException (String.Concat ("Cannot bind to property '", property_name, "' because it is read only."));
+                               
+                       data_type = control_property.PropertyType; // Getting the PropertyType is kinda slow and it should never change, so it is cached
+                       control.Validating += new CancelEventHandler (ControlValidatingHandler);
+
+                       this.control = control;
+               }
+
+               internal void Check (BindingContext binding_context)
+               {
+                       if (control == null || control.BindingContext == null)
+                               return;
+
+                       manager = control.BindingContext [data_source, data_member];
+
+                       manager.AddBinding (this);
+                       manager.PositionChanged += new EventHandler (PositionChangedHandler);
+                       manager.CurrentChanged += new EventHandler (CurrentChangedHandler);
+
+                       is_null_desc = TypeDescriptor.GetProperties (manager.Current).Find (property_name + "IsNull", false);
+
+                       PushData ();
+               }
+
+               internal void PullData ()
+               {
+                       if (IsBinding == false || manager.Current == null)
+                               return;
+
+                       data = control_property.GetValue (control);
+                       SetPropertyValue (data);
+               }
+
+               internal void PushData ()
+               {
+                       if (manager == null || manager.IsSuspended || manager.Current == null)
+                               return;
+
+                       if (is_null_desc != null) {
+                               bool is_null = (bool) is_null_desc.GetValue (manager.Current);
+                               if (is_null) {
+                                       data = Convert.DBNull;
+                                       return;
+                               }
+                       }
+
+                       PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true);
+                       if (pd == null) {
+                               data = ParseData (manager.Current, manager.Current.GetType ());
+                       } else {
+                               data = ParseData (pd.GetValue (manager.Current), pd.PropertyType);
+                       }
+
+                       data = FormatData (data);
+                       SetControlValue (data);
+               }
+
+               internal void UpdateIsBinding ()
+               {
+                       PushData ();
+               }
+
+               private void SetControlValue (object data)
+               {
+                       control_property.SetValue (control, data);
+               }
+
+               private void SetPropertyValue (object data)
+               {
+                       PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true);
+                       if (pd.IsReadOnly)
+                               return;
+                       data = ParseData (data, pd.PropertyType);
+                       pd.SetValue (manager.Current, data);
+               }
+
+               private void CurrentChangedHandler (object sender, EventArgs e)
+               {
+                       PushData ();
+               }
+
+               private void ControlValidatingHandler (object sender, CancelEventArgs e)
+               {
+                       object old_data = data;
+
+                       // If the data doesn't seem to be valid (it can't be converted,
+                       // is the wrong type, etc, we reset to the old data value.
+                       try {
+                               PullData ();
+                       } catch {
+                               data = old_data;
+                               SetControlValue (data);
+                       }
+               }
+
+               private void PositionChangedHandler (object sender, EventArgs e)
+               {
+                       PushData ();
+               }
+
+               private object ParseData (object data, Type data_type)
+               {
+                       ConvertEventArgs e = new ConvertEventArgs (data, data_type);
+
+                       OnParse (e);
+                       if (data_type.IsInstanceOfType (e.Value))
+                               return e.Value;
+                       if (e.Value == Convert.DBNull)
+                               return e.Value;
+
+                       return ConvertData (e.Value, data_type);
+               }
+
+               private object FormatData (object data)
+               {
+                       if (data_type == typeof (object)) 
+                               return data;
+
+                       ConvertEventArgs e = new ConvertEventArgs (data, data_type);
+
+                       OnFormat (e);
+                       if (data_type.IsInstanceOfType (e.Value))
+                               return e.Value;
+
+                       return ConvertData (data, data_type);
+               }
+
+               private object ConvertData (object data, Type data_type)
+               {
+                       TypeConverter converter = TypeDescriptor.GetConverter (data.GetType ());
+                       if (converter != null && converter.CanConvertTo (data_type))
+                               return converter.ConvertTo (data, data_type);
+
+                       if (data is IConvertible) {
+                               object res = Convert.ChangeType (data, data_type);
+                               if (data_type.IsInstanceOfType (res))
+                                       return res;
+                       }
+
+                       return null;
+               }
+
                #region Events
                public event ConvertEventHandler Format;
                public event ConvertEventHandler Parse;