Use reflections to bind business objects to ASP.NET Form Controls
Release Date: 12/10/2004
| Update Date: 12/10/2004
John Dyerdallas theology seminary
Applicable to: Microsoft Visual Studio 2005 and Early Version ASP.NET 1.1C # Programming Language Visual Basic Programming Language
Summary: Use reflection to bind business objects to the ASP.NET web form, reducing complexity and decrease errors. (This article contains links to English sites. Please note that in the sample file, the programmer's comment is in English. In this paper, it is translated into Chinese to facilitate the reader.)
Download the MSDFORMBINDING.MSI sample file.
This page
Introduction Simplification and shortening the form code Start: Retrieving the property list from the reflection to the value of the object property value to the control with a known property to set the values of the unknown control: BindControlstoobject performance and extension of the FORMBINDING
introduction
Among the most common tasks of the web developer, there is a task that they want to perform repeatedly: Establish a simple form for updating the database table. We will create a list page and a form page, and the list is displayed in a table form, and the form page has an appropriate form control for each database field. Many developers also use business objects that represent database tables to a multi-layer design. If the database table (Documents) is used in the business object, many forms of forms look like this:
Protected Void Page_Load (Object SRC, Eventargs E) {
IF (! ispostback) {
Document Document =
Documents.getDocument (Request.QueryString ";" DocumentID "]);
Title.Text = Document.Title;
Active.checked = document.active;
Createddate.text = document.createdddate.toString ();
Authorid.FindByValue (Document.Authorid.toString ()). SELECTED =
True;
// ... and many more
HTMLBODY.TEXT = Document.htmlbody;
}
}
Protected Void SaveButton_Click (Object SRC, Eventargs E) {
Document Document =
Documents.getDocument (Request.QueryString ";" DocumentID "]);
Document.title = Title.Text;
Document.active = Active.Checked;
Document.createdDate = convert.todatetime (createddate.text);
Document.authorid = Convert.Toint32 (Authorid.selectedItem.Value);
// ... and many more
Document.htmlbody = HTMLBODY.TEXT;
Documents.Update (document);
}
script>
Back to top
Simplify and shorten the form code
In the above code, each control is explicitly converted, and it is set to the correct attribute of the form control. This part of the code may become long and difficult to manage according to the number of attributes and form controls. The code should also contain the type conversion error correction and ListControl, which will further increase the complexity. Even if the form is generated by a code generation tool (such as Eric J. Smith, it is easy to introduce an error when any custom logical relationship is required. Using reflections, you can use only a single line of code to bind all attributes of the business object to the appropriate form control, thereby reducing the number of lines of code and enhances readability. After completing the establishment of the reflection system, the above code will be simplified to:
Protected Void Page_Load (Object SRC, Eventargs E) {
IF (! ispostback) {
Document Document =
Documents.getDocument (Request.QueryString ";" DocumentID "]);
FormBinding.bindObjectTocontrols (document);
}
}
Protected Void Save_Click (Object SRC, Eventargs E) {
Document Document =
Documents.getDocument (Request.QueryString ";" DocumentID "]);
Formbinding.bindControlstoObject (document);
Documents.Update (document);
}
This code can be used for all standard ASP.NET controls (TextBox, DropDownList, Checkbox, etc.) and many third-party controls (such as Free Textbox and Calendar Popup). Regardless of how many business object properties and form controls, this line of code provides all the features required, as long as the ID of the form control is matched to the business object attribute name.
Back to top
Start: Retrieve attribute list from reflection
First, we need to check the properties of the business object and find an ASP.NET control with the same ID as the business object property name. The following code forms the basis of binding findings:
Public class formbinding {
Public Static Void BindObjectTocontrols (Object Obj,
Control container) {
IF (obj == null) return;
TYPE OBJTYPE = Obj.gettype ();
PropertyInfo [] ObjPropertiesArray =
Objtype.getproperties ();
Foreach (propertyInfo objproperty in objpropertiesay) {
Control Control =
Container.FindControl (ObjProperty.Name);
IF (Control! = null) {
// Handling controls ...
}
}
}
}
In the above code, the method BindObjectStocontrols accepts business objects OBJ and a container control. Container controls are typically the PAGE object of the current web form. If the version used is ASP.NET 1.x masterpages that will change the sequence of controls at runtime, you will need to specify the Content control in which the form control is located. This is in the ASP.NET 1.x, the FindControl method causes the design of nested controls and naming containers.
In the above code, we get the TYPE of the business object and then use this type to get the array of PropertyInfo objects. Each PropertyInfo object contains information about the ability of the business object properties and the ability to get and set values from the business object. We use the Foreach loop to check the container of the ASP.NET control with the ID attribute corresponding to the business object property name (PropertyInfo.name). If the control is found, try to bind the attribute value to the control. Back to top
Bind the object attribute value to the control
Most of the operations in the process are performed at this stage. We need to populate the found control with the property value of the object. One implementation method is to create an IF ... ELSE statement for each control type. Derive All controls from ListControl (DropDownList, Radiobuttonlist, CheckBoxList, and Listbox have public interfaces that can be accessed, so they can group them together. If the found control is ListControl, we can convert it as ListControl and set the selected item:
Control control = container.FindControl (ObjProperty.Name);
IF (Control! = null) {
IF (Control Is ListControl) {
ListControl ListControl = (ListControl) Control;
String PropertyValue = ObjProperty.getValue (Obj,
NULL). Tostring ();
ListItem ListItem =
ListControl.Items.FindByValue;
IF (ListItem! = null) ListItem.selected = true;
} else {
// Handle other control types
}
}
Unfortunately, other control types are not derived from the parent class. The following public controls have .Text string properties: TextBox, Litral and Label. However, this property is not derived from the public parent class, so it is necessary to convert each control type separately. We also need to convert other control types, such as Calendar controls to use the appropriate properties (in Calendar's example, is a SELECTEDDATE property). To include all standard ASP.NET Forms Controls, and access the correct attribute of the form control does not require too much code rows.
IF (Control Is ListControl) {
ListControl ListControl = (ListControl) Control;
String PropertyValue = ObjProperty.getValue (Obj,
NULL). Tostring ();
ListItem ListItem = ListControl.Items.FindByValue (PropertyValue);
IF (ListItem! = null) ListItem.selected = true;
} else if (control is checkbox) {
IF (ObjProperty.PropertyType == TypeOf (bool))
(CheckBox) .Checked = (bool)
ObjProperty.getValue (OBJ, NULL);
} else IF (control is calendar) {
IF (ObjProperty.PropertyTyPE == TypeOf (datetime))
(Calendar) .SelectedDate = (datetime)
ObjProperty.getValue (OBJ, NULL);
} else if (control is textbox) {
(TextBox) .Text = Objproperty.getValue (Obj,
NULL). Tostring ();
Else IF (Control Is Literal)
//... and many more. Can also be used for attributes such as labels.
}
This method integrates the standard ASP.NET 1.x control. From this perspective, we have a fully fully equipped BindObjectTocontrols method. But while playing, this method of application will be limited because it only considers built-in ASP.NET 1.x control. If you want to support new ASP.NET 2.0 controls, or use any third-party controls, we must use the controls of the control in the FormBinding project and add the control type to the IF ... Else list.
The solution for this issue is the second time you use reflections to see the properties of each control, and find the control with the property type corresponding to the attribute type of the business object.
Back to top
Set the value of unknown controls with known properties
As mentioned above, some controls share string properties. TEXT, most form controls use this property in the same way. This property is used to get and set data input by the user. There is a large number of controls, there are other common attributes and attribute types. The following is some of these properties: called .selectedDate's DateTime property, it is used in many calendar and date picking controls; called .Checked Boolean properties, it is used in Boolean controls; called .Value characters String properties, it is common in hidden controls. These four properties (String text, String Value, Bool Checked, and DateTime SELECTEDDATE are the most common control properties. If the system is designed to bind to these properties, our binding method will apply to any controls using the four properties.
In the following code, we use reflections for the second time (this time is used for the form control, not the business object) to determine if it has any common attributes. If so, try setting the property value of the business object to the properties of the control. As an example, we will iterate the entire PropertyInfo array and look for string properties called .Text. If the control has this attribute, the data is sent from the business object to the properties of the control.
IF (Control Is ListControl) {
// ...
} else {
// Get the type and properties of the control
//
TYPE controltype = control.gettype ();
PropertyInfo [] ControlPropertiesAry =
ControlType.getProperties ();
/ / Find .Text properties
//
Foreach (PropertyInfo ControlProperty)
In ControlPropertiesArray) {
IF (ControlPropertiesAmray.name == "Text" &&
ControlPropertiesArray.propertyType == TypeOf (String)) {
/ / Set the .Text property of the control
//
ControlProperty.SetValue (Control,
(String) ObjProperty.getValue (Obj, null), null;}
}
}
If you find .Text, use the GetValue method of the PropertyInfo class to retrieve the value from the properties of the business object. Then, use the Control's .Text property of the SetValue method. Here, we also use the type command to set the properties of the control to Type (String), and use the (String) symbol explicitly convert the value from the property.
In order to make the BindObjectTocontrols method, we also need to handle other public properties, ie .checked, .selectedddate and .value. In the following code, we package the control property search to simplify the code.
IF (Control Is ListControl) {
// ...
} else {
// Get the properties of the control
//
TYPE controltype = control.gettype ();
PropertyInfo [] ControlPropertiesAry =
ControlType.getProperties ();
Bool Success = FALSE;
Success = FINDANDSETCONTROLPROPERTY (Obj,
ObjProperty, Control, ControlPropertiesArray,
"Checked", TypeOf (BOOL);
IF (! SUCCESS)
Success = FINDANDSETCONTROLPROPERTY (Obj,
ObjProperty, Control, ControlPropertiesArray,
"SELECTEDDATE", TypeOf (datetime));
IF (! SUCCESS)
Success = FINDANDSETCONTROLPROPERTY (Obj,
ObjProperty, Control, ControlPropertiesArray,
"Value", TypeOf (String);
IF (! SUCCESS)
Success = FINDANDSETCONTROLPROPERTY (Obj,
ObjProperty, Control, ControlPropertiesArray,
"Text", TypeOf (String);
}
Private static void FindandSetControlProperty (Object Obj,
PropertyInfo ObjProperty, Control Control,
PropertyInfo [] ControlPropertiesAme, String PropertyName,
TYPE TYPE) {
/ / Iterations in the entire control attribute
Foreach (PropertyInfo ControlProperty in)
ControlpropertiesAry) {
// Check the name and type of the match
IF (ControlPropertiesAmray.name == "Text" &&
ControlPropertiesArray.propertyType == TypeOf (String)) {
// Set the properties of the control to
// Business object attribute value
ControlProperty.SetValue (Control,
Convert.changeType
ObjProperty.GetValue (Obj, NULL), TYPE, NULL;
Return True;
}
}
Return False;
}
The order in which the above attribute check is important, because some controls have multiple in the above properties, but we just want to set one. For example, the Checkbox control has both .Text properties also have .Checked properties. In this example, we want to use the .checked attribute rather than .Text properties, so put the .Checked in the primary search order. In any case, if you find a control property with the correct name and type, try to set the property of the control to the value of the business object property.
From this perspective, we have a fully fully equipped BindObjectTocontrols method. With this method, we can call any of the ASPX forms, any combination of any classes and controls, which is indeed valid. Now, we need to create a method of reversing when a form is submitted. We need to retrieve new values from the controls indicating the user input, rather than setting the value of the control attribute to the value of the business object.
Back to top
Reverse process: BindControlstoObject
In the BindControlStoObject method, we will start in the same way, namely the list of properties from the business object, and then use the FindControl method to find controls with the ID matching with the object properties. If the control is found, the value is retrieved and the value is returned to the business object. This section will also contain a separate code of ListControl because these controls have a public interface. We will use another auxiliary method to search and retrieve values in the control, and then return this value to the business object.
Public Static void BindControlstoObject (Object Obj,
Control container) {
TYPE OBJTYPE = Obj.gettype ();
PropertyInfo [] ObjPropertiesArray = ObjType.getProperties ();
Foreach (propertyInfo objproperty in objpropertiesay) {
IF (Control Is ListControl) {
ListControl ListControl = (ListControl) Control;
IF (ListControl.SelectedItem! = null)
ObjProperty.SetValue (Obj,
Convert.changeType (list.selectedItem.Value,
ObjProperty.propertyType), NULL);
} else {
// Get the properties of the control
//
TYPE controltype = control.gettype ();
PropertyInfo [] ControlPropertiesAry =
ControlType.getProperties ();
Bool Success = FALSE;
Success = FindandGetControlProperty (Obj,
ObjProperty, Control, ControlPropertiesArray,
"Checked", TypeOf (BOOL);
IF (! SUCCESS)
Success = FindandGetControlProperty (Obj,
ObjProperty, Control, ControlPropertiesArray,
"SELECTEDDATE", TypeOf (datetime));
IF (! SUCCESS)
Success = FindandGetControlProperty (Obj,
ObjProperty, Control, ControlPropertiesArray, "Value", TypeOf (String);
IF (! SUCCESS)
Success = FindandGetControlProperty (Obj,
ObjProperty, Control, ControlPropertiesArray,
"Text", TypeOf (String);
}
}
}
Private static void FindandGetControlProperty (Object Obj,
PropertyInfo ObjProperty, Control Control, PropertyInfo []
ControlPropertiesAmray, String propertyName, Type Type {
/ / Iterations in the entire control attribute
Foreach (PropertyInfo ControlProperty in)
ControlpropertiesAry) {
// Check the name and type of the match
IF (ControlPropertiesAmray.name == "Text" &&
ControlPropertiesArray.propertyType == TypeOf (String)) {
// Set the properties of the control to
// Business object attribute value
Try {
ObjProperty.SetValue (Obj,
Convert.changeType
ControlProperty.GetValue (Control, Null),
ObjProperty.propertyType), NULL);
Return True;
} catCH {
/ / Unable to come from the form control
//'s data conversion to
// ObjProperty.propertyType
Return False;
}
}
}
Return True;
}
Once these two methods are completed, our form syntax will be simplified, as described above and shortening the form code. Each attribute and control type conversion and error correction are automatically performed. BindObjectToControls and BindControlstoObject provide a lot of flexibility for developers' creation forms. They can also be used to deal with these common solutions:
• If you add a new property to a business object, and you need to access the new property on the form, the developer simply adds the control to the page, and sets the name of the control to the new attribute, the FORMBINDING method will handle the rest everything of. • If developers need to change controls for specific properties, for example from TextBox to third-party HTML editor controls, he / she only needs to ensure that new controls have one of the above properties (for example, .text), the form will Working in a completely consistent manner. • All using the TextBox control can also generate a form quickly, but the input will continue to convert the correct type for the business object properties. For example, you can use the TextBox control instead of the Calendar control or a third party's date pickup control. As long as the user enters the DateTime string as the value, the value in the TEXTBOX .Text property is converted to DateTime, just like it is the same as the SelectedDate property on the calendar control. If you will change TextBox to date pickup control, the logical relationship will remain unchanged. • Developers can quickly create the View page by changing all controls to Literal controls. Literal's .Text property will be set to the value of the business object properties, just like it is TextBox. • In a practical scheme, the form also contains other data types and custom configurations. Codes for handling these specific operations can be placed after the call to BindObjectTocontrols and BindControlStoObject. Back to top
Performance and extension of the FormBinding scheme
Some developers may want to know whether the performance of performance caused by reflection is worth it. In my tests, the use of the object in seven properties (int DocumentID, bool Active, DateTime Created, int CategoryID, String Title, string Author and String htmlText), and about 1/3 ms BindObjectToControls used, with about 1 millisecond when BindControlsToObject . These values are obtained by looping 1000 BindObjectToControls and BindControlstoObject methods. For common "Add" and "Edit" form schemes, such performance should not cause any major problems, and it is indeed possible to improve development speed and flexibility.
Although this method is almost applicable to each form, it may be necessary to modify the above code. In some scenarios, the controls to be used by developers may not use one of the above properties as its primary interface. In this case, you need to update the FORMBINDING method to include this attribute and type.
Back to top
in conclusion
These two formbinding methods (BindObjectTocontrols, and BindControlstoObject) can greatly simplify form code and provide maximum flexibility for the development of ASP.NET forms. Use them to benefit more, I hope your team can also benefit from it.
Back to top
Reference
• ASP.NET Unleashed • Programming Microsoft ASP.NET
About the Author