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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
20 // Copyright (c) 2004-2005 Novell, Inc.
23 // Peter Bartok pbartok@novell.com
24 // Jackson Harper jackson@ximian.com
28 using System.ComponentModel;
30 namespace System.Windows.Forms {
32 [TypeConverter (typeof (ListBindingConverter))]
33 public class Binding {
35 private string property_name;
36 private object data_source;
37 private string data_member;
39 private bool is_binding;
40 private bool checked_isnull;
42 private BindingMemberInfo binding_member_info;
44 private IBindableComponent control;
46 private Control control;
49 private BindingManagerBase manager;
50 private PropertyDescriptor control_property;
51 private PropertyDescriptor is_null_desc;
54 private Type data_type;
57 private DataSourceUpdateMode datasource_update_mode;
58 private ControlUpdateMode control_update_mode;
59 private object datasource_null_value;
60 private object null_value;
61 private IFormatProvider format_info;
62 private string format_string;
63 private bool formatting_enabled;
65 #region Public Constructors
67 public Binding (string propertyName, object dataSource, string dataMember)
68 : this (propertyName, dataSource, dataMember, false, DataSourceUpdateMode.OnValidation, null, string.Empty, null)
72 public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled)
73 : this (propertyName, dataSource, dataMember, formattingEnabled, DataSourceUpdateMode.OnValidation, null, string.Empty, null)
77 public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode)
78 : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, null, string.Empty, null)
82 public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue)
83 : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, string.Empty, null)
87 public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString)
88 : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, formatString, null)
92 public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString, IFormatProvider formatInfo)
94 property_name = propertyName;
95 data_source = dataSource;
96 data_member = dataMember;
97 binding_member_info = new BindingMemberInfo (dataMember);
98 datasource_update_mode = dataSourceUpdateMode;
99 null_value = nullValue;
100 format_string = formatString;
101 format_info = formatInfo;
103 EventDescriptor prop_changed_event = GetPropertyChangedEvent (data_source, binding_member_info.BindingField);
104 if (prop_changed_event != null)
105 prop_changed_event.AddEventHandler (data_source, new EventHandler (SourcePropertyChangedHandler));
108 public Binding (string propertyName, object dataSource, string dataMember)
110 property_name = propertyName;
111 data_source = dataSource;
112 data_member = dataMember;
113 binding_member_info = new BindingMemberInfo (dataMember);
115 EventDescriptor prop_changed_event = GetPropertyChangedEvent (data_source, binding_member_info.BindingField);
116 if (prop_changed_event != null)
117 prop_changed_event.AddEventHandler (data_source, new EventHandler (SourcePropertyChangedHandler));
120 #endregion // Public Constructors
122 #region Public Instance Properties
124 [DefaultValue (null)]
125 public IBindableComponent BindableComponent {
131 public BindingManagerBase BindingManagerBase {
137 public BindingMemberInfo BindingMemberInfo {
139 return binding_member_info;
143 [DefaultValue (null)]
144 public Control Control {
147 return control as Control;
155 [DefaultValue (ControlUpdateMode.OnPropertyChanged)]
156 public ControlUpdateMode ControlUpdateMode {
158 return control_update_mode;
161 control_update_mode = value;
166 public object DataSource {
173 [DefaultValue (DataSourceUpdateMode.OnValidation)]
174 public DataSourceUpdateMode DataSourceUpdateMode {
176 return datasource_update_mode;
179 datasource_update_mode = value;
183 public object DataSourceNullValue {
185 return datasource_null_value;
188 datasource_null_value = value;
192 [DefaultValue (false)]
193 public bool FormattingEnabled {
195 return formatting_enabled;
198 if (formatting_enabled == value)
201 formatting_enabled = value;
206 [DefaultValue (null)]
207 public IFormatProvider FormatInfo {
212 if (value == format_info)
216 if (formatting_enabled)
221 public string FormatString {
223 return format_string;
227 value = String.Empty;
228 if (value == format_string)
231 format_string = value;
232 if (formatting_enabled)
238 public bool IsBinding {
245 public object NullValue {
250 if (value == null_value)
254 if (formatting_enabled)
261 public string PropertyName {
263 return property_name;
266 #endregion // Public Instance Properties
269 public void ReadValue ()
274 public void WriteValue ()
280 #region Protected Instance Methods
282 protected virtual void OnBindingComplete (BindingCompleteEventArgs e)
284 if (BindingComplete != null)
285 BindingComplete (this, e);
289 protected virtual void OnFormat (ConvertEventArgs cevent)
292 Format (this, cevent);
295 protected virtual void OnParse (ConvertEventArgs cevent)
298 Parse (this, cevent);
300 #endregion // Protected Instance Methods
302 internal string DataMember {
303 get { return data_member; }
307 internal void SetControl (IBindableComponent control)
309 internal void SetControl (Control control)
312 if (control == this.control)
315 control_property = TypeDescriptor.GetProperties (control).Find (property_name, true);
317 if (control_property == null)
318 throw new ArgumentException (String.Concat ("Cannot bind to property '", property_name, "' on target control."));
319 if (control_property.IsReadOnly)
320 throw new ArgumentException (String.Concat ("Cannot bind to property '", property_name, "' because it is read only."));
322 data_type = control_property.PropertyType; // Getting the PropertyType is kinda slow and it should never change, so it is cached
324 if (control is Control)
325 ((Control)control).Validating += new CancelEventHandler (ControlValidatingHandler);
328 EventDescriptor prop_changed_event = GetPropertyChangedEvent (control, property_name);
329 if (prop_changed_event != null)
330 prop_changed_event.AddEventHandler (control, new EventHandler (ControlPropertyChangedHandler));
332 this.control = control;
335 internal void Check ()
337 if (control == null || control.BindingContext == null)
340 if (manager == null) {
341 manager = control.BindingContext [data_source];
342 manager.AddBinding (this);
343 manager.PositionChanged += new EventHandler (PositionChangedHandler);
346 if (manager.Position == -1)
349 if (!checked_isnull) {
350 is_null_desc = TypeDescriptor.GetProperties (manager.Current).Find (property_name + "IsNull", false);
351 checked_isnull = true;
357 internal bool PullData ()
359 return PullData (false);
362 // Return false ONLY in case of error - and return true even in cases
363 // where no update was possible
364 bool PullData (bool force)
366 if (IsBinding == false || manager.Current == null)
369 if (!force && datasource_update_mode == DataSourceUpdateMode.Never)
373 data = control_property.GetValue (control);
376 SetPropertyValue (data);
377 } catch (Exception e) {
379 if (formatting_enabled) {
380 FireBindingComplete (BindingCompleteContext.DataSourceUpdate, e, e.Message);
388 if (formatting_enabled)
389 FireBindingComplete (BindingCompleteContext.DataSourceUpdate, null, null);
394 internal void PushData ()
399 void PushData (bool force)
401 if (manager == null || manager.IsSuspended || manager.Current == null)
404 if (!force && control_update_mode == ControlUpdateMode.Never)
408 if (is_null_desc != null) {
409 bool is_null = (bool) is_null_desc.GetValue (manager.Current);
411 data = Convert.DBNull;
416 PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true);
418 data = manager.Current;
420 data = pd.GetValue (manager.Current);
424 data = FormatData (data);
425 SetControlValue (data);
426 } catch (Exception e) {
428 if (formatting_enabled) {
429 FireBindingComplete (BindingCompleteContext.ControlUpdate, e, e.Message);
437 if (formatting_enabled)
438 FireBindingComplete (BindingCompleteContext.ControlUpdate, null, null);
442 internal void UpdateIsBinding ()
446 if (control == null || (control is Control && !((Control)control).Created))
448 if (control == null && !control.Created)
451 if (manager == null || manager.IsSuspended)
458 private void SetControlValue (object data)
460 control_property.SetValue (control, data);
463 private void SetPropertyValue (object data)
465 PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true);
468 data = ParseData (data, pd.PropertyType);
469 pd.SetValue (manager.Current, data);
472 private void ControlValidatingHandler (object sender, CancelEventArgs e)
475 if (datasource_update_mode != DataSourceUpdateMode.OnValidation)
480 // If the data doesn't seem to be valid (it can't be converted,
481 // is the wrong type, etc, we reset to the old data value.
482 // If Formatting is enabled, no exception is fired, but we get a false value
492 private void PositionChangedHandler (object sender, EventArgs e)
498 EventDescriptor GetPropertyChangedEvent (object o, string property_name)
500 if (o == null || property_name == null || property_name.Length == 0)
503 string event_name = property_name + "Changed";
504 Type event_handler_type = typeof (EventHandler);
506 EventDescriptor prop_changed_event = null;
507 foreach (EventDescriptor event_desc in TypeDescriptor.GetEvents (o)) {
508 if (event_desc.Name == event_name && event_desc.EventType == event_handler_type) {
509 prop_changed_event = event_desc;
514 return prop_changed_event;
517 void SourcePropertyChangedHandler (object o, EventArgs args)
523 void ControlPropertyChangedHandler (object o, EventArgs args)
525 if (datasource_update_mode != DataSourceUpdateMode.OnPropertyChanged)
532 private object ParseData (object data, Type data_type)
534 ConvertEventArgs e = new ConvertEventArgs (data, data_type);
537 if (data_type.IsInstanceOfType (e.Value))
539 if (e.Value == Convert.DBNull)
543 return data_type.IsByRef ? null : Convert.DBNull;
546 return ConvertData (e.Value, data_type);
549 private object FormatData (object data)
551 ConvertEventArgs e = new ConvertEventArgs (data, data_type);
554 if (data_type.IsInstanceOfType (e.Value))
558 if (formatting_enabled) {
559 if (e.Value == null || e.Value == Convert.DBNull) {
563 if (e.Value is IFormattable && data_type == typeof (string)) {
564 IFormattable formattable = (IFormattable) e.Value;
565 return formattable.ToString (format_string, format_info);
569 if (e.Value == null && data_type == typeof (object))
570 return Convert.DBNull;
572 return ConvertData (data, data_type);
575 private object ConvertData (object data, Type data_type)
580 TypeConverter converter = TypeDescriptor.GetConverter (data.GetType ());
581 if (converter != null && converter.CanConvertTo (data_type))
582 return converter.ConvertTo (data, data_type);
584 if (data is IConvertible) {
585 object res = Convert.ChangeType (data, data_type);
586 if (data_type.IsInstanceOfType (res))
593 void FireBindingComplete (BindingCompleteContext context, Exception exc, string error_message)
595 BindingCompleteEventArgs args = new BindingCompleteEventArgs (this,
596 exc == null ? BindingCompleteState.Success : BindingCompleteState.Exception,
599 args.SetException (exc);
600 args.SetErrorText (error_message);
603 OnBindingComplete (args);
608 public event ConvertEventHandler Format;
609 public event ConvertEventHandler Parse;
611 public event BindingCompleteEventHandler BindingComplete;