[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / Binding.cs
blob468f30e74983519149b7be801801c72d8f794d13
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:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
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.
22 // Authors:
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;
43 private IBindableComponent control;
45 private BindingManagerBase manager;
46 private PropertyDescriptor control_property;
47 private PropertyDescriptor is_null_desc;
49 private object data;
50 private Type data_type;
52 private DataSourceUpdateMode datasource_update_mode;
53 private ControlUpdateMode control_update_mode;
54 private object datasource_null_value = Convert.DBNull;
55 private object null_value;
56 private IFormatProvider format_info;
57 private string format_string;
58 private bool formatting_enabled;
59 #region Public Constructors
60 public Binding (string propertyName, object dataSource, string dataMember)
61 : this (propertyName, dataSource, dataMember, false, DataSourceUpdateMode.OnValidation, null, string.Empty, null)
65 public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled)
66 : this (propertyName, dataSource, dataMember, formattingEnabled, DataSourceUpdateMode.OnValidation, null, string.Empty, null)
70 public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode)
71 : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, null, string.Empty, null)
75 public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue)
76 : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, string.Empty, null)
80 public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString)
81 : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, formatString, null)
85 public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString, IFormatProvider formatInfo)
87 property_name = propertyName;
88 data_source = dataSource;
89 data_member = dataMember;
90 binding_member_info = new BindingMemberInfo (dataMember);
91 datasource_update_mode = dataSourceUpdateMode;
92 null_value = nullValue;
93 format_string = formatString;
94 format_info = formatInfo;
96 #endregion // Public Constructors
98 #region Public Instance Properties
99 [DefaultValue (null)]
100 public IBindableComponent BindableComponent {
101 get {
102 return control;
106 public BindingManagerBase BindingManagerBase {
107 get {
108 return manager;
112 public BindingMemberInfo BindingMemberInfo {
113 get {
114 return binding_member_info;
118 [DefaultValue (null)]
119 public Control Control {
120 get {
121 return control as Control;
125 [DefaultValue (ControlUpdateMode.OnPropertyChanged)]
126 public ControlUpdateMode ControlUpdateMode {
127 get {
128 return control_update_mode;
130 set {
131 control_update_mode = value;
135 public object DataSource {
136 get {
137 return data_source;
141 [DefaultValue (DataSourceUpdateMode.OnValidation)]
142 public DataSourceUpdateMode DataSourceUpdateMode {
143 get {
144 return datasource_update_mode;
146 set {
147 datasource_update_mode = value;
151 public object DataSourceNullValue {
152 get {
153 return datasource_null_value;
155 set {
156 datasource_null_value = value;
160 [DefaultValue (false)]
161 public bool FormattingEnabled {
162 get {
163 return formatting_enabled;
165 set {
166 if (formatting_enabled == value)
167 return;
169 formatting_enabled = value;
170 PushData ();
174 [DefaultValue (null)]
175 public IFormatProvider FormatInfo {
176 get {
177 return format_info;
179 set {
180 if (value == format_info)
181 return;
183 format_info = value;
184 if (formatting_enabled)
185 PushData ();
189 public string FormatString {
190 get {
191 return format_string;
193 set {
194 if (value == null)
195 value = String.Empty;
196 if (value == format_string)
197 return;
199 format_string = value;
200 if (formatting_enabled)
201 PushData ();
205 public bool IsBinding {
206 get {
207 if (manager == null || manager.IsSuspended)
208 return false;
210 return is_binding;
214 public object NullValue {
215 get {
216 return null_value;
218 set {
219 if (value == null_value)
220 return;
222 null_value = value;
223 if (formatting_enabled)
224 PushData ();
228 [DefaultValue ("")]
229 public string PropertyName {
230 get {
231 return property_name;
234 #endregion // Public Instance Properties
236 public void ReadValue ()
238 PushData (true);
241 public void WriteValue ()
243 PullData (true);
246 #region Protected Instance Methods
247 protected virtual void OnBindingComplete (BindingCompleteEventArgs e)
249 if (BindingComplete != null)
250 BindingComplete (this, e);
253 protected virtual void OnFormat (ConvertEventArgs cevent)
255 if (Format!=null)
256 Format (this, cevent);
259 protected virtual void OnParse (ConvertEventArgs cevent)
261 if (Parse!=null)
262 Parse (this, cevent);
264 #endregion // Protected Instance Methods
266 internal string DataMember {
267 get { return data_member; }
270 internal void SetControl (IBindableComponent control)
272 if (control == this.control)
273 return;
275 control_property = TypeDescriptor.GetProperties (control).Find (property_name, true);
277 if (control_property == null)
278 throw new ArgumentException (String.Concat ("Cannot bind to property '", property_name, "' on target control."));
279 if (control_property.IsReadOnly)
280 throw new ArgumentException (String.Concat ("Cannot bind to property '", property_name, "' because it is read only."));
282 data_type = control_property.PropertyType; // Getting the PropertyType is kinda slow and it should never change, so it is cached
284 Control ctrl = control as Control;
285 if (ctrl != null) {
286 ctrl.Validating += new CancelEventHandler (ControlValidatingHandler);
287 if (!ctrl.IsHandleCreated)
288 ctrl.HandleCreated += new EventHandler (ControlCreatedHandler);
291 EventDescriptor prop_changed_event = GetPropertyChangedEvent (control, property_name);
292 if (prop_changed_event != null)
293 prop_changed_event.AddEventHandler (control, new EventHandler (ControlPropertyChangedHandler));
294 this.control = control;
295 UpdateIsBinding ();
298 internal void Check ()
300 if (control == null || control.BindingContext == null)
301 return;
303 if (manager == null) {
304 manager = control.BindingContext [data_source, binding_member_info.BindingPath];
306 if (manager.Position > -1 && binding_member_info.BindingField != String.Empty &&
307 TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true) == null)
308 throw new ArgumentException ("Cannot bind to property '" + binding_member_info.BindingField + "' on DataSource.",
309 "dataMember");
311 manager.AddBinding (this);
312 manager.PositionChanged += new EventHandler (PositionChangedHandler);
314 if (manager is PropertyManager) { // Match .net, which only watchs simple objects
315 EventDescriptor prop_changed_event = GetPropertyChangedEvent (manager.Current, binding_member_info.BindingField);
316 if (prop_changed_event != null)
317 prop_changed_event.AddEventHandler (manager.Current, new EventHandler (SourcePropertyChangedHandler));
321 if (manager.Position == -1)
322 return;
324 if (!checked_isnull) {
325 is_null_desc = TypeDescriptor.GetProperties (manager.Current).Find (property_name + "IsNull", false);
326 checked_isnull = true;
329 PushData ();
332 internal bool PullData ()
334 return PullData (false);
337 // Return false ONLY in case of error - and return true even in cases
338 // where no update was possible
339 bool PullData (bool force)
341 if (IsBinding == false || manager.Current == null)
342 return true;
343 if (!force && datasource_update_mode == DataSourceUpdateMode.Never)
344 return true;
346 data = control_property.GetValue (control);
347 if (data == null)
348 data = datasource_null_value;
350 try {
351 SetPropertyValue (data);
352 } catch (Exception e) {
353 if (formatting_enabled) {
354 FireBindingComplete (BindingCompleteContext.DataSourceUpdate, e, e.Message);
355 return false;
357 throw e;
360 if (formatting_enabled)
361 FireBindingComplete (BindingCompleteContext.DataSourceUpdate, null, null);
362 return true;
365 internal void PushData ()
367 PushData (false);
370 void PushData (bool force)
372 if (manager == null || manager.IsSuspended || manager.Count == 0 || manager.Position == -1)
373 return;
374 if (!force && control_update_mode == ControlUpdateMode.Never)
375 return;
377 if (is_null_desc != null) {
378 bool is_null = (bool) is_null_desc.GetValue (manager.Current);
379 if (is_null) {
380 data = Convert.DBNull;
381 return;
385 PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true);
386 if (pd == null) {
387 data = manager.Current;
388 } else {
389 data = pd.GetValue (manager.Current);
392 if ((data == null || data == DBNull.Value) && null_value != null)
393 data = null_value;
395 try {
396 data = FormatData (data);
397 SetControlValue (data);
398 } catch (Exception e) {
399 if (formatting_enabled) {
400 FireBindingComplete (BindingCompleteContext.ControlUpdate, e, e.Message);
401 return;
403 throw e;
406 if (formatting_enabled)
407 FireBindingComplete (BindingCompleteContext.ControlUpdate, null, null);
410 internal void UpdateIsBinding ()
412 is_binding = false;
413 if (control == null || (control is Control && !((Control)control).IsHandleCreated))
414 return;
416 is_binding = true;
417 PushData ();
420 private void SetControlValue (object data)
422 control_property.SetValue (control, data);
425 private void SetPropertyValue (object data)
427 PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true);
428 if (pd.IsReadOnly)
429 return;
430 data = ParseData (data, pd.PropertyType);
431 pd.SetValue (manager.Current, data);
434 private void ControlValidatingHandler (object sender, CancelEventArgs e)
436 if (datasource_update_mode != DataSourceUpdateMode.OnValidation)
437 return;
439 bool ok = true;
440 // If the data doesn't seem to be valid (it can't be converted,
441 // is the wrong type, etc, we reset to the old data value.
442 // If Formatting is enabled, no exception is fired, but we get a false value
443 try {
444 ok = PullData ();
445 } catch {
446 ok = false;
449 e.Cancel = !ok;
452 private void ControlCreatedHandler (object o, EventArgs args)
454 UpdateIsBinding ();
457 private void PositionChangedHandler (object sender, EventArgs e)
459 Check ();
460 PushData ();
463 EventDescriptor GetPropertyChangedEvent (object o, string property_name)
465 if (o == null || property_name == null || property_name.Length == 0)
466 return null;
468 string event_name = property_name + "Changed";
469 Type event_handler_type = typeof (EventHandler);
471 EventDescriptor prop_changed_event = null;
472 foreach (EventDescriptor event_desc in TypeDescriptor.GetEvents (o)) {
473 if (event_desc.Name == event_name && event_desc.EventType == event_handler_type) {
474 prop_changed_event = event_desc;
475 break;
479 return prop_changed_event;
482 void SourcePropertyChangedHandler (object o, EventArgs args)
484 PushData ();
487 void ControlPropertyChangedHandler (object o, EventArgs args)
489 if (datasource_update_mode != DataSourceUpdateMode.OnPropertyChanged)
490 return;
492 PullData ();
495 private object ParseData (object data, Type data_type)
497 ConvertEventArgs e = new ConvertEventArgs (data, data_type);
499 OnParse (e);
500 if (data_type.IsInstanceOfType (e.Value))
501 return e.Value;
502 if (e.Value == Convert.DBNull)
503 return e.Value;
504 if (e.Value == null) {
505 bool nullable = data_type.IsGenericType && !data_type.ContainsGenericParameters &&
506 data_type.GetGenericTypeDefinition () == typeof (Nullable<>);
507 return data_type.IsValueType && !nullable ? Convert.DBNull : null;
510 return ConvertData (e.Value, data_type);
513 private object FormatData (object data)
515 ConvertEventArgs e = new ConvertEventArgs (data, data_type);
517 OnFormat (e);
518 if (data_type.IsInstanceOfType (e.Value))
519 return e.Value;
521 if (formatting_enabled) {
522 if ((e.Value == null || e.Value == Convert.DBNull) && null_value != null)
523 return null_value;
525 if (e.Value is IFormattable && data_type == typeof (string)) {
526 IFormattable formattable = (IFormattable) e.Value;
527 return formattable.ToString (format_string, format_info);
531 if (e.Value == null && data_type == typeof (object))
532 return Convert.DBNull;
534 return ConvertData (data, data_type);
537 private object ConvertData (object data, Type data_type)
539 if (data == null)
540 return null;
542 TypeConverter converter = TypeDescriptor.GetConverter (data.GetType ());
543 if (converter != null && converter.CanConvertTo (data_type))
544 return converter.ConvertTo (data, data_type);
546 converter = TypeDescriptor.GetConverter (data_type);
547 if (converter != null && converter.CanConvertFrom (data.GetType()))
548 return converter.ConvertFrom (data);
550 if (data is IConvertible) {
551 object res = Convert.ChangeType (data, data_type);
552 if (data_type.IsInstanceOfType (res))
553 return res;
556 return null;
558 void FireBindingComplete (BindingCompleteContext context, Exception exc, string error_message)
560 BindingCompleteEventArgs args = new BindingCompleteEventArgs (this,
561 exc == null ? BindingCompleteState.Success : BindingCompleteState.Exception,
562 context);
563 if (exc != null) {
564 args.SetException (exc);
565 args.SetErrorText (error_message);
568 OnBindingComplete (args);
571 #region Events
572 public event ConvertEventHandler Format;
573 public event ConvertEventHandler Parse;
574 public event BindingCompleteEventHandler BindingComplete;
575 #endregion // Events