private object data_source;
private string data_member;
+ private bool is_binding;
+ private bool checked_isnull;
+
private BindingMemberInfo binding_member_info;
private Control control;
private PropertyDescriptor control_property;
private PropertyDescriptor is_null_desc;
- private EventDescriptor changed_event;
- private EventHandler property_value_changed_handler;
- private object event_current; // The manager.Current as far as the changed_event knows
-
private object data;
private Type data_type;
+#if NET_2_0
+ private DataSourceUpdateMode datasource_update_mode;
+ private ControlUpdateMode control_update_mode;
+ private object datasource_null_value;
+ private object null_value;
+ private IFormatProvider format_info;
+ private string format_string;
+ private bool formatting_enabled;
+#endif
#region Public Constructors
- public Binding (string propertyName, object dataSource, string dataMember)
+#if NET_2_0
+ public Binding (string propertyName, object dataSource, string dataMember)
+ : this (propertyName, dataSource, dataMember, false, DataSourceUpdateMode.OnValidation, null, string.Empty, null)
+ {
+ }
+
+ public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled)
+ : this (propertyName, dataSource, dataMember, formattingEnabled, DataSourceUpdateMode.OnValidation, null, string.Empty, null)
+ {
+ }
+
+ public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode)
+ : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, null, string.Empty, null)
+ {
+ }
+
+ public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue)
+ : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, string.Empty, null)
+ {
+ }
+
+ public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString)
+ : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, formatString, null)
+ {
+ }
+
+ public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString, IFormatProvider formatInfo)
{
property_name = propertyName;
data_source = dataSource;
data_member = dataMember;
binding_member_info = new BindingMemberInfo (dataMember);
+ datasource_update_mode = dataSourceUpdateMode;
+ null_value = nullValue;
+ format_string = formatString;
+ format_info = formatInfo;
+
+ EventDescriptor prop_changed_event = GetPropertyChangedEvent (data_source, binding_member_info.BindingField);
+ if (prop_changed_event != null)
+ prop_changed_event.AddEventHandler (data_source, new EventHandler (SourcePropertyChangedHandler));
}
+#else
+ public Binding (string propertyName, object dataSource, string dataMember)
+ {
+ property_name = propertyName;
+ data_source = dataSource;
+ data_member = dataMember;
+ binding_member_info = new BindingMemberInfo (dataMember);
+
+ EventDescriptor prop_changed_event = GetPropertyChangedEvent (data_source, binding_member_info.BindingField);
+ if (prop_changed_event != null)
+ prop_changed_event.AddEventHandler (data_source, new EventHandler (SourcePropertyChangedHandler));
+ }
+#endif
#endregion // Public Constructors
#region Public Instance Properties
+#if NET_2_0
+ public IBindableComponent BindableComponent {
+ get {
+ return control;
+ }
+ }
+#endif
public BindingManagerBase BindingManagerBase {
get {
return manager;
}
}
+#if NET_2_0
+ [DefaultValue (ControlUpdateMode.OnPropertyChanged)]
+ public ControlUpdateMode ControlUpdateMode {
+ get {
+ return control_update_mode;
+ }
+ set {
+ control_update_mode = value;
+ }
+ }
+#endif
+
public object DataSource {
get {
return data_source;
}
}
+#if NET_2_0
+ [DefaultValue (DataSourceUpdateMode.OnValidation)]
+ public DataSourceUpdateMode DataSourceUpdateMode {
+ get {
+ return datasource_update_mode;
+ }
+ set {
+ datasource_update_mode = value;
+ }
+ }
+
+ [DefaultValue (null)]
+ public object DataSourceNullValue {
+ get {
+ return datasource_null_value;
+ }
+ set {
+ datasource_null_value = value;
+ }
+ }
+
+ [DefaultValue (false)]
+ public bool FormattingEnabled {
+ get {
+ return formatting_enabled;
+ }
+ set {
+ if (formatting_enabled == value)
+ return;
+
+ formatting_enabled = value;
+ PushData ();
+ }
+ }
+
+ [DefaultValue (null)]
+ public IFormatProvider FormatInfo {
+ get {
+ return format_info;
+ }
+ set {
+ if (value == format_info)
+ return;
+
+ format_info = value;
+ if (formatting_enabled)
+ PushData ();
+ }
+ }
+
+ [DefaultValue ("")]
+ public string FormatString {
+ get {
+ return format_string;
+ }
+ set {
+ if (value == null)
+ value = String.Empty;
+ if (value == format_string)
+ return;
+
+ format_string = value;
+ if (formatting_enabled)
+ PushData ();
+ }
+ }
+#endif
+
public bool IsBinding {
get {
- if (control == null || !control.Created)
- return false;
- if (manager == null || manager.IsSuspended)
- return false;
- return true;
+ return is_binding;
+ }
+ }
+
+#if NET_2_0
+ [DefaultValue (null)]
+ public object NullValue {
+ get {
+ return null_value;
+ }
+ set {
+ if (value == null_value)
+ return;
+
+ null_value = value;
+ if (formatting_enabled)
+ PushData ();
}
}
+#endif
[DefaultValue ("")]
public string PropertyName {
}
#endregion // Public Instance Properties
+#if NET_2_0
+ public void ReadValue ()
+ {
+ PushData (true);
+ }
+
+ public void WriteValue ()
+ {
+ PullData (true);
+ }
+#endif
+
#region Protected Instance Methods
+#if NET_2_0
+ protected virtual void OnBindingComplete (BindingCompleteEventArgs args)
+ {
+ if (BindingComplete != null)
+ BindingComplete (this, args);
+ }
+#endif
+
protected virtual void OnFormat (ConvertEventArgs cevent)
{
if (Format!=null)
}
#endregion // Protected Instance Methods
+ internal string DataMember {
+ get { return data_member; }
+ }
internal void SetControl (Control control)
{
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);
+#if NET_2_0
+ EventDescriptor prop_changed_event = GetPropertyChangedEvent (control, property_name);
+ if (prop_changed_event != null)
+ prop_changed_event.AddEventHandler (control, new EventHandler (ControlPropertyChangedHandler));
+#endif
this.control = control;
- control.DataBindings.Add (this);
}
- internal void Check (BindingContext binding_context)
+ internal void Check ()
{
if (control == null || control.BindingContext == null)
return;
- manager = control.BindingContext [data_source, data_member];
+ if (manager == null) {
+ manager = control.BindingContext [data_source];
+ manager.AddBinding (this);
+ manager.PositionChanged += new EventHandler (PositionChangedHandler);
+ }
- manager.AddBinding (this);
- manager.PositionChanged += new EventHandler (PositionChangedHandler);
- manager.CurrentChanged += new EventHandler (CurrentChangedHandler);
+ if (manager.Position == -1)
+ return;
- is_null_desc = TypeDescriptor.GetProperties (manager.Current).Find (property_name + "IsNull", false);
+ if (!checked_isnull) {
+ is_null_desc = TypeDescriptor.GetProperties (manager.Current).Find (property_name + "IsNull", false);
+ checked_isnull = true;
+ }
PushData ();
}
- internal void PullData ()
+ internal bool PullData ()
+ {
+ return PullData (false);
+ }
+
+ // Return false ONLY in case of error - and return true even in cases
+ // where no update was possible
+ bool PullData (bool force)
{
if (IsBinding == false || manager.Current == null)
- return;
+ return true;
+#if NET_2_0
+ if (!force && datasource_update_mode == DataSourceUpdateMode.Never)
+ return true;
+#endif
data = control_property.GetValue (control);
- SetPropertyValue (data);
+
+ try {
+ SetPropertyValue (data);
+ } catch (Exception e) {
+#if NET_2_0
+ if (formatting_enabled) {
+ FireBindingComplete (BindingCompleteContext.DataSourceUpdate, e, e.Message);
+ return false;
+ }
+#endif
+ throw e;
+ }
+
+#if NET_2_0
+ if (formatting_enabled)
+ FireBindingComplete (BindingCompleteContext.DataSourceUpdate, null, null);
+#endif
+ return true;
}
internal void PushData ()
+ {
+ PushData (false);
+ }
+
+ void PushData (bool force)
{
if (manager == null || manager.IsSuspended || manager.Current == null)
return;
+#if NET_2_0
+ if (!force && control_update_mode == ControlUpdateMode.Never)
+ return;
+#endif
if (is_null_desc != null) {
bool is_null = (bool) is_null_desc.GetValue (manager.Current);
PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true);
if (pd == null) {
- data = ParseData (manager.Current, manager.Current.GetType ());
+ data = manager.Current;
} else {
- data = ParseData (pd.GetValue (manager.Current), pd.PropertyType);
+ data = pd.GetValue (manager.Current);
+ }
+
+ try {
+ data = FormatData (data);
+ SetControlValue (data);
+ } catch (Exception e) {
+#if NET_2_0
+ if (formatting_enabled) {
+ FireBindingComplete (BindingCompleteContext.ControlUpdate, e, e.Message);
+ return;
+ }
+#endif
+ throw e;
}
- data = FormatData (data);
- SetControlValue (data);
+#if NET_2_0
+ if (formatting_enabled)
+ FireBindingComplete (BindingCompleteContext.ControlUpdate, null, null);
+#endif
}
internal void UpdateIsBinding ()
{
+ is_binding = false;
+ if (control == null || !control.Created)
+ return;
+ if (manager == null || manager.IsSuspended)
+ return;
+
+ is_binding = true;
PushData ();
}
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 NET_2_0
+ if (datasource_update_mode != DataSourceUpdateMode.OnValidation)
+ return;
+#endif
+ bool ok = true;
// 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.
+ // If Formatting is enabled, no exception is fired, but we get a false value
try {
- PullData ();
+ ok = PullData ();
} catch {
- data = old_data;
- SetControlValue (data);
+ ok = false;
}
+
+ e.Cancel = !ok;
}
private void PositionChangedHandler (object sender, EventArgs e)
+ {
+ Check ();
+ PushData ();
+ }
+
+ EventDescriptor GetPropertyChangedEvent (object o, string property_name)
+ {
+ if (o == null || property_name == null || property_name.Length == 0)
+ return null;
+
+ string event_name = property_name + "Changed";
+ Type event_handler_type = typeof (EventHandler);
+
+ EventDescriptor prop_changed_event = null;
+ foreach (EventDescriptor event_desc in TypeDescriptor.GetEvents (o)) {
+ if (event_desc.Name == event_name && event_desc.EventType == event_handler_type) {
+ prop_changed_event = event_desc;
+ break;
+ }
+ }
+
+ return prop_changed_event;
+ }
+
+ void SourcePropertyChangedHandler (object o, EventArgs args)
{
PushData ();
}
+#if NET_2_0
+ void ControlPropertyChangedHandler (object o, EventArgs args)
+ {
+ if (datasource_update_mode != DataSourceUpdateMode.OnPropertyChanged)
+ return;
+
+ PullData ();
+ }
+#endif
+
private object ParseData (object data, Type data_type)
{
ConvertEventArgs e = new ConvertEventArgs (data, data_type);
return e.Value;
if (e.Value == Convert.DBNull)
return e.Value;
+#if NET_2_0
+ if (e.Value == null)
+ return data_type.IsByRef ? null : Convert.DBNull;
+#endif
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;
+#if NET_2_0
+ if (formatting_enabled) {
+ if (e.Value == null || e.Value == Convert.DBNull) {
+ return null_value;
+ }
+
+ if (e.Value is IFormattable && data_type == typeof (string)) {
+ IFormattable formattable = (IFormattable) e.Value;
+ return formattable.ToString (format_string, format_info);
+ }
+ }
+#endif
+ if (e.Value == null && data_type == typeof (object))
+ return Convert.DBNull;
+
return ConvertData (data, data_type);
}
private object ConvertData (object data, Type data_type)
{
+ if (data == null)
+ return null;
+
TypeConverter converter = TypeDescriptor.GetConverter (data.GetType ());
if (converter != null && converter.CanConvertTo (data_type))
return converter.ConvertTo (data, data_type);
return null;
}
+#if NET_2_0
+ void FireBindingComplete (BindingCompleteContext context, Exception exc, string error_message)
+ {
+ BindingCompleteEventArgs args = new BindingCompleteEventArgs (this,
+ exc == null ? BindingCompleteState.Success : BindingCompleteState.Exception,
+ context);
+ if (exc != null) {
+ args.SetException (exc);
+ args.SetErrorText (error_message);
+ }
+
+ OnBindingComplete (args);
+ }
+#endif
#region Events
public event ConvertEventHandler Format;
public event ConvertEventHandler Parse;
+#if NET_2_0
+ public event BindingCompleteEventHandler BindingComplete;
+#endif
#endregion // Events
}
}