Friday, 13 June 2014

User Controls Introduction

A UserControl is a separate, reusable part of a page. You can put a piece of a page in a UserControl, and then reuse it from a different location. The name, UserControl, might seem a bit fancy, but actually, it's just like a regular page, with an optional CodeBehind file. A notable difference is that UserControls can be included on multiple pages, while a page can't. UserControls are used much like regular server controls, and they can be added to a page declaratively, just like server controls can.

A big advantage of the UserControl is that it can be cached, using the OutputCache functionality described in a previous chapter, so instead of caching an entire page, you may cache only the UserControl, so that the rest of the page is still re-loaded on each request.

An example where a UserControl could come in handy, is a control for showing information about a certain user on a community website. In the next couple of chapters, we will create a UserControl from scratch, make it fit to our purpose, and then use it on a page.

Creating a UserControl


We will be building a UserControl for displaying information about a community user. First of all, let's add a UserControl to our project. In your Visual Studio, you should be able to right click on your project and select Add new item.. A dialog will pop up, and you should select the Web User Control from the list of possible things to add. Let's call our UserControl UserInfoBoxControl, with the filename of UserInfoBoxControl.ascx. Make sure that you have checked the checkbox which places code in a separate file, the so-called CodeBehind file.

You should now have a UserInfoBoxControl.ascx and a UserInfoBoxControl.ascx.cs in your project. The first is where we put our markup, and the second is our CodeBehind file. Now, if UserInfoBoxControl.ascx is not already open and selected, do so now. You will see only one line of code, the UserControl declaration. As mentioned, this control will be displaying information about a user, so let's get started adding some markup to do so:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="UserInfoBoxControl.ascx.cs" Inherits="UserInfoBoxControl" %>
<b>Information about <%= this.UserName %></b>
<br /><br />
<%= this.UserName %> is <%= this.UserAge %> years old and lives in <%= this.UserCountry %>



As you can see, it's all very basic. We have a declaration, some standard tags, some text, and then we have some sort of variables. Now, where do they come from? Well, right now, they come from nowhere, since we haven't declared them yet. We better do that right away. Open the CodeBehind file for the UserControl, that is, the one which ends on .cs.

As you can see, it looks just like a CodeBehind file for a regular page, except that it inherits from UserControl instead of from Page. We will declare the tree properties used in our markup, and base them on three corresponding fields.

private string userName;
private int userAge;
private string userCountry;

public string UserName
{
    get { return userName; }
    set { userName = value; }
}

public int UserAge
{
    get { return userAge; }
    set { userAge = value; }
}

public string UserCountry
{
    get { return userCountry; }
    set { userCountry = value; }
}


It's all very simple and works just like a regular class. You can even add methods, if you feel like it! Our UserControl is actually done now, but as you may have already experienced, we can't use it yet. A UserControl can't be displayed directly in the browser - it has to be included on a page.

Using a UserControl


 Pick a page in your project, or simply create a new one for the purpose, and open it. The first thing we have to do, is declare our UserControl. It can be done either in each page where it's used, or globally in the web.config file. There is no performance difference, but when declaring UserControls in the web.config file, the controls have to reside in a different directory than the page(s) using it.

For now, let's just declare it within the page. Add the following line below the standard page declaration:

<%@ Register TagPrefix="My" TagName="UserInfoBoxControl" Src="~/UserInfoBoxControl.ascx" %>


Make sure that the src value matches the path to your UserControl file. Now you may use the UserControl in your page, like any other control. For instance, like this:

<My:UserInfoBoxControl runat="server" ID="MyUserInfoBoxControl" />


If you look at the page now, you will see our UserControl in action, although the information will be a bit... limited. We will have to set a value for the properties we defined, for things to get just a bit more interestingly. Fortunately, it's very easy:

<My:UserInfoBoxControl runat="server" ID="MyUserInfoBoxControl" UserName="Pratik Panbude" UserAge="23" UserCountry="India" />

You see, every public or protected member can be accessed declaretively, allowing easy access to them when we use our control. However, with this specific UserControl, chances are that you will be receiving the information from an external resource, like a database, and then populating the UserControl from there. This usually involves the CodeBehind of the page, so how can we do that? Pretty simple, actually. In the CodeBehind of the page, try something like this:


protected void Page_Load(object sender, EventArgs e)
{
    // These values can come from anywhere, but right now, we just hardcode them
    MyUserInfoBoxControl.UserName = "Pratik Panbude";
    MyUserInfoBoxControl.UserAge = 21;
    MyUserInfoBoxControl.UserCountry = "Germany";
}

Loading dynamically

Sometimes you may wish to add UserControls to your page dynamically instead of declaring them. It's actually quite simple too. You need an existing control where you can add the UserControl to, for instance a Panel. If there's no logical control on your page to add it to, you may create one for the purpose - the PlaceHolder control is for situations just like that.

On your page, define it like this:

<asp:PlaceHolder runat="server" ID="phUserInfoBox" />


In the CodeBehind of the page, we add the control like this:

phUserInfoBox.Controls.Add(LoadControl("~/UserInfoBoxControl.ascx"));

We use the LoadControl method to instantiate the UserControl by specifying the path. This is very easy, but also very anonymous - because we just use the LoadControl method, we can't really use our own, custom properties. To do that, we need to make .NET aware of it. On the page, add the following declaration in the top:

<%@ Reference Control="~/UserInfoBoxControl.ascx" %>

Now we can access the UserInfoBoxControl class like if it were a regular class, which also means that we can typecast the UserControl returned by the LoadControl method to this type. In the next example, we do just that, then we set the properties, and at last, we add it to the PlaceHolder:

UserInfoBoxControl userInfoBoxControl = (UserInfoBoxControl)LoadControl("~/UserInfoBoxControl.ascx");
userInfoBoxControl.UserName = "Pratik Panbude";
userInfoBoxControl.UserAge = 28;
userInfoBoxControl.UserCountry = "Spain";
phUserInfoBox.Controls.Add(userInfoBoxControl);

This will come in handy, for instance when you're adding multiple instances of the same UserControl to a single page, because you can do it inside a loop.