Tuesday, July 27, 2010

Expanding the Usefulness of Global.asax

I've long utilized the 'Global.asax' file to run assorted startup methods, both from an Application and Session perspective.  One limitation of this file is that you can't introduce "using" statements like you can in any normal C# file.  This forces you to prefix every method and class with its full definition.  This isn't so bad but I've reached a point where I have more complex code I need to run and have grown tired of all those prefixes.  Frankly, I think they also make the code much less readable.

To resolve this issue I found this excellent blog post by Ross Nelson which explains how to modify things.  Essentially Global.asax is altered to contain just this one line:
<%@ Application Language="C#" Inherits="Global" %>
This then lets you create a new 'Global.cs' file in which all of the previous contents of 'Global.asax' are placed.

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.