To bind a business object to a asp.net form control using reflection

Source: Internet
Author: User
Tags foreach bind bool datetime include reflection tostring
Asp.net| Object | control

John Dyer
Dallas Theological Seminary

Apply to:
Microsoft Visual Studio 2005 and Previous versions
asp.net 1.1
C # programming language
Visual Basic programming language

Summary: Use reflection to bind business objects to asp.net Web forms in single-line code, reducing complexity and reducing errors. (This article contains links to English-language sites.) Note that in the sample file, the programmer's comment is in English and is translated into Chinese for easy reader's understanding. )

Download the Msdformbinding.msi sample file.

Content of this page

Introduction simplifies and shortens form code start: Retrieving property lists from reflection binding object property values to controls setting values for unknown controls with known properties reverse process: Extended conclusion reference for Bindcontrolstoobject performance and formbinding scenarios

Introduction

One of the most common tasks for WEB developers is that they want to do it over and over again: Create a simple form that updates a database table. We'll create a list page and a form page that displays records in tabular form pages, with the appropriate form controls for each database field in the form page. Many developers also use business objects that represent database tables to organize code into layers of design. If you represent a database table (Documents) as a business object (Document), the code for many forms looks like the following:

<script runat= "Server" >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. Createddate.tostring ();   Authorid.findbyvalue (document. Authorid.tostring ()). Selected =         true;   // ... Wait   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);   // ... Wait,   document. HtmlBody = Htmlbody.text;   Documents.update (document);} </script>
Back to the top of the page

Simplify and shorten form codes

In the preceding code, you explicitly cast each control and set it as the correct property for the form control. Depending on the number of properties and form controls, this part of the code may become longer and difficult to manage. The code should also contain error corrections and ListControl for type conversions, which further increases complexity. Even if a form is generated by a code generation tool (such as the excellent Codesmith of Eric J. Smith), it is easy to introduce errors when any custom logical relationships are needed.

With reflection, you can use a single line of code to bind all properties of a business object to the corresponding form control, reducing the number of lines of code and enhancing readability. When the reflection system is complete, the code above 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 is available for all standard asp.net controls (textbox, DropDownList, CheckBox, and so on) and many Third-party controls (such as free textbox and Calendar Popup). This line of code provides all the functionality you need, regardless of the number of business object properties and form controls, as long as the ID of the form control matches the business object property name.

Back to the top of the page

Starting: Retrieving a list of properties from reflection

First, we need to check the properties of the business object and look for the ASP.net control with the same ID as the business object property name. The following code forms the basis for binding lookups:

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 Objpropertiesarray) {control control         =                      container. FindControl (objproperty.name);         if (control!= null) {             //Process Controls ...}}         }   

In the above code, the method Bindobjectstocontrols accepts the business object obj and a container control. A container control is typically a Page object for the current Web form. If the version you are using is the ASP.net 1.x masterpages that will change the control's nesting order at run time, you will need to specify the Content control that contains the form control. This is caused by the way the FindControl method handles nested controls and naming containers in asp.net 1.x.

In the above code, we get the type of the business object, and then use that type to get an array of the PropertyInfo objects. Each PropertyInfo object contains information about the properties of the business object and the ability to get and set values from the business object. We use the Foreach Loop to check the container for the ASP.net control with the ID attribute that corresponds to the business object attribute name (propertyinfo.name). If a control is found, an attempt is to bind the property value to the control.

Back to the top of the page

To bind an object property value to a control

Most of the operations in the process are performed at this stage. We need to populate the found control with the object's property values. An implementation method is to create an if ... else statement for each type of control. All controls derived from ListControl (DropDownList, RadioButtonList, CheckBoxList, and ListBox) have public interfaces that can be uniformly accessed, so they can be grouped together. If the found control is ListControl, we can convert it as a ListControl and then set the selected item:

Control control = Container. FindControl (Objproperty.name); if (control!= null) {   if (control is ListControl) {      ListControl ListControl = (Lis Tcontrol) control;      String propertyvalue = Objproperty.getvalue (obj,               null). ToString ();      ListItem ListItem =              listControl.Items.FindByValue (propertyvalue);      if (ListItem!= null) listitem.selected = true;   } else {      //handling other control types   }}

Unfortunately, other control types are not derived from the parent class. The following several common controls have. Text String properties: TextBox, Literal, and Label. However, this property is not derived from the common parent class, so you need to convert each type of control separately. We also need to convert other control types, such as the Calendar control, to use the appropriate properties (in the case of the calendar, the SelectedDate property). It does not take too many lines of code to include all the standard asp.net form controls and access the correct properties of the form control.

if (Control are 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) control. Checked = (bool) objproperty.getvalue (obj, null); else if (control is Calendar) {if (Objproperty.propertytype = typeof (DateTime)) (calendar) control. SelectedDate = (DateTime) objproperty.getvalue (obj, null); else if (control's textbox) {(TextBox) control. Text = objproperty.getvalue (obj, null). ToString ();} else if (control is Literal) (//...). Wait a minute. It can also be used for properties such as labels. }

This method covers the standard ASP.net 1.x control in its entirety. From this point of view, we have a full-featured Bindobjecttocontrols method. However, the application scope of this method is limited because it only considers the built-in ASP.net 1.x control. If you want to support the new ASP.net 2.0 control, or if you want to use any third-party controls, we must refer to the control's assembly in the Formbinding project and add the control type to the IF ... else list.

The solution to this problem is to use reflection for the second time to see the properties of each control and to find out whether the control has a property type that corresponds to the property type of the business object.

Back to the top of the page

To set the value of an unknown control with a known property

As mentioned, some controls share string properties. Text, most form controls use this property in substantially the same way. This property is used to get and set the data entered by the user. There are a number of controls that also use some of the other common properties and property types. Here are some of these properties: called. The DateTime attribute of SelectedDate, which is used in many calendar and date picker controls; The Boolean property of the Checked, which is used in a Boolean control; The string property of Value, which is common to hidden controls. These four properties (string Text, String Value, bool Checked, and DateTime SelectedDate) are the most common control properties. If you can design your system to bind to these properties regardless of the type of control, our binding method will apply to any control that uses those four properties.

In the following code, we will use reflection for the second time (this time it is used on the form control, not the business object) to determine whether it has any common properties. If it does, it attempts to set the property value of the business object to the control's properties. As an example, we will iterate over the entire PropertyInfo array and look for what is called. The string property of the Text. If the control has this property, the data is sent from the business object to the control's properties.

If (control is ListControl) {   //...} else {   //Get the Type and property   //   Type ControlType = Controls. GetType ();   propertyinfo[] Controlpropertiesarray =         controltype.getproperties ();   Find. The Text property   //   foreach (PropertyInfo controlproperty in         controlpropertiesarray) {      if ( Controlpropertiesarray.name = = "Text" &&               controlpropertiesarray.propertytype = = typeof (String)) {         Sets the control's. Text Property         //         Controlproperty.setvalue (Control,                    (String) objproperty.getvalue (obj, null), NULL);   }}

If found. Text, the value is retrieved from the properties of the business object using the GetValue method of the PropertyInfo class. Then, use the control's. The SetValue method for the Text property. Here, we also use the Type command to set the control's property to typeof (String) and to explicitly convert the value from the property using the (string) symbol.

To make the Bindobjecttocontrols method complete, we also need to deal with other common properties, that is. Checked,. SelectedDate and. Value. In the following code, we package the control property search into a helper method called Findandsetcontrolproperty to simplify the code.

If (controls is ListControl) {//...} else {//Get the property/Type ControlType = control.   GetType ();   propertyinfo[] Controlpropertiesarray = Controltype.getproperties ();   BOOL success = FALSE; Success = Findandsetcontrolproperty (obj, Objproperty, control, Controlpropertiesarray, "Checked", typeof (b   OOL));               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[) CO Ntrolpropertiesarray, String PropertyName, type type) {//iterative foreach in the entire control property (PropertyInfo Controlproperty in Controlpropertiesarray) {//check Matching name and type if (Controlpropertiesarray.name = "Text" && controlpropertiesarray.propertytype = = Ty                    Peof (String) {//Set the control's property to//Business object property value Controlproperty.setvalue (         Convert.changetype (objproperty.getvalue (obj, null), type), NULL);      return true; return false;}

The order of the above property checks is important because some controls have more than one of these properties, but we just want to set one. For example, a CheckBox control has both. The Text property also has. Checked property. In this example, we want to use the. Checked property instead of. Text property, so the. Checked is placed first in the attribute search order. In any case, if you find a control property with the correct name and type, you try to set the control's property to the value of the business object property.

From this point of view, we have a full-featured Bindobjecttocontrols method. With this method, we can invoke any combination of any class and control anywhere on the ASPX form, which is really effective. Now we need to create a way to reverse the form when we submit it. Instead of setting the value of the control property to the value of the business object, we need to retrieve the new value from the control that represents the user input.

Back to the top of the page

Reverse process: Bindcontrolstoobject

In the Bindcontrolstoobject method, we will start in the same way by retrieving the list of properties from the business object and then using the FindControl method to find a control with an ID that matches the object's properties. If the control is found, the value is retrieved and the value is returned to the business object. This section will also contain separate code for ListControl because the controls have a public interface. We'll use another helper method to search for and retrieve the value in the control, and then return the 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 Objpropertiesarray) {if (control is ListControl) {ListControl Listcont         Rol = (ListControl) control; if (Listcontrol.selecteditem!= null) objproperty.setvalue (obj, Convert.changetype (li St.      Selecteditem.value, objproperty.propertytype), NULL); else {//Get the control's property//Type ControlType = controls.         GetType ();         propertyinfo[] Controlpropertiesarray = 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, CONTROLPR      Opertiesarray, "Text", typeof (String)); }}}private static void Findandgetcontrolproperty (Object obj, PropertyInfo objproperty, control control, propertyinfo[          ] Controlpropertiesarray, String propertyname, type type) {//iteration foreach in the entire control property (PropertyInfo Controlproperty in               Controlpropertiesarray) {//check the matching name and type if (Controlpropertiesarray.name = = "Text" &&    Controlpropertiesarray.propertytype = = typeof (String) {//Set the control's property to//Business object property value     try {objproperty.setvalue (obj, Convert.changetype (CO            Ntrolproperty.getvalue (control, NULL), objproperty.propertytype), NULL);         return true;            The catch {//cannot convert data from the form control//To//Objproperty.propertytype         return false; }} return true;}

After you have completed both methods, our form syntax is simplified, as described in the simplified and shortened form code above. The type conversions and error corrections for each property and control are automatic. Both of these methods (Bindobjecttocontrols and Bindcontrolstoobject) provide a great flexibility for developers to create forms. They can also be used to handle the following common scenarios:

If you add a new attribute to a business object and you need to access the new property on a form, the developer simply adds the control to the page and sets the ID of the control to the name of the new property, and the Formbinding method handles all the rest.

If a developer needs to change the type of control used for a particular property, such as an HTML editor control that changes from a TextBox to a third party, he or she only needs to make sure that the new control has one of the above properties, for example. Text), the form will work in exactly the same way as before.

Using the TextBox control all can also quickly generate a form, but the input will still be converted to the correct type for business object properties. For example, you can use a TextBox control instead of a calendar control or a Third-party date picker control. As long as the user enters a DateTime string as a value, the TextBox's. The value in the Text property is converted to DateTime as if it were the SelectedDate property on the Calendar control. If you later change the TextBox to a date picker control, the logical relationship remains unchanged.

Developers can also quickly create a view page by changing all controls to Literal controls. Literal's. The Text property is set to the value of the business object property as if it were a TextBox.

In the actual scenario, the form also contains other data types and custom configurations. The code that handles these specific actions can be placed after a call to Bindobjecttocontrols and Bindcontrolstoobject.

Back to the top of the page

Expansion of performance and formbinding scenarios

Some developers may wonder whether the performance degradation caused by using reflection is worthwhile. In my tests, I used seven properties (int DocumentID, bool Active, DateTime Created, int categoryid, String Title, String Author, and string HTMLText), Bindobjecttocontrols spents about 1/3 milliseconds, and bindcontrolstoobject about 1 milliseconds. These values are obtained by looping through the 1000 times Bindobjecttocontrols and Bindcontrolstoobject methods. For common "add" and "edit" form scenarios, such performance should not cause any significant problems and indeed improve development speed and flexibility.

Although this approach works for almost every form, you may need to modify the above code sometimes. In some scenarios, a control that a developer wants to use may not use one of these properties as its primary interface. In this case, you need to update the Formbinding method to include the property and type.

Back to the top of the page

Conclusion

Both of these formbinding methods (Bindobjecttocontrols and Bindcontrolstoobject) can be used to greatly simplify form code and provide the most flexibility for the development of ASP.net forms. I have benefited a lot from using them, and I hope your team will benefit as well.



Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.