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 BindingMemberInfo binding_member_info
;
40 private Control control
;
42 private BindingManagerBase manager
;
43 private PropertyDescriptor control_property
;
44 private PropertyDescriptor is_null_desc
;
46 private EventDescriptor changed_event
;
47 private EventHandler property_value_changed_handler
;
48 private object event_current
; // The manager.Current as far as the changed_event knows
51 private Type data_type
;
53 #region Public Constructors
54 public Binding (string propertyName
, object dataSource
, string dataMember
)
56 property_name
= propertyName
;
57 data_source
= dataSource
;
58 data_member
= dataMember
;
59 binding_member_info
= new BindingMemberInfo (dataMember
);
61 #endregion // Public Constructors
63 #region Public Instance Properties
64 public BindingManagerBase BindingManagerBase
{
70 public BindingMemberInfo BindingMemberInfo
{
72 return binding_member_info
;
77 public Control Control
{
83 public object DataSource
{
89 public bool IsBinding
{
91 if (control
== null || !control
.Created
)
93 if (manager
== null || manager
.IsSuspended
)
100 public string PropertyName
{
102 return property_name
;
105 #endregion // Public Instance Properties
107 #region Protected Instance Methods
108 protected virtual void OnFormat (ConvertEventArgs cevent
)
111 Format (this, cevent
);
114 protected virtual void OnParse (ConvertEventArgs cevent
)
117 Parse (this, cevent
);
119 #endregion // Protected Instance Methods
122 internal void SetControl (Control control
)
124 if (control
== this.control
)
127 control_property
= TypeDescriptor
.GetProperties (control
).Find (property_name
, true);
129 if (control_property
== null)
130 throw new ArgumentException (String
.Concat ("Cannot bind to property '", property_name
, "' on target control."));
131 if (control_property
.IsReadOnly
)
132 throw new ArgumentException (String
.Concat ("Cannot bind to property '", property_name
, "' because it is read only."));
134 data_type
= control_property
.PropertyType
; // Getting the PropertyType is kinda slow and it should never change, so it is cached
135 control
.Validating
+= new CancelEventHandler (ControlValidatingHandler
);
137 this.control
= control
;
140 internal void Check (BindingContext binding_context
)
142 if (control
== null || control
.BindingContext
== null)
145 manager
= control
.BindingContext
[data_source
, data_member
];
147 manager
.AddBinding (this);
148 manager
.PositionChanged
+= new EventHandler (PositionChangedHandler
);
149 manager
.CurrentChanged
+= new EventHandler (CurrentChangedHandler
);
151 is_null_desc
= TypeDescriptor
.GetProperties (manager
.Current
).Find (property_name
+ "IsNull", false);
156 internal void PullData ()
158 if (IsBinding
== false || manager
.Current
== null)
161 data
= control_property
.GetValue (control
);
162 SetPropertyValue (data
);
165 internal void PushData ()
167 if (manager
== null || manager
.IsSuspended
|| manager
.Current
== null)
170 if (is_null_desc
!= null) {
171 bool is_null
= (bool) is_null_desc
.GetValue (manager
.Current
);
173 data
= Convert
.DBNull
;
178 PropertyDescriptor pd
= TypeDescriptor
.GetProperties (manager
.Current
).Find (binding_member_info
.BindingField
, true);
180 data
= ParseData (manager
.Current
, manager
.Current
.GetType ());
182 data
= ParseData (pd
.GetValue (manager
.Current
), pd
.PropertyType
);
185 data
= FormatData (data
);
186 SetControlValue (data
);
189 internal void UpdateIsBinding ()
194 private void SetControlValue (object data
)
196 control_property
.SetValue (control
, data
);
199 private void SetPropertyValue (object data
)
201 PropertyDescriptor pd
= TypeDescriptor
.GetProperties (manager
.Current
).Find (binding_member_info
.BindingField
, true);
204 data
= ParseData (data
, pd
.PropertyType
);
205 pd
.SetValue (manager
.Current
, data
);
208 private void CurrentChangedHandler (object sender
, EventArgs e
)
213 private void ControlValidatingHandler (object sender
, CancelEventArgs e
)
215 object old_data
= data
;
217 // If the data doesn't seem to be valid (it can't be converted,
218 // is the wrong type, etc, we reset to the old data value.
223 SetControlValue (data
);
227 private void PositionChangedHandler (object sender
, EventArgs e
)
232 private object ParseData (object data
, Type data_type
)
234 ConvertEventArgs e
= new ConvertEventArgs (data
, data_type
);
237 if (data_type
.IsInstanceOfType (e
.Value
))
239 if (e
.Value
== Convert
.DBNull
)
242 return ConvertData (e
.Value
, data_type
);
245 private object FormatData (object data
)
247 if (data_type
== typeof (object))
250 ConvertEventArgs e
= new ConvertEventArgs (data
, data_type
);
253 if (data_type
.IsInstanceOfType (e
.Value
))
256 return ConvertData (data
, data_type
);
259 private object ConvertData (object data
, Type data_type
)
261 TypeConverter converter
= TypeDescriptor
.GetConverter (data
.GetType ());
262 if (converter
!= null && converter
.CanConvertTo (data_type
))
263 return converter
.ConvertTo (data
, data_type
);
265 if (data
is IConvertible
) {
266 object res
= Convert
.ChangeType (data
, data_type
);
267 if (data_type
.IsInstanceOfType (res
))
275 public event ConvertEventHandler Format
;
276 public event ConvertEventHandler Parse
;