Posts:
Creating custom server controls for use with ASP.NET websites.
Many developers have been lead to believe that building custom server controls for ASP.NET is difficult and extremely time consuming. In fact, building custom server controls is easy, it makes your code more reusable and cleaner, and will save you time in the end.
Suppose you want to load a drop down list or a check box list control on one or more of your web pages. You could put the list control directly on the page and write the code to load it, but then you would need to repeat this code on every page that you want to use the control on. Additionally, your web page code will be cluttered with code to load the list control. Ideally you want to only have the really important and relevant data processing code in your web pages and have the rest of the code to load data and lists in a separate place that is reusable and out of sight.
Here is a fairly simple example of a custom control that renders a CheckBoxList from a collection. I have chosen to load the list with CultureInfo objects (Langauges) from the System.Globalization namespace.
Let's take it step by step...
Step 1: Create a new website project in Visual Studio 2005 or Visual Web Developer.
Step 2: Add an App_Code folder to the website project.
Step 3: Create a new WebForm and name it TestServerControls.aspx, check the 'Place code in a separate file' checkbox before creating the WebForm.
Step 4: Open TestServerControls.aspx in the 'Source' view in Visual Studio 2005.
Step 5: Select all of the text (Ctrl-A) and paste the following code into TestServerControls.aspx.
<%@ Page
Language="C#"
AutoEventWireup="true"
CodeFile="TestServerControls.aspx.cs"
Inherits="TestServerControls"
%>
<%@ Register TagPrefix="cwc" Namespace="CustomWebControls" %>
<!-- add the Assembly attribute to the Register tag
if CustomWebControls is compiled into a dll.
Assembly="CustomWebControls" -->
<!-- Note:
see web.config <system.web><pages><controls>
for addition control declarations -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Test Custom Server Controls</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<div style="width:350px;height:120px;overflow:auto;border:solid 1px silver;">
<cwc:LanguageCBL runat="server" ID="cblLanguages" Width="100%" Font-Size="8pt" AutoLoad="true" />
</div>
<br />
<asp:Button runat="server" ID="btnSubmit" Text="PostBack" />
<br />
<br />
<span>Selected Languages:<br /></span>
<asp:Label runat="server" ID="lblSelections" Text="" />
</div>
</form>
</body>
</html>
Step 6: Save TestServerControls.aspx (Ctrl-S).
Step 7: Open the code file for the WebForm, TestServerControls.aspx.cs.
Step 8: Select all of the text in the code file (Ctrl-A) and paste the following code into TestServerControls.aspx.cs.
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;
public partial class TestServerControls : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
this.btnSubmit.Command += new CommandEventHandler(btnSubmit_Command);
}
void btnSubmit_Command(object sender, CommandEventArgs e)
{
StringBuilder sb = new StringBuilder();
foreach (ListItem itm in this.cblLanguages.Items)
{
if (itm.Selected)
{
sb.Append(itm.Text);
sb.Append("<br/>");
}
}
this.lblSelections.Text = sb.ToString();
}
}
Step 9: Save TestServerControls.aspx.cs (Ctrl-S).
Step 10: Create a Web.config file for your project. (Right click on the project in the Solution Explorer and select the 'Add New Item...' menu. Select the 'Web Configuration File' from the list of Installed Templates. Leave the name of it set to the default value of Web.config. Click Add.)
Step 11: Select all of the text in the Web.config file (Ctrl-A) and paste the following code into Web.config.
<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<pages>
<controls>
<add tagPrefix="cwc" namespace="CustomWebControls"/>
</controls>
</pages>
<compilation debug="true"/>
<authentication mode="Windows"/>
</system.web>
</configuration>
Step 12: Save Web.config (Ctrl-S).
Step 13: Create a new class file named 'LanguageCBL.cs' in the App_Code folder. (Right click on the App_Code folder and select the 'Add New Item...' menu. Select Class from the list of Installed Templates. Set the name of the class to 'LanguageCBL.cs' and click Add.)
Step 14: Open LanguageCBL.cs and select all of the text in the file. Paste the following code into LanguageCBL.cs.
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Globalization;
namespace CustomWebControls
{
public class LanguageCBL : CheckBoxList , INamingContainer
{
private bool _autoLoad = true;
public bool AutoLoad
{
get { return _autoLoad; }
set { _autoLoad = value; }
}
protected override void OnLoad(EventArgs e)
{
if ( this.AutoLoad && !this.Page.IsPostBack )
{
this.LoadData();
}
base.OnLoad(e);
}
public void LoadData()
{
this.Items.Clear();
ListItem itm = null;
string name = null;
CultureInfo[] cultures = null;
cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach ( CultureInfo ci in cultures )
{
name = ci.Name + " [" + ci.EnglishName + "]";
itm = new ListItem(name, ci.LCID.ToString());
this.Items.Add(itm);
}
}
}
}
Step 15: Save LanguageCBL.cs (Ctrl-S).
Step 16: Right click on the TestServerControls.aspx file in the Solution Explorer. Select the 'Set As Start Page' menu item.
Step 17: Run (Start Debugging) the website project.
Step 18: Check several of the languages listed in the check box list.
Step 19: Click the 'PostBack' button.
Step 20: Observe that the selected language names have been written to the Selected Languages label after the post-back is complete.
That's it!
Notes:
1) When you build custom server controls it is a very, very good idea to always implement the INamingContainer interface. This interface does not have any methods to implement, just add it to the class declaration. INamingContainer will eliminate any problems of controls inside your custom control having the same IDs as controls on the WebForm.
2) This example uses a CheckBoxList but you can use any List Control that you want, DropDownList, RadioButtonList, etc.
Hi
Very good code.
I am having one doubt is it possible to add controls without using web config. means I want add the checkbox and Dropdown control to panel in all the pages I have created the controls using above code.
I want to add both controls in all pages but I didnt want to design time. I wnt to add both the controls to panels in runtime in cs page.
Is it possible? please tell me how to do it.
Hi kanns1234,
If I understand, you don't want to make changes to the web.config file - is that correct?
If you have the following on each page:
<%@ Register TagPrefix="cwc" Namespace="CustomWebControls" %>
you don't need to make changes to the web.config file <controls> section.
If you only want to add ASP.NET controls (not your own custom controls) it is easy, you just write the code to dynamically add them and there is no need to modify the web.config file or have the Register declaration shown above.
You could create a class with a static method that takes a Panel as an argument and the method could create the controls add them to the Panel.Controls collection. Then you could call the static method in the Page_Load event handler on each web form and pass in the panel object that you want the controls to be added to.
I hope this helps and let me know if you have more questions.
-Jeff
Hi Jeff,
Thank you.
I have created panel as an Static method and added all the controls I needed. Now I have added gridview and button inside that panel method. How I can trigger paging event of gridview and button click event from other page to this class file.
Thanks,
Kannappan.
Hi Kannappan,
First thing - the information in my last post is not quite correct. If you want to create any controls dynamically (asp controls or your own) then you don't need to change the web.config file and you don't need the Register statement in the page. If you want to create your custom controls in the .aspx or .ascx file, then you need to have one of these things so .NET can figure out what assembly to use to load the control
Ok, now to your question... Loading controls dynamically is a bit tricky when you get to handling postbacks. You should make sure that your control is loaded in the Page_Load event or before the Page_Load event so the control will exist when the page starts processing a postback. The tricky part is that you don't want to reload the control everytime if it comes from a database and you don't want to reload it and lose the user's selections. There are 2 keys to getting this to work - set an ID on the control and add it to the web forms control tree (add it to a control that is already in the control tree).
By default most controls save their data in the ViewState so it will automatically be reloaded before the postback. In this case you can always create the controls (during get and post operations) but only load the data on the initial get. Try this to see if your postback events start working.
-Jeff
Hi Jeff,
Thaks again for the Replay.
I have not registered the PANEL assembly in web.config. as you mentioned I am calling the PANEL class from the aspx page. I am handling the page load event based on my requiremnt.
But the problem I am facing now is I have added the gridview and button inside that PANEL class. Now I didnt know how to call and write button click and Paging event inside the PANLE class in aspx page. Please help me.
Kannappan
When you create the control and add it to the web form dynamically you can do the following to hook up the postback events:
ctrl.EventName += new EventHandler(crtl_EventName);
and then create a method 'ctrl_EventName' with the code that you want to run when the event fires.
I can't give you any advice on how to use the GridView because I don't use it for a number of reasons. One reason is that I like to create controls dynamically and the Template controls make that really hard to do. I also like to maintain more control over my web pages and I have found it hard to work with controls like the GridView because many of the web pages that I create for clients have very specialized needs and I would end up struggling to try to get the GridView to allow me to create the page the way I want to. I just render the data and controls into a Table control instead which gives me total control over the layout etc.
-Jeff
Hi Jeff,
I am creating the custom control with registering the control in web.config. As you mentioned above in this format.
<add tagPrefix="cwc" namespace="CustomWebControls"/>
But it displays error for not specifying Assembly for the above control. All the other controls showing error, so I added below to fix error,
<add tagPrefix="cwc" namespace="CustomWebControls" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
Whether this is right or we can do in some other way please help me
Regards,
Kannappan.
Hi Kannappan,
Sorry for the delay in getting back to you...
This seems like an unusual solution because the System.Web.Extensions.dll is for AJAX.NET and nothing in this code uses AJAX.NET but I don't know if your project is using it. Did you put an AJAX.NET control inside your server control? If so that might be why this is happening.
I think that I would change the control declaration to the following standard for AJAX.NET and see if it continues to work:
<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
I hope this helps!
-Jeff
Hi jeff,
Thanks. I know that is required for AJAX.Net controls. See Below code in this way I have declared the controls
<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add tagPrefix="cwc" namespace="CustomWebControls"/>
As you mentioned in the above sample of creating the custom control.
After assigning the above code to web.config file. When I see the designer aspx page no control (norm asp.net controls) is loaded up it displays the error that "assembly cannot be empty" for the control.
When we are adding the custom control in web.config file it asks for the assembly. What I have to specify for the custom control assembly. Since we are only having tagPrefix and namespace in our custom control definiton in web.config.
Please guide me thru wat I have to specify for Assembly in custom control.
Hi - please answer these questions so I can get a better idea of what the problem might be:
1. Are you using Visual Studio or Visual Web Developer?
2. If you are using Visual Studio, is your project a "website" project?
3. Does your custom control contain an AJAX.NET control or is it contained inside an AJAX.NET control?
Thanks,
Jeff
Hi Jeff,
1. Yes I am using Visual Studio.
2. I am using Guidance Package Web Client Factory which will create solution folder with website and C#
3. I am just creating normal asp controls such as grid, label, textbox.
Without giving assembly to the webconfig custom control declaration every functionality is working fine. Only problem I ant see any controls in design view with all the controls showing cant able to load due to assembly is empty error.
Kannappan.