Building ASP.NET User and Server Controls, Part 2

By Solomon Shaffer

In my first installment, we explored the creation and implementation of user controls. These controls encapsulate code and HTML into smaller more functional units. User controls are built very similar to ASP.NET Web forms but are placed on the hosting page as objects. The controls can then interact with each other. It is important to note that user controls are created and edited just like any other page in ASP.NET. The HTML and code-behind files are freely viewable and editable. But what if you want to sell your controls, or for some other reason, limit access to the code the control contains? You may also want to encapsulate the control in a more concise manner. You may want to distribute only one file, not the three files created with user controls, to the other developers on your team. Or, you may want to distribute the control as a single file that can be added to the IDE toolbox just like the built-in ASP.NET server controls. Since user controls must contain an HTML based ascx file, and the codebehind must be compiled in the assembly, user controls are not a viable option. Enter custom controls. While more complex and time consuming to create, custom controls (or sometimes called composite controls) afford you greater flexibility with all the advantages mentioned above.

What Is An ASP.NET Custom Control

In contrast to a user control, a custom control is boiled down into one compiled class. The interface (HTML and JavaScript) is written out programmatically instead of being visually created in an IDE. You can blend the richness of the .NET programming model in your code with as complex of an interface as need be. Because a custom control is contained in a class, you have access to all the functionality of the .NET Framework, properties can be defined, and functions can be implemented. In fact, the server controls that ship with ASP.NET and Visual Studio.NET are in essence, custom controls. They are compiled classes that when placed on a page, interact with each other, interact with the page (take advantage of events like OnLoad), emit HTML and script, and provide the power behind the ASP.NET technology.

The only difference between Microsoft's pre-built server controls and our custom controls is that they are pre-registered in the IDE for use (the System.Web.dll file is registered in the toolbox), and references in the HTML are implied (as discussed with user controls). Obviously, Microsoft's controls are very thought out and are designed to work together efficiently. For instance, the SQLDataAdapter, DataSet, and DataGrid controls work very closely with each other. Your custom controls are more likely to focus on one particular piece of functionality and not worry about interaction to this degree. So let's get down to building our control, registering it with the IDE for use (we will even define an icon for use in the toolbox), and placing the control on a page for rendering.

Creating a Sample Custom Control

In this article, we will create one custom control. I will try to make the control broad enough to cover a number of different areas and issues. For this example, we will create a visual HTML container that could be used to surround a piece of functionality (possibly even another custom or server control) in a page. The container will have a title on top, borders surrounding the left, right, and bottom sides, and a collapse button placed in the header. The collapse button will expand or collapse the control with some JavaScript. This type of control would be useful where the page is broken down into portal-like chunks of data or functionality. By using this container control when you have multiple controls on a page, you could promote a consistent look and feel to your site.

For clarity, both examples are written in C# and the full source code is available for download.

First, we need to create a new project. Open the VS.NET IDE, click the New Project button, and select a Web Control Library in the Visual C# Projects folder. Name the project "BuildingCustomControls" and click OK. The IDE will create a new project (remember that this is not an ASP.NET project so an IIS Web folder will not be created) and a very bare-bones project is created with only two files and three references. A skeleton file is created and displayed for you. Close and delete this file. Right-click on the project and click Add - Add New Item and select a Web Custom Control. Name the control "CCContainer" and click Open. The new file contains our new class name (which needs to be descriptive and will be referenced later) and is within our namespace (also should be descriptive and will be referenced later - in our case, BuildingCustomControls). The file you just created should be open in code view. You now have a clean slate with which to build.

Notice that our control inherits from System.Web.UI.WebControls.WebControl. This allows us to tap into the page's event model and all the goodies associated with the creation and destruction of a Web control. Also, notice the explicit attributes specified above the class declaration. The DefaultProperty attribute specifies the default property of the component (as the name implies). This is the property that is set when a value is applied to the component and no specific property is defined. We also have an attribute called "ToolboxData." Since we must place these controls on the page and register them in the HTML (registration is not implied as with ASP.NET server controls), default tag prefixes and names may be defined. This is very similar to adding a user control to the page (See Building ASP.NET User and Custom Controls, Part 1). These tag values will be automatically registered and placed in the HTML when the control is dragged onto the page from the toolbox. The "{0}" tag prefix denotes that the tags prefixes will be automatically created unique by the IDE. It is best to leave this prefix tag alone and let the system handle it. We also have the "runat=server" text to ensure that this control renders server side (we will get a runtime error if it is not present). We will also add an attribute called "ToolboxBitmap." This value will specify the icon bitmap to use in the IDE toolbox. The bitmap should be 16x16 pixels in size and somehow represent your control in graphical format. Also, the path to the icon must be an absolute path with a drive letter specified. Relative paths to the bitmap (i.e. \images\icon.bmp) will produce a runtime error.

The attributes above the class declaration indicate how the control will behave.
Figure 1 - The attributes above the class declaration indicate how the control will behave.

Next, we will declare our public properties of the component. We will have three public properties, all of which will describe how the control will appear rendered. The first property is the container's contents. This is a text property that will be displayed within the body that lies between the borders of our container. This property could very well be plain text or HTML (perhaps an <iframe> tag pointing to another page). The second property is the title text displayed in the container header. The final property in this example is the container width. This property's datatype is a "struct" declared in the System.Web.UI.WebControls.WebControl namespace. A struct is a user defined value type tailored to suit a specific need. In this case, we can specify "px," "%," etc. as our unit of measure, and the control will understand how to use these measurements. The properties are accessed through the traditional get and set routines. In our example, we are not using default values for our properties, although this could be easily implemented.

The properties are declared using the proper data types
Figure 2 - The properties are declared using the proper data types and accessed through get and set routines.

We now can concentrate on the output of the control. The idea for a custom control is to emit HTML and script to the page in an encapsulated unit. This means that the JavaScript must be written inline with the control (as opposed to within the header). All HTML will be place inline within the page as well. It is up the creator to emit the correct HTML and script to run properly in the browser. You could very well have two sets of HTML and output only one of them based on the browser the user is running.

Microsoft takes this into account with their server controls. First, they query the user's browser for capabilities and type. Types include IE, Netscape, PocketPC, cellphone, Palm, etc. Based off the capabilities and the browser type, the server control will emit the proper HTML for that machine. If the browser does not support client-side JavaScript, the control will not emit JavaScript and deal with interactivity another way. If the HTML renders differently on browser type A than on browser type B, the control will account for these differences. One great example of this is the MobileControls shipped with the Mobile Internet SDK. These controls are capable of emitting an entirely different interface based off the brand or type of cell phone or PDA they are targeting. The developer must take into account all these scenarios for a robust control.

For our control, we will create two functions. Both of these functions will take the properties we declared above as parameters and will return a StringBuilder object that contains HTML. The first function will build the header HTML, JavaScript, and define the styling. The second function will build the HTML for the borders and footer. To ensure cross-browser HTML, the developer could build the HTML programmatically with HTML objects. While this could ensure correct cross-browser HTML, the code to create the HTML DOM could get quite cumbersome with a sizeable control. In our example, the HTML will be manually written out and appended to a StringBuilder object.

HTML created programmatically.
Figure 3 - HTML created programmatically.

When dealing with large strings, it is recommend that you not concatenate the text with the "x = x + y" approach. This is especially true when you have a number of text files that you are combining. Each new string that is created holds a memory space and must wait for garbage collection. This can be very expensive and can deteriorate performance substantially in our case where we are creating a large HTML string. Instead, we will use a StringBuilder object. With the StringBuilder, we allocate one chunk of memory for our object and add text to it. The StringBuilder object is located in the System.Text namespace, so it will have to be referenced in your code. Remember to use single quotes within your JavaScript so you do not confuse the compiler.

Our two functions build the HTML string and return StringBuilder objects.
Figure 4 - Our two functions build the HTML string and return StringBuilder objects. Notice the style sheet and JavaScript is inline with the HTML of our control.

Next, we need to call these functions. Since our control inherits from System.Web.UI.WebControls.WebControl, we can tap into the event lifecycle of the page (see my article on The ASP.NET Page Life Cycle for more information). Since we have this luxury, we will override the Render event and call our functions from there. We will use the "output.Write" function to send our markup to the browser. We call the first function (passing in our parameters set with our properties and getting our HTML back in a StringBuilder object), insert the sContextText variable set in our ContentText property, and call the second function to build the borders and footer. The overridden Render event takes a single argument called "output."

The Render event is overridden
Figure 5 - The Render event is overridden and our HTML building functions are called and outputted.

Our control should now be complete and compiled successfully. Click the Build Solution button and the code should compile into a single file called BuildingCustomControls.dll (based off our namespace that we defined).

Registering and Using the Control

Now we can use the control on a page. Open a new instance of the VS.NET IDE, click the New Project button, and select an ASP.NET Web Application in the Visual C# Projects folder. Name the project "UsingCustomControls" and click OK. The IDE will create a new Web project.

We now want to register our control in the toolbox, so we can simply drag it onto the designer. Right-click on the toolbox and select Customize Toolbox. Select the .NET Components tab (since our control is a .NET assembly, not a COM component) and click the Browse button. Navigate to the BuildingCustomControls project that we created and drill down into the bin/debug folder (if you built our custom control project in "release" configuration, you will see a "release" folder also). There you should find our BuildingCustomControls.dll component. Select the BuildingCustomControls.dll file and click OK. You should now see our control with our custom icon in the toolbox.

The CCContainer
Figure 6 - The CCContainer (derived from the CCContainer class) component is now located in the toolbox.

Drag the control on the body of the open Web form and click View In Browser. You should get a parser error stating that one of the dependencies was not found. This is because while we added the control to the toolbox, the code is unreachable by the CLR. We must set a reference to the component in our project and import the class. To do this, right-click on the References folder in the solution explorer and click Add Reference. The displayed list shows .NET components that are recognized by the IDE. Our component is not in this list yet, so click on the Browse button. Again, find the .NET component called BuildingCustomControls.dll that we discussed earlier. Click Open, click OK. We now have a reference to our control in the References folder. Refresh the browser see if the control renders (there is no need to recompile since the control is already compiled into a dll file).

The reference to our control is added.
Figure 7 - The reference to our control is added. Now we can access the code in the BuildingCustomControls namespace.

You should now get some rendered HTML with broken images. This is because we reference several images in our control and specify relative paths to those images (i.e. images/ CCContainer_arrow_open.gif). We now have the control in a context that leaves these paths unresolved. There are three fixes to this problem. One is to import the images folder into the Web application so that the paths in the HTML are valid. Another would be to make the paths fully qualified and absolute in the control code. This would ensure that paths are valid regardless of where the images were located. Third would be not to use images at all in our custom control at all. Images in our control were included for example, but it is recommended that developers keep their controls self contained and not dependent on any outside resources that they do not have control over (such as images or external style sheets not created and placed in a setup routine). Microsoft has opted to included icon images for their controls, but the HTML rendered from these controls contains no images. The entire presentation is created with markup. For our example, I have included the images folder in the example project.

Next, we set the control properties. This topic is covered in Building ASP.NET User and Custom Controls, Part 1. Insert Width="80%" Title="This is the title" into the control declaration in the HTML. This will set the width and title properties.

The Width and Title properties set in the HTML.
Figure 8 - The Width and Title properties set in the HTML.

You can also set properties at runtime in the code behind file by inserting CCContainer1.ContentText = "This is the body"; into the Page_Load event.

The ContentText property is set in the code.
Figure 9 - The ContentText property is set in the code.

Build the project and click View in Browser. The control should render and behave correctly now. Click on the arrow to expand and collapse the control. Right-click on the page and view the source of the document. The JavaScript and styling is rendered inline with the HTML in the control.

The custom control rendered in IE.
Figure 10 - The custom control rendered in IE.

Conclusion

While this control is quite simple, it is a good example of how custom controls can be bundled up into tidy components that can be distributed and used with ease. We will see a large commercial market open up with a variety of custom controls in the future. It may also be a common practice for developers to package their own custom controls for distribution within their own team. The ease of use and versatility make custom controls a very powerful tool.

Appreciation

I would like to thank my wife for her support through the years.

About the Author

Solomon Shaffer has been in the information technology industry for over five years. Recently, he founded Cynthetic, Inc., a software-development practice focused on .NET and Microsoft Internet technologies. Solomon's areas of expertise include COM development, ASP, SQL Server, and UI layout / design.

At press time, Solomon is working on a contract basis in the Atlanta area building the next-generation Web applications using the .NET platform. He has over 1 year of enterprise .NET development experience, developing enterprise applications with the platform since its Beta 1 release as part of the Early Adopters Program.

Solomon and his wife reside in Alpharetta, GA. He can be reached at solomon.shaffer@cynthetic.com.



Downloads

Comments

  • uno de los estilos GHD están en descuento

    Posted by leedge776 on 07/18/2013 04:23am

    Esto es a menudo debido a sus herramientas de diseño, y ahora Barber Shop es la peor opción, ya que ahora tienen que hacer cola, si se podía hacer hasta que el cabello, se puede sentir el efecto no es muy buena, lo que afecta Imagina tenías el pelo. Cómo hacer esto, no quiero volver a hacerlo otra vez? Planchas ghd que no lo hacen porque diseñador tiene un concepto único diseñado para permitir a más personas a hacer su peinado favorito, sino también a sí mismo. Planchas ghd ahora, es que la gente piensa que es una varita mágica. Capaz de sorprenderme cada øjeblik.Mange gente compra en línea ghd, la razón principal es barato, pelo ghd tan barato cada vez más popular, y proporcionamos a los expertos venta ghd más profesionales, tenemos un equipo fuerte dedicada plancha ghd adquisición, presentación, promoción, etc, que se actualizará cada día, productos alisadores GHD todos los días, terminando nuestros pedidos ghd. Así usted compra nuestros productos ghd, seleccione su información personal clave. Para más información consulte las preguntas frecuentes, etc. Espero que compras felices en nuestro sitio web [url=http://cheapghdoutlet.jimdo.com/]planchas ghd baratas[/url] La ciudad industrial del siglo XIX y la construcción de puertos, el rápido desarrollo económico, la convierten en la segunda mayor ciudad del país, Aarhus es una ciudad comercial Jutlandia, Noruega y Dinamarca también se conectan otros medios de transporte de la ciudad hub.Clean y hermosa ciudad de Aarhus, el paisaje rural de Europa, El edificio formado número de único e innovador bygninger.fordi diseño de su ubicación geográfica y los residentes locales entusiastas culture.Aarhus amor siempre ha sido el centro cultural de Jylland.Vores línea planchas ghd para la venta, la cerámica lineal, muy bueno para proteger tu cabello se ve muy buena resistencia al calor. Rápidamente se calienta, en el transcurso de 2-3 minutos para alcanzar la temperatura deseada. Voltaje seguro, fácil de usar que en cualquier país. La plancha de pelo ghd es el más barato. Tenemos una amplia gama de productos y colores. Si te gusta, por lo que comprar lo correcto. [url=http://planchaspeloghd.cabanova.com/]planchas ghd baratas[/url] ghd sitios de venta en línea, disfrutar del pelo GHD barato para lograr los mejores resultados, ofrecemos el envío libre en Dinamarca, luchando para encontrar ghd le da la magia ahora, como planchas ghd populares, la ghd unos accesorios para el cabello perfectamente liso no sólo le da la oportunidad de? utilizando la vasta, sino también para ahorrar tid.Vi están preocupados por sus estrellas favoritas, no sólo una mayor comprensión de lo que dicen, van a degustar más preocupado por el vestido, retro-moda hoy en día sigue siendo cero loco, pelo rizado señora de pelo lacio tan popular diseño y más pelo volumen no es difícil ver lo que usted elija plancha ghd y tiene las habilidades, por lo que ha dado hoy una plancha de pelo pind.ghd diseño más elegante, el uso del campo hoy en día los aparatos negros más populares, una chica enamorada de uno de los varios colores, el mango es de color negro brillante, el color variado, a mano diseñado, antideslizante fácil de entender, difícil deslizar, mejor agarre, diseño del interruptor en el parte frontal del mango, fácil de operar.

    Reply
  • Render Images

    Posted by Farhad on 09/26/2012 05:17am

    Hi, Thank you for all you made! I tryed to make a server control, and just like you, i did also need to render an image. I did just the same you did, and use img tag, but the problem we both have i guess, is that, we should have the images where we us ethe control, and it is not good at all, if you want to publish your control. I like to know if you have any solution, so we embed or do something like that our image, so we do not need to copy images in the target web application? Please reply me to my email address, if you have any idea. Thank you, Farhad

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

  • Hybrid cloud platforms need to think in terms of sweet spots when it comes to application platform interface (API) integration. Cloud Velocity has taken a unique approach to tight integration with the API sweet spot; enough to support the agility of physical and virtual apps, including multi-tier environments and databases, while reducing capital and operating costs. Read this case study to learn how a global-level Fortune 1000 company was able to deploy an entire 6+ TB Oracle eCommerce stack in Amazon Web …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds