Managed C++ and .NET Development: Visual Studio .NET 2003 Edition

User controls provide Web developers with a quick way to repeat the same little section of a Web Form on multiple Web Forms. You can create a user control once and then deploy it to as many Web Forms as you like. Something in the user control that gets changed immediately shows up in all Web Forms that use the user control. No longer do you have to wade through multiple Web Forms to make the same correction to all of them.

Here are five things that you need to know about user controls:

  1. User controls are basically the same thing as a Web Form, except they don't have an <HTML>, <BODY>, or <FORM> tag. This is because a Web Form is only allowed one copy of each of these, and the main Web Form where you inserted the user control will already have them. It also has a @ Control directive instead of a @ Page directive, though the contents of the directive other than the directive name would be, in most cases, the same.

  2. A user control has the suffix .ascx, which enables the compiler to differentiate between a Web Form and a user control. Also, it stops the compiler from generating an error for the missing aforementioned tags.

  3. By convention, a user control codebehind has the suffix .ascx.h, though truthfully you can use just about anything.

  4. The codebehind class is virtually the same as a Web Form's except that it is abstract and inherits from System::Web::UI::UserControl.

  5. A user control can't execute on its own. It has to be inserted into a Web Form to run. Personally, I like to lay out the Web Form using a table tag or Table control and then insert the appropriate user control into each table cell. This isn't required, though. You can use a user control just like any HTML or intrinsic control. Therefore, you can place a user control however you like on a Web Form.

Other than that, there isn't much to user controls.

Creating a User Control

Probably one of the most common user controls you will come across when developing Web Forms is the Header user control. Virtually every page on a Web site will have a header. It only makes sense that you create a control to display it, if only for the reason that if you need to change your header, you will only need to do it once with a user control.

Header.ascx (see Listing 14-19) and Header.ascx.h (see Listing 14-20) are the GUI design and codebehind for the simple Header user control found on my Web site http://www.contentmgr.com. You might recognize the code if you read my book, Real World ASP.NET: Building a Content Management System.

Listing 14-19: The ASP.NET GUI Design File Header.ascx

<%@ Assembly Name="WebForms" %> <%@ Control Inherits="WebForms.uc.Header" %> <asp:Image id=imgHeader runat="server"></asp:Image> <BR> <HR width="100%" SIZE="1">

Listing 14-20: The Codebehind Header.ascx.h

using namespace System; using namespace System::Web::UI; using namespace System::Web::UI::WebControls; namespace WebForms { namespace uc { public __gc __abstract class Header : public UserControl { private: String *level; protected: WebControls::Image *imgHeader; void OnLoad(EventArgs *e) { // Set the image based on passed header level imgHeader->ImageUrl = String::Concat(S"Images/", level, S".jpg"); UserControl::OnLoad(e); } public: // Create property to pass header level __property String *get_Level() { return level; } __property void set_Level(String *level) { this->level = level; } }; } }

Not much to it, is there? The only thing you need to note is the GUI design code for the user control can't contain any <HTML>, <BODY>, or <FORM> tags, and you use the @ Control directive and not the @ Page directive. Other than that, user controls and Web Form GUI design code are exactly the same.

Not much different from a Web Form, is it? First, I added another level to the namespace hierarchy, just to remind me that this is a user control. This is completely optional, but it helps me understand better where I am in the code.

The second and probably most important thing to notice is that the user control class inherits from System::Web::UI::UserControl and not System::Web::UI::Page. Because of this, you also have to call the UserControl::OnLoad() method and not the Page::OnLoad() method.

If you are observant, you may have noticed that you did not define the header's image URL within the design code. The reason is that you want to be able to change it based on which page it is currently heading. This dynamic functionality needs to be added to the codebehind.

The solution is elegant and very simple. Make anything you want passed to the user control a property. Then, if the user control is implemented statically within the GUI design file, pass the information as an attribute in the user control tag, or in the codebehind set the value using the property. On the other hand, if the user control is implemented dynamically, your only option is setting the property within the codebehind. You will see both of these methods later in the chapter. The code within the user control's codebehind to handle passed values is standard property logic.

Statically Implementing a User Control

As you can see in Listing 14-21, the static implementation of a user control is done entirely within the GUI design file. No changes are needed in the codebehind.

Listing 14-21: The ASP.NET GUI Design File Blank.aspx Implementing a User Control

<%@ Assembly Name="WebForms" %> <%@ Page Inherits="WebForms.Blank" %> <%@ Register TagPrefix="myUC" TagName="Header" src="/books/2/474/1/html/2/Header.ascx" %> <HTML> <HEAD> <title>Blank</title> </HEAD> <body> <form method="post" runat="server"> <myUC:Header Level="Home" runat="server"></myUC:Header> </form> </body> </HTML>

The first step in implementing a user control is to register it with the @ Register directive.

TagPrefix is used to ensure that the user control tag is unique and can be anything you want, so long as it abides by standard C++ variable-naming rules. For example, it is possible that you may have two user controls that have the exact same name, especially if you use third-party user controls. So, by prefixing these identically named user controls with different TagPrefixes, you will make the user control names unique.

TagName is an alias to associate the user control with its class. It should match the name you gave the user control when you created it.

Src is the name of the user control's GUI design filename. Src may also include a path. Unfortunately, it must be relative to the root directory of the Web application and can't be a URI.

<%@ Register TagPrefix="myUC" TagName="Header" src="/books/2/474/1/html/2/Header.ascx" %>

The second (and last) step is to place the user control within the form tag of your Web Form. Optionally, as I show in the example, you can pass a value to the user control using an attribute. The name of the attribute must match exactly the name of the property that you placed within your user control's codebehind.

<myUC:Header Level="Home" runat="server"></myUC:Header>

What if you don't know the name of the image you want to place in the header at design time? Or what if you need to calculate it based on some set of values? To solve these problems, you need to set the Image property of the user control within the Web Form's codebehind.

Listing 14-22 shows how to call the user control without any user control-specific attributes. Notice that the only difference is that the Level attribute is not specified.

Listing 14-22: The ASP.NET GUI DESIGN FILE Blank2.aspx Implementing a User Control

<%@ Assembly Name="WebForms" %> <%@ Page Inherits="WebForms.Blank2" %> <%@ Register TagPrefix="myUC" TagName="Header" src="/books/2/474/1/html/2/Header.ascx" %> <HTML> <HEAD> <title>Blank</title> </HEAD> <body> <form method="post" runat="server"> <myUC:Header runat="server"></myUC:Header> </form> </body> </HTML>

Listing 14-23 shows how to update the attributes within the codebehind.

Listing 14-23: The Codebehind Blank2.aspx.h

using namespace System; using namespace System::Web::UI; using namespace System::Web::UI::WebControls; namespace WebForms { public __gc class Blank2 : public Page { protected: WebForms::uc::Header *pgHeader; void OnLoad(EventArgs *e) { // set image to home in user control pgHeader->Level = S"Home"; } }; }

As you can see, the code is hardly rocket science. The only thing worth noting is that you use a definition to the user control within this class. Therefore, you need to define the user control before you define this class. In other words, make sure you place user controls before Web Forms in the linker file.

Figure 14-16 shows the user control header at the top of a blank page.

Figure 14-16: The user control header

Dynamically Implementing a User Control

The process of creating user controls dynamically is not difficult. It is just not obvious how it needs to be done. You would think that you could simply create a new user class with the new operator and you are done:

Header *header = new Header(); // Invalid code

If you were to compile the preceding code, you would get an error. Remember, I said earlier that a user control's codebehind class is abstract. Abstract classes can't be instantiated directly. In other words, you can use the new operator with them.

So how do you create a user control? The answer is, you don't. Instead, you load the user control using the Page class's LoadControl() method. The basic syntax of the LoadControl() method is as follows:

Control* LoadControl(String *virtualPathToControl);

Because the LoadControl() method returns a control, you need to typecast it to the specific user control type you are loading. Notice that I also stated that it takes a virtual path as a parameter. This means that it can take only paths with a root of the Web application. This means that a URI to the user control's .ascx file is not allowed:

Header *header = dynamic_cast<Header*>(LoadControl("Header.ascx"));

ManyHeadings.aspx (see Listing 14-24) and ManyHeadings.aspx.h (see Listing 14-25) are the GUI design and codebehind showing how to dynamically create user controls. This Web Form simply places two headers at the top of an otherwise empty Web Form.

Listing 14-24: The ASP.NET GUI Design File ManyHeadings.aspx

<%@ Assembly Name="WebForms" %> <%@ Page Inherits="WebForms.ManyHeadings" %> <HTML> <HEAD> <title>ManyHeadings</title> </HEAD> <body> <form method="post" runat="server"> <asp:Table runat="server" Width="100%"> <asp:TableRow> <asp:TableCell ></asp:TableCell> <asp:TableCell ></asp:TableCell> </asp:TableRow> </asp:Table> </form> </body> </HTML>

Listing 14-25: The Codebehind ManyHeadings.aspx.h

using namespace System; using namespace System::Web::UI; using namespace System::Web::UI::WebControls; using namespace WebForms::uc; namespace WebForms { public __gc class ManyHeadings : public Page { protected: TableCell *cell00; TableCell *cell01; void OnLoad(EventArgs *e) { Header *header; header = dynamic_cast<Header*>(LoadControl("Header.ascx")); header->Level = S"Home"; cell00->Controls->Add(header); header = dynamic_cast<Header*>(LoadControl("Header.ascx")); header->Level = S"Domain"; cell01->Controls->Add(header); } }; }

As you can see, there is no trace of the user controls in the GUI design file. However, I did create two cells to simplify the coding in the codebehind. Normally, you would probably create the cells programmatically within the code-behind as you saw earlier in the chapter.

Now that you know how to load user controls, the preceding code shows how easy it is to create them dynamically.

Figure 14-17 shows two dynamically created user control headers at the top of a blank page.

Figure 14-17: Two dynamic user control headers

Категории