User Controls
User controls are very like binary composite controls. However, instead of deriving from System. Web.UI.CompositeControl, they derive from System.Web.UI.UserControl. Perhaps a better description is that they're very much like miniature Web forms. The have a UI component (an .ascx file) that works with the Visual Studio designer, and they employ a matching class to manage the execution. However, unlike a Web form, they may be dragged onto the toolbox and then dropped into a Web form.
To get a good idea as to how Web User controls work, here's how to build the palindrome checker as a User control.
The Palindrome Checker as a User Control
Open the ControlORama project (if it's not already open). Highlight the ControlORama Web site within the Solution Explorer. Right-click on the site and select Add New Item. Select the Web User Control template and name the control PalindromeCheckerUserControl.ascx.
Notice that Visual Studio immediately drops you into the designer. User controls are designer friendly. Drag a Label, a TextBox, a Button, and another Label from the toolbox. Drop them into the User control like so:
Name the second label labelPalindromeStatus to distinguish it from the label applying to the text box.
Borrow the StripNonAlphanumerics and CheckForPalindrome from the PalindromeCheckerCompositeControl class.
protected string StripNonAlphanumerics(string str) { string strStripped = (String)str.Clone(); if (str != null) { char[] rgc = strStripped.ToCharArray(); int i = 0; foreach (char c in rgc) { if (char.IsLetterOrDigit(c)) { i++; } else { strStripped = strStripped.Remove(i, 1); } } } return strStripped; } protected bool CheckForPalindrome() { if (this.Text != null) { String strControlText = this.Text; String strTextToUpper = null; strTextToUpper = Text.ToUpper(); strControlText = this.StripNonAlphanumerics(strTextToUpper); char[] rgcReverse = strControlText.ToCharArray(); Array.Reverse(rgcReverse); String strReverse = new string(rgcReverse); if (strControlText == strReverse) { return true; } else { return false; } } else { return false; } }
Add the PalindromeFound event to the control class.
public event EventHandler PalindromeFound; // public event
Unlike binary composite controls, User controls aren't generated with any default properties. Open the code file and add a text member variable and a Text property, very much like the other composite control implemented.
private String text; public string Text { get { return text; } set { text = value; if (this.CheckForPalindrome()) { if (PalindromeFound != null) { PalindromeFound(this, EventArgs.Empty); } this.labelPalindromeStatus.Text = "This is a palindrome <br><FONT size=5 color=blue><B>" + text + "</B> </FONT>"; } else { labelPalindromeStatus.Text = "This is NOT a palindrome <br><FONT size=5 color=red><B>" + text + "</B> </FONT>"; } } }
Now add support for keeping track of palindromes. Add an ArrayList to the control class:
ArrayList alPalindromes;
Add a Table to the control. Switch to the PalindromeCheckerUserControl Design view and drag a Table onto the form.
Add a method to build the table of palindromes. It's very much like the one in the PalindromeCheckerCompositeControl, except the name of the table has changed. Table1 is the name given the table by Visual Studio.
protected void BuildPalindromesTable() { this.alPalindromes = (ArrayList)this.ViewState["palindromes"]; if (this.alPalindromes != null) { foreach (string s in this.alPalindromes) { TableCell tableCell = new TableCell(); tableCell.BorderStyle = BorderStyle.Double; tableCell.BorderWidth = 3; tableCell.Text = s; TableRow tableRow = new TableRow(); tableRow.Cells.Add(tableCell); this.Table1.Rows.Add(tableRow); } } }
Add support for keeping track of the palindromes in the Text property's setter.
public string Text { get { return text; } set { text = value; this.alPalindromes = (ArrayList)this.ViewState["palindromes"]; if (this.alPalindromes == null) { this.alPalindromes = new ArrayList(); } if (this.CheckForPalindrome()) { if (PalindromeFound != null) { PalindromeFound(this, EventArgs.Empty); } alPalindromes.Add(text); this.labelPalindromeStatus.Text = "This is a palindrome <br><FONT size=5 color=blue><B>" + text + "</B> </FONT>"; } else { labelPalindromeStatus.Text = "This is NOT a palindrome <br><FONT size=5 color=red><B>" + text + "</B> </FONT>"; } this.ViewState.Add("palindromes", alPalindromes); this.BuildPalindromesTable(); } }
Build and run the project. When you type palindromes into the PalindromeCheckerUserControl, it should look something like this:
Before leaving, take a look at the page with tracing turned on. Here you can see how the page/control hierarchy is laid out in memory.
Notice how similar the User control is to the composite control. Both composite-style controls nest multiple single controls. They're very convenient ways of grouping rich Web-based user interface functionality into single units.