Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Manage ASP.NET Server Controls, Event Handlers, and Server-Side Validation Using XML and XSLT

0.00/5 (No votes)
18 Apr 2008 4  
An article on managing ASP.NET server controls, event handlers, and server-side validation using XML and XSLT.

Introduction

In most cases, server controls are very useful in ASP.NET web applications since they have some valuable events (for example, click event, data binding event, data bound event, etc.) and many advance functionalities like state management, input validation, etc. In general, XSLT produces plain XML or HTML without any hassle, but if we want to create our ASP.NET server control by using XML and XSLT, then we should follow some procedures which will be described below.

XML has vast uses in web applications, and when we combine XML and XSLT, it shows its own strength and beauty which can speed up our application very much. One major benefit of using XML is column flexibility. Suppose there are two types of addresses in our application: home address and office address. This number can be increased or decreased anytime without changing much code. And using XSLT, we will not just create server controls, but also define their events which will work like a magic.

Requirements

I am assuming that the reader of this article has basic knowledge of XML, XSLT and ASP.NET.

Using the code

We will follow these steps to get things done:

  • Prepare the XML document
  • Prepare the XSLT document to transform the XML data
  • Write the C# code to instantiate the controls and event handlers

Consider the following XML:

<root>
  <Employee Id="1">
      <Address Caption="Address">
        <Home Caption="Home 1">
          <Street Caption="Street 1" Type="Text">Road#  27, House# 13, Banani</Street>
          <Street Caption="Street 2" Type="Text">
           </Street>
          <City Caption="City" Type="Text" Required="yes">Dhaka</City>
          <Zip Caption="Zip" Type="Text">1213</Zip>
          <Country Caption="Country" Type="CountryDDL">BD</Country>
        </Home>
        <Home Caption="Home 2">
          <Street Caption="Street 1" Type="Text">Sector-  10</Street>
          <Street Caption="Street 2" Type="Text">Uttara</Street>
          <Street Caption="Street 3" Type="Text">
           </Street>
          <City Caption="City" Type="Text" Required="yes">Dhaka</City>
          <Zip Caption="Zip" Type="Text">1230</Zip>
          <Country Caption="Country" Type="CountryDDL">BD</Country>
        </Home>
      </Address>
  </Employee>
  <Employee Id="2">
      <Address Caption="Address">
        <Home Caption="Home 1">
          <Street Caption="Street 1" Type="Text">J-13,  Road 27</Street>
          <Street Caption="Street 2" Type="Text">Banani</Street>
          <City Caption="City" Type="Text">Dhaka</City>
          <Zip Caption="Zip" Type="Text">1213</Zip>
          <Country Caption="Country" Type="CountryDDL">BD</Country>
        </Home>
        <Home Caption="Home 2">
          <Street Caption="Street 1" Type="Text">Michigan Avenue</Street>
          <Street Caption="Street 2" Type="Text">Suite 2800</Street>
          <Street Caption="Street 3" Type="Text">
           </Street>
          <City Caption="City" Type="Text">Chicago</City>
          <Zip Caption="Zip" Type="Text">60601</Zip>
          <Country Caption="Country" Type="CountryDDL">USA</Country>
        </Home>
      </Address>
  </Employee>
</root>

We have to show the addresses like below:

Article

Since there are multiple employee’s data in our XML document, we have to select the requested employee’s data among them. For this purpose, we have to create an argument list and need to pass the employee ID through the XSLT parameter.

//create argument list
XsltArgumentList xslArg = new XsltArgumentList();
xslArg.AddParam("employeeId",  "", ddlEmployee.SelectedValue);

//load the data
XPathDocument xdoc = new XPathDocument(Server.MapPath("Address.xml"));
//load Xslt
XslCompiledTransform transform  = new XslCompiledTransform();
transform.Load(Server.MapPath("DynamicControls.xslt"));
StringWriter sw = new  StringWriter();

//transform it
transform.Transform(xdoc, xslArg,  sw);

And, we will receive the argument from XSLT like below:

<!--<xsl:param  name="employeeId"/>-->
<xsl:param name="employeeId"/>

If we see look at the XML, then we will find that there is a ‘Caption’ attribute in each node. This is the caption of each value while showing the output. On the other hand, to give input, sometimes it is better to show a dropdown list rather than a traditional textbox. For instance, when the user has to choose country name, it is more meaningful to show a country list rather than a textbox. To fulfill this purpose, we have a similar attribute named ‘type’ in the XML nodes. And by inspecting this attribute, we can render the appropriate ASP.NET server control from XSLT.

<xsl:choose>
 <xsl:when test="translate($varType,$up,$lo)='countryddl'">
    <asp:DropDownList  id="{concat('ddlCountry',$rowindex)}" runat="server" 
    DataTextField="Text" DataValueField="Value">
          <asp:ListItem  value="{.}">
                <xsl:value-of  select="."/>
           </asp:ListItem>
    </asp:DropDownList>
 </xsl:when>
 <xsl:otherwise>
    <asp:TextBox ID="{$varId}" runat="server" 
       Text="{.}" width="205px" ></asp:TextBox>
    <xsl:if test="translate($isRequired,$up,$lo)='yes'">
          <asp:RequiredFieldValidator  ErrorMessage=" 
                Required Field" runat="server" 
    ControlToValidate="{$varId}" />
    </xsl:if>
 </xsl:otherwise>
</xsl:choose>

At last, we must declare a button to save the input data in XSLT:

<asp:Button  ID="btnSaveAddress" runat="server" BackColor="White"
   BorderColor="DeepSkyBlue" BorderStyle="Solid" 
   BorderWidth="1px" Font-Names="Tahoma" 
   Font-Size="10pt" Text="Save Data" />

Now, we have to set the event handler for this button from the code behind. The ParseControl function will make our work very easy by parsing the XML string to an ASP.NET server control. To get a reference of newly created controls, we have to call the FindControl method. As soon as we get the reference of the control, we can set the event handler for that control. One thing that is very important to know is that the event handler adding process should be after parsing the control. Because, before parsing, the control will not be available. Also, the parsing should be in the Page_Init event so that the controls will be available in the rest of the page life cycle.

//parse control
Control ctrl = Page.ParseControl(result);
phEmployeeAddress.Controls.Add(ctrl);

//find control to add event handler
Button btnSaveAddress = (Button)phEmployeeAddress.FindControl("btnSaveAddress");
btnSaveAddress.Click += new EventHandler(btnSaveAddress_Click);

We have almost covered everything. The most interesting thing is, using XSLT, our ASPX page will become very simple and clear. Here is the full ASPX source:

<%@ Page Language="C#" 
    AutoEventWireup="true" CodeFile="Default.aspx.cs" 
    Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head runat="server">
      <title>Dynamic ASP.net Controls Using Xslt</title>
  </head>
  <body>
      <form id="form1" runat="server">
      <div style="float: right; background-color: Yellow">
          <asp:Label ID="lblMessage"  runat="server" 
             Text="Label"></asp:Label>
      </div>
      <div>
          <asp:Label ID="Label1" runat="server" 
             Text="Choose  Employee"></asp:Label>
          <asp:DropDownList ID="ddlEmployee" 
                     runat="server" Width="128px">
              <asp:ListItem Value="1">Ehsan</asp:ListItem>
              <asp:ListItem Value="2">Ashraf</asp:ListItem>
          </asp:DropDownList>
           <asp:Button ID="btnLoadData" runat="server" 
               BackColor="White" BorderColor="DeepSkyBlue" 
               BorderStyle="Solid" BorderWidth="1px"  
               Font-Names="Tahoma" Font-Size="10pt" 
               Text="Load  Data" 
               OnClick="btnLoadData_Click"  /><br />
          <br />
          <asp:PlaceHolder ID="phEmployeeAddress" 
                    runat="server"></asp:PlaceHolder>
      </div>
      </form>
  </body>
</html>

All the XSLT controls will be extracted to the PlaceHolder, and here is the entire XSLT used to render the HTML and server controls:

<xsl:stylesheet  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:asp="remove">
    <xsl:output method="xml" indent="yes" 
       encoding="utf-8" omit-xml-declaration="yes"/>
    <!--<xsl:param name="employeeId"/>-->
    <xsl:param name="employeeId"/>
    <xsl:template match="/root">
      <xsl:for-each select="Employee">
        <xsl:if test="@Id = $employeeId">
        <table width="100%" border="0" 
               cellspacing="0" cellpadding="0" 
               bgcolor="#FFFFFF">
          <tbody>
             <tr>
               <td>
                 <xsl:apply-templates  select="Address">
                  <!--<xsl:with-param name="count" 
                           select="$count"/>-->
                 </xsl:apply-templates>
               </td>
             </tr>
             <tr>
               <td>&#160;</td>
             </tr>
             <tr>
               <td align="right">
                 <span style="margin-right:20%">
                   <asp:Button ID="btnSaveAddress" 
                     runat="server" BackColor="White"
                     BorderColor="DeepSkyBlue" BorderStyle="Solid" 
                     BorderWidth="1px" Font-Names="Tahoma" 
                     Font-Size="10pt" Text="Save Data" />
                 </span>
                 <span>&#160;</span>
               </td>
             </tr>
           </tbody>
        </table>
        </xsl:if>
      </xsl:for-each>
    </xsl:template>
    <xsl:template name="HomeAddress" 
             match="/root/Employee/Address">
      <table width="100%">
        <tr>
          <td height="30" colspan="2" align="left">
             <strong>
               <xsl:value-of select="@Caption"/>
             </strong>
           </td>
        </tr>
        <tr>
          <td height="2" colspan="2" 
                 align="left" bgcolor="#CCCC99"></td>
        </tr>
        <tr>
          <td width="50%" height="30" 
                    align="left" valign="top">
             <table width="100%" border="0" 
                     cellspacing="0" cellpadding="0">
               <tr>
                 <td colspan="4" height="4"></td>
               </tr>
             <tr>
                 <xsl:for-each select="child::*">
                   <xsl:variable name="rowindex" 
                          select="position()"></xsl:variable>
                   <td align="left" valign="top">
                     <table cellpadding="4">
                      <tr>
                        <td colspan="4" height="28" 
                                align="left" valign="top">
                          <strong>
                            <xsl:value-of select="@Caption"/>
                          </strong>
                        </td>
                      </tr>
                     <xsl:for-each select="child::*">
                        <xsl:variable name="varType" 
                             select="@Type"></xsl:variable>
                        <xsl:variable name="isRequired" 
                             select="@Required"></xsl:variable>
                        <xsl:variable name="varId" 
                           select="translate(concat(concat(concat(@Caption,'_'), 
                                         $rowindex),position()),'  ','_')">
                        </xsl:variable>
                        <xsl:variable name="up" 
                          select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
                        <xsl:variable name="lo" 
                          select="'abcdefghijklmnopqrstuvwxyz'"/>
                        <tr>
                          <td height="28" align="left" valign="top">
                            <xsl:value-of select="@Caption"/>
                          </td>
                          <td colspan="3" align="left" 
                             valign="top" height="28">
                            <xsl:choose>
                              <xsl:when test="translate($varType,$up,$lo)='countryddl'">
                                <asp:DropDownList id="{concat('ddlCountry',$rowindex)}" 
                                       runat="server" DataTextField="Text" 
                                       DataValueField="Value">
                                  <asp:ListItem value="{.}">
                                   <xsl:value-of select="."/>
                                  </asp:ListItem>
                               </asp:DropDownList>
                              </xsl:when>
                              <xsl:otherwise>
                                <asp:TextBox ID="{$varId}" 
                                     runat="server" Text="{.}" 
                                     width="205px" ></asp:TextBox>
                                 <xsl:if test="translate($isRequired,$up,$lo)='yes'">
                                  <asp:RequiredFieldValidator 
                                    ErrorMessage="Required Field" runat="server" 
                                    ControlToValidate="{$varId}" />
                                </xsl:if>
                              </xsl:otherwise>
                            </xsl:choose>
                         </td>
                        </tr>
                       </xsl:for-each>
                     </table>
                   </td>
                 </xsl:for-each>
              </tr>
             </table>
           </td>
        </tr>
      </table>
    </xsl:template>
</xsl:stylesheet>

Summary

ASP.NET server controls are very powerful in web applications without any doubt, and by combining XML and XSLT with it, we can make web applications more powerful, easier, efficient, and re-usable. Also, by using XML and XSLT, the application UI script will look clean and will be easier to maintain. I hope this will be a great start for those who want to make their site more dynamic and structured using XML and XSLT with the great power of ASP.NET controls. Enjoy!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here