Software applications often provide different functionalities to different users. For instance, an application will give an administrator role access to more features than it will to a typical user role. Changes to the application's user interface (UI) inevitably accompany these role-based changes in the application's functionality—and the UI changes may go beyond simple things such as enabling and disabling buttons. In fact, if role capability is different enough, an application may require a complete makeover. Whole sections of Web pages may disappear between roles, for example. Moving the positions of certain controls may be necessary when other controls are hidden from the user.
To implement UI changes based on role changes, you typically begin by implementing sets of user controls for your Web Forms. You could code separate Web Forms for each role, but why write redundant code when you can compose your page from user controls? Most likely, you will vary your role functionality by making user controls visible and invisible, or you will dynamically create user controls. To represent the different role-states, you normally implement enum values along with a switch statement to execute code based on the application's role-state. When a Web Form is loaded, each user control interrogates the current role-state and then executes the appropriate instructions based on the particular user control switch statement.
At this point, your solution contains a number of switch statements. For a small application, the number of switch statements does not result in a large amount of code. For a larger application with many user controls, the amount of code resulting from the switch statements can become significant. Common user controls save some coding, but how do you eliminate the repetitive switch statements? With an understanding of the controls collection and a little recursion, you can craft a solution with a single switch statement.
The Controls Collection
Utilizing the Controls collection on a Web Form page object is the first key to implementing the single switch statement solution. A Controls collection contains all of the child controls of a given control object. The control object is a base class for server controls, user control objects, and page objects. A Web Form page object is derived from a TemplateControl object, and a TemplateControl object is derived from the Control object.
A Controls collection implements the IEnumerable interface and, therefore, allows iteration using the foreach statement. The following is a simple example of iterating through the Controls collection on a server control object:
foreach (Control cNext in c.Controls) ( pv = new PageSecurityRoleSetup (); pv.SetupControl (lb, cNext,level+1); //Recurse to next set //of sub-cont VisitTheControl (level, cNext); )
As stated previously, server controls, user controls, and Web Forms are all derived from the Control class. So, as you iterate through the Controls collection, how do you distinguish a regular server control from a control that implements role-state behavior? The answer lies in a C# operator.
C# has a simple but powerful operator called "is" that allows a developer to determine whether a class implements a particular interface or is derived from a particular class. The "is" operator can be used in if-then statements, as in the following example:
if (c is IPageUserSetup) ( WriteToList ("FOUND ONE: " + c.ToString(),level); ipagesetup = (IPageUserSetup)c; InvokeRoleSetup ( ipagesetup ); )
With the "is" statement, you have the following two options for separating .NET Framework server controls from server controls that must implement your role changes:
- Create a common base class (for user controls or Web Forms) that implements your role changes. All classes implementing role changes must be derived from this base class. Although perfectly acceptable, this solution is inflexible. C# allows you to derive a class only from one base class. Creating a single common base class may force you to create groups of intermediate common base classes. Common base classes also force you to create separate implementations for Web Forms and user controls.
- Create an interface. Like a class, an interface is a contract. A class derived from an interface must implement all of the properties and functions declared in the interface. Unlike the common base class solution, an interface is flexible. Derived user controls and Web Forms can both implement the same interface. An interface implementation would allow you the flexibility to implement Option #1 if a group of user controls behaved in a similar fashion.
The following is an example of a typical interface declaration:
public interface IPageUserSetup ( void DoSec1 (); void DoSec2 (); )