Wednesday, July 14, 2010

Multiple Interchangeable User Controls on One Web Page

I'm building an ASP.Net web page in which there's a need to display any one of about twenty different user controls at any one time.  The contents of each user control is varied, with each holding a different assortment of labels, textboxes, dropdown listboxes, etc.  Assorted criteria on the page determines which user control is displayed.  The image shown on the left shows a trio of examples representing the [blue] web page and different [orange] user controls.

I don't have a lot of experience with ASP.Net user controls but when I have used them there'd typically be 2 or 3 on every page in the project, representing such things as a toolbar, a pulldown menu, a navigation menu, etc.  In those cases it was easy enough to just refer to the user control directly, performing a simple cast like this:

         ToolBar toolBar = (ToolBar)...

But the situation with this page is quite different.  With it I have a PlaceHolder control called "placeHolderSubForm" into which one user control at a time will be loaded.  Where the difficulty arises is when it's time to cast from a Control object to a specific User Control type.  For example, if the first user control shown were loaded into the web page then the cast might look like this:

UserControlA ucA = (UserControlA)placeHolderSubForm.Controls[0]

That works okay if there are one or two user controls to deal with but with 20 of them I immediately realized that the code would get rather unwieldy, with a whole lot of switch-case statements necessary to determine which User Control type to cast to.  I wanted something much more generic!

At the end of the day the interaction between the web page and each user control is fairly basic, consisting of:
  1. Passing some basic parameters to each user control.
  2. Retrieving a varied assortment of user entered data from each user control.
After much research I opted to construct a base class that each user control would be derived from.  It's still evolving but here's what it looks like so far:
public class UserControlBase : System.Web.UI.UserControl
    // Input Parameters (more to be added when required)
    public virtual int ContractIdx { get; set; }

    // Output Data - passed via SortedList
    public SortedList NewData = new SortedList();

    // Generic event handler to notify parent web page
    public virtual event EventHandler NewData_Handler;

In this way, within each user control I can add newly entered data to the general purpose SortedList container 'NewData' via a key & value pair.  Thus, one user control might retrieve the following data from a user:
  • Width: 5.0
  • Height: 7.0
  • Length: 144
  • Grade: 2.7%
  • Overtime: Yes
  • Crew: Alpha Prime
Then back in the web page the container can be retrieved like this:
SortedList newData = ((UserControlBase)placeHolderSubForm.Controls[0]).NewData;

Please note that I have posted this blog entry not as "the definitive way" to do this kind of thing but simply to throw out to the ASP.Net developer community what approach I've used.  I very much look forward to feedback from others about alternate approaches they prefer and will definitely modify things accordingly if I learn of a better practice.

No comments:

Post a Comment