Zeeshan Hirani

Senior .net Developer
CheaperThanDirt.com

May 2008 - Posts

ParseChildren in Templated Controls

Well, I have been spending sometime learning about Templated controls at work. Hence I am slowly getting an understanding of common attributes that you would want to use on Templated controls. If your template control inherits from WebControl than you do not need to worry about setting ParseChildren to true because by default WebControls have ParseChildren set to true. However if your controls inherit from Control class, than in order to get Templates to work you need to set ParseChildren to true. When you set ParseChildren to true, asp.net parser maps the top level tags of the server control to properties on the server control. For e.g

<cc:KeyWordControl runat="server" id="test">
   <KeyWords>
     content goes here.
  </KeyWords>

[ParseChildren(true)]
public class KeyWordControl

{

public ITemplate KeyWords{get;set;}

}

When ParseChildren is set to true, KeyWords tag automatically gets mapped to KeyWords property on your server control. If the value is not set to true, than everything inside of it is considered as Literal control and does not get parsed.

Instantiating Templates

I thought to write a blog post telling what is the correct way to instantiate templates because on researching many blog posts and reading few articles, I saw couple of different usages and one of them is misleading and incorrect. Here is the most common way of instantiating templates for a custom control.

image

The above code is wrong! The reason is control inside the templates misses the control life cycle. It is important that each control reaches to the same point in the life cycle as it parents control. All the Instantiate control does is, it instantiates the instance of the control and adds it to control hierarchy and plays its life cycle. The problem is each control in the template are not at the same level in control life cycle. Say if you have a label and textbox control then this is the life cycle that gets played.

Label Init
Label Load
Label PreRender

TextBox Init
TextBox Load
TextBox PreRender

However the correct control life cycle should be this

Label Init
TextBox Init
Label Load
TextBox Load
...

The magic in asp.net that causes the correct lifecycle to occur is the Controls.Add. When you add the controls inside of a control that is actually present on a page, .net tries to catch up all the child controls life cycle to reach up to its parent life cycle. So here is the correct way to solve this problem.

image

Use TemplateInstance.Single to avoid FindControls

If you have created templated controls, you would be aware that it requires you to implement INamingContainer. Only job of INamingContainer is to ensure that controls are unique within that Naming Container. However sometimes if you are using Templated controls that are not going to be repeated like LoginView Control has anonymous Template which does not have a concept of a repeated template, in those cases you would like to be able to access those controls directly in the page.Templated controls have a requirement that contents with in the templated controls must be instantiated inside of a container that implements INamingContainer. Here is a simple example that illustrates this behavior.

image

image

In the above code, I am attributing ITemplate property with a TemplateContainer attribute. TemplateContainer attribute takes a control that implements INamingContainer as shown by my KeyWordContainer control. As I mentioned above Implementing name container causes page developers to access any controls inside of the KeyWordTemplate using FindControl to find the control inside that naming container. To avoid this problem, I am making use of the new .net 2.0 attribute called TemplateInstance.Single. Basically that is  a hint telling that KeyWordTemplate would only be repeated once and therefore controls within the template should be considered controls of the page or whatever its parent is. Another implementation of TemplateInstance.Single is UpdatePanel. Any controls that you create inside of ContentTemplate is basically available to the page without using FindControl method.

When to instantiate templates

Most of the examples that I saw on the net recommended to instantiate templates inside of CreateChildControls method but it does not work correctly. Basically I marked my Itemplate property to TemplateInstance.Single, so all the controls inside my template are available to the page without using FindControl. This works great but only in design time. In the design mode, I can access all the controls but when the page executes, any controls being accessed that are inside of template causes object reference not set to an instance of an object. For a while I couldn't figure out what was going on. Then I realized that UpdatePanel has pretty much the same implementation I can access all the controls inside of UpdatePanel without any problems. Using Reflector I saw that UpdatePanel was not instantiating the template inside of CreateChildControls, in fact they were instantiating the template inside ITemplate property as shown below

image

Inside the setter of Contenttemplate, is where the template is instantiated and sure enough when I changed my code to do similar implementation, I  no longer was getting object reference exception. Here is the updated code that works for me.

image

Using Pragma to disable warnings

Lot of times, you have variables declared in your class that are never getting used directly and are accessed and their values altered using reflection. In those cases when you build you solution you get a warning saying that this particular field is never used. Here is a simple example that shows warning for first field in Person class for not being used.

image

An easy way to disable those warnings, is making use of Pragma keyword followed by the warning number that you want to disable which in this case 0169 for un used variables. Once you have disabled the warnings, as a good practice you should reset the warnings back after portion of code that required disabling the warnings. Here is the finished code that makes use of Pragma keyword to disable the warning for unused variable.

image

Global Namespace in C#

By default if you do not specify a namespace for a class it will go to default namespace. What happens When you are in particular namespace that has the same class that is also available in default namespace. How do you access the class that is available in default namespace. With C# 2.0, global keyword was introduced which allows you to access class that is available in global namespace. Here is an example that illustrates the problem and how we use global to access class available in global namespace.

image

image

In the above code when I create an instance of person object and called toString on it, we are confirmed that the instance of person we created resides in Custom namespace because instantiation also happens in Custom namespace. If you wanted to create an instance of Person object in global namespace, we make use of global keyword in front to tell the compiler to create an instance of person object available in global namespace.

Callbacks in Asp.net Ajax

Callbacks provide an ability to call a function passing in additional parameters that your function would need. In the past to achieve this objective, I have created global variables that can be referenced from any where in your code. . Instead using callbacks, you can pass in a context that has the information your function would need. In the example below, I am passing an array of numbers to a callback function which simply writes the array to a label. Here is the markup

image

In the above code, the second parameter to createCallBack method is the context that you want the actual function to receive. The context could be anything which in my case is an array of integers. In the PrintArray method the second parameter is the context that you have passed earlier. Using that context (array of ints), I am simply append the integer to a label on the screen.

Moving Divs on the page

Today I had a need to move my progress bar control on top of any control that was being updated asynchronously. Therefore I had to reposition my progress bar when an update happened. This lead me to investigate asp.net Ajax client side library and see what api it provides me to move a div from one position to another on a page. Sure enough Sys.UI.DomElement provides a method called getbounds which returns the width,height, x and y coordinate of an element on a page. The DomElement object also provides static method called SetLocation that takes 3 parameters. First parameter is the element that you want to move. Second and third parameters specifies the x and y coordinate of the location where the element should be moved to. To demonstrate the usage I have created a simple page which has 2 buttons. First button simply returns width, height,x and y coordinate of an element on the page. Clicking the second button moves the div to new x and y location on the page. X and Y positions are obtained as user input from the textboxes on the page. Here is how the page looks like.

image

Get Location simply calls a JavaScript function called GetLocation. GetLocation function uses getbounds method defined on DomElement class to extract the x and y position of the div.Move to location button calls MoveTo function which uses SetLocation method defined on DomElement to move the div to a new location. Below is the complete markup for the both JavaScript functions

image

Prevent Enter Key using Asp.net Ajax

Today at work, I had a requirement where I had to prevent user from pressing enter key when they are on a particular textbox because it would cause the page to postback which I wanted to prevent. Using asp.net Ajax, you can register for the keypress event. The key press event gets an argument of type Sys.UI.DomEvent. The DomEvent object has a property called charCode which tells you which key the user has pressed.You can compare the charCode value with Sys.UI.Key.enter to check if the user has pressed enter key. On confirmation that user has pressed enter key, I make use of method exposed on DomEvent class called preventDefault. PreventDefault basically prevents the default action from happening which in my case prevents the enter key from being executed. Here is the code that prevents enter key from being executed by trapping keypress event on textbox.

image

Debug Vs Release Version of JavaScript file

When you are debugging application it is easier to work with debug version of js file because the code is indented and comments provide better readability. However when deploying it production debugs version would increase the load time of the page. ScriptManager makes it really easy to work with debug and release versions of JavaScript file by using its ScriptMode property. For instance if you are referencing a JavaScript file called Popup.js, in order to get debug and release support from ScriptManager, you need to have two versions of the the js file like Popup.js and Popup.debug.js and depending on the ScriptMode set on the ScriptManager it will pull the appropriate JavaScript file. Here is an example that shows how to reference debug and release version of a JavaScript file.

image

In the second script manager, I am setting ScriptMode to debug which instructs the ScriptManager to load the debug version of the JavaScript file called JScript.debug.js. Another easier way to use debug or release version is to set ScriptMode = Inherits which basically tells the ScriptManager to read the compilation mode from web.config and if compilation is set to debug= true than load the debug version of the JavaScript file otherwise load release version of js file. Here is an example of that.

image

More Posts Next page »