Representing ASP.NET server controls in a custom page or
user control class can be a double-edge sword for several reasons. By adding
properties or fields that represent ASP.NET server controls, this often couples
the custom page class to the ASP.NET page it represents. This may not be a bad
thing overall, but it will require more work to utilize its full effect. I am
currently working on some code to make this implementation approach easier to
work with, and that might be the subject of a future article. For now, we will
be taking this approach, seen as a variant to the front controller or page
controller pattern. Check out the properties below.
Listing 12
public class SignupPage : PageBase
{
protected abstract TextBox EmailAddressBox { get; }
protected abstract TextBox NameBox { get; }
protected abstract RadioButtonList NewsletterSignupList { get; }
}
Instead of properties, examples using page or front
controller use protected fields as you did in ASP.NET 1.1. Because the
approach that I use is not using Web Application Project (WAP), to expose
controls to the custom page class requires the use of properties. These
properties are overridden and return the real components for each property.
Listing 13
<%@ Page CodeFile="signup.aspx.cs" Inherits="Mains.Examples.InboxASPXPage" %>
<table>
<tr>
<td>Name:</td>
<td><asp:TextBox id="txtName" runat="server" /></td>
</tr>
<tr>
<td>Email:</td>
<td><asp:TextBox id="txtEmail" runat="server" /></td>
</tr>
<tr>
<td>Newsletter Signup?:</td>
<td>
<asp:RadioButtonList id="rblSignup" runat="server">
<asp:ListItem>Yes</asp:ListItem>
<asp:ListItem>No</asp:ListItem>
</asp:RadioButtonList>
</td>
</tr>
</table>
public class InboxASPXPage : SignupPage
{
protected override TextBox EmailAddressBox
{
get { return txtEmail; }
}
protected override TextBox NameBox
{
get { return txtName; }
}
protected override RadioButtonList NewsletterSignupList
{
get { return rblSignup; }
}
}
This ASPX page inherits from the custom signup page above,
implementing the protected properties and returning the appropriate control.
The reason those properties add additional opportunities are because the custom
page class can do something like this below:
Listing 14
protected override void OnLoad(EventArgs e)
{
if (!Page.IsPostBack)
{
this.NewsletterSignupList.Items.Add("Yes");
this.NewsletterSignupList.Items.Add("No");
this.NameBox.Text = this.GetProfileValue < string > ("Name");
}
}
Because the controls of the page are exposed in this
fashion, the custom page class can perform whatever interaction it needs to do.
Notice that the page loads the default list of items. This could be something
more complex as checking with a back-end reservation system and creating a
dynamic page, creating a data-driven web site, or something simpler.
In the previous sample, the ASPX markup defines a list of
items; however, removing the code from that markup and adding them to the
code-behind OnLoad method adds a good benefit: the list will always have a
common set of known, standard values that the custom page definitely knows
about.
From this, it is possible to create a unit test like the one
below. The test inherits from the abstract page class and implements the server
control properties with dummy controls. That is why it is nice to setup some of
the server control properties in this custom code-behind page, as shown above.
Listing 15
[TestFixture]Public class SignupPageTest: SignupPage
{
Private TextBox txtEmail = new TextBox();
Private TextBox txtName = new TextBox();
Private RadioButtonList rblSignup = new RadioButtonList();
protected override TextBox EmailAddressBox
{
get
{
return txtEmail;
}
}
protected override TextBox NameBox
{
get
{
return txtName;
}
}
protected override RadioButtonList NewsletterSignupList
{
get
{
return rblSignup;
}
}
[TestFixtureSetUp]Public void Initialize()
{
this.OnInit(EventArgs.Empty); //Raises init event
this.OnLoad(EventArgs.Empty); //Raises load event
}
[Test]Public void TestInitialValues()
{
Assert.AreEqual(2, this.NewsletterSignupList.Items.Count);
}
}