Thoughts, Tips and Tricks on what I'm currently do for a living. Currently most of my spare time is spent on contributing to Akka.NET.

Friday, July 27, 2007

AutoEventWireup=true

If you specify the attribute AutoEventWireup=True on a Web User Control or a Page, methods like Page_Init() och Page_Load() will be automatically routed to the page's Init- and Load-events.

This is good, sometimes. It simplifies for you since you don't have to hook up events to event handlers. But it is something that's done during runtime, and therefore adds to the executiion time and it may cause event handlers to be called many times.

Example: Event handler beeing called twice.

protected void Page_Init()
{
    Page.Load += Page_Load;
}
protected void Page_Load(object sender, EventArgs e)
{
    //This code will execute twice
}

Page_Load in the example above will be called twice. Once since you mannually hooked the event to the Page_Load handler. Another time since AutoEventWireup=true and the method has a name causing the event to automatically be hooked to it.

AutoEventWireup works on TemplateControl which both Page och Web User Controls derives from.

K Scott Allen's blog talkes about this. I'll go more into depths.

SupportAutoEvents

What happens when AutoEventWireup=true? A TemplateControl has a property SupportAutoEvents. This is true by default (and will change to false by the parser/control builderif you set the attribute AutoEventWireup=false).

HookUpAutomaticHandlers

TemplateControl.HookUpAutomaticHandlers (which is called during the OnInit) will, if AutoEventWireup=true try to find methods with these names:

  • If the control is a Page:
    • Page_PreInit
    • Page_PreLoad
    • Page_LoadComplete
    • Page_PreRenderComplete
    • Page_InitComplete
    • Page_SaveStateComplete
  • For all TemplateControls:
    • Page_Init
    • Page_Load
    • Page_DataBind
    • Page_PreRender
    • Page_Unload
    • Page_Error
    • Page_AbortTransaction  or if it does not exist; OnTransactionAbort
    • Page_CommitTransaction  or if it does not exist; OnTransactionCommit

This is carried out in TemplateControl.GetDelegateInformationWithNoAssert().

32 attempts

As K Scott Allen writes two attempts will be made for every name. First it will try to find an EventHandler with the specified name, i.e. a method with the signature:

void EventHandler(object sender, EventArgs e)

Exemple: A method that is an EventHandler

void Page_PreInit(object sender, EventArgs e)

If that fails a VoidMethod is searched for, i.e. a method with the signature:

void VoidMethod()

Exemple: A method that is a VoidMethod

void Page_PreInit()

Although no methods matching the list have been added to the Page, 32 attempts to find a method will be made (K Scott Allen got 28 but he must have forgotten about OnTransactionAbort and OnTransactionCount).

Ok, the result will be cached but the search will be made at least once, at that's for every TemplateControl.

Hook up the event to the handler

For all matching methods on the control TemplateControl.HookUpAutomaticHandlers() will hook up the event to the corresponding event handler, unless the method already has been added to the event since HookUpAutomaticHandlers searches the list of event handlers for the event. If it finds the method, it will not add the method again.

But wait. In the first example Page_Load() was obviously added twice to the event.
Yes, but that's because HookUpAutomaticHandlers already had hooked up the Page.Load event to the Page_Load handler when we in Page_Init did it. Remember that HookUpAutomaticHandlers is called in the Page's OnInit, which is called before our Page_Init method. If we hook up the event to the handler before the page's OnInit we will do it before the HookUpAutomaticHandlers has ben called and therefore Page_Load will only be called once.

Exemple: Page_Load is only called once.

public partial class _Default : System.Web.UI.Page
{
    public _Default()
    {
        Page.Load += Page_Load;
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        //This code will execute once
    }
}

Conclusion: AutoEventWireup=false

Consider setting AutoEventWireup=false and manually hook up the events to the handlers. You gain control over when things are called and you don't have to pay for the overhead TemplateControl.HookUpAutomaticHandlers causes.

Microsoft recommends setting it to false if performance is a key consideration.

More on AutoEventWireup on MSDN

http://msdn2.microsoft.com/en-us/library/system.web.configuration.pagessection.autoeventwireup.aspx
http://support.microsoft.com/default.aspx/kb/324151

Monday, May 21, 2007

Insert Do-nothing comments

Always insert a //Do nothing comment in places where the intention is that nothing should be done. Let Me show you why by an example. Assume you have a constructor for a Control that inherits WebControl and all you want to do is changing the default tag (which is Span).
public MyControl()
   :base(HtmlTextWriterTag.Div)
{
}
When someone else reads this code (or you in a month or so when you've forgotten all about it) they might wonder if this code has been finished or if there is something missing in the constructor. By adding a comment, you show for anyone reading the code that there shouldn't really be any code inside the constructor.
public MyControl()
   :base(HtmlTextWriterTag.Div)
{
   //Do nothing
}
I have a code snippet for this so I just need to type don and hit tab twice and //Do nothing is inserted.

Friday, May 18, 2007

Passing values to behavior properties

Typically a property in a AjaxControlToolkit Extender looks like this:
[ExtenderControlProperty]
[DefaultValue("")]
public string MyProperty
{
  get { ... }
  set { ... }
}
Which will match a property in the behavior:
get_MyProperty : function() { ... },
set_MyProperty : function(value) { ... }
Values for MyProperty on the server side will end up in the behavior. Sometimes you want to pass values to the behavior without creating a property in the Extender control. To do this, simply override RenderScriptAttributes() and add the properties using AddProperty().
protected override void RenderScriptAttributes(ScriptBehaviorDescriptor descriptor)
{
  base.RenderScriptAttributes(descriptor);
  string horizontalAlignment=GetHorizontalAlignment();
  descriptor.AddProperty("HorizontalAlignment", horizontalAlignment);
}
And voilà, the HorizontalAlignment property in the beahvior will be set.

Property names & Extenders

Properties for extenders inheriting ExtenderControlBase typically looks like this:
[ExtenderControlProperty]
[DefaultValue("")]
public string MyProperty
{
  get
  {
    return GetPropertyValue("MyProperty", "");
  }
  set
  {
    SetPropertyValue("MyProperty", value);
  }
}
You must have a property with the same name in the behavior on the client side:
get_MyProperty : function() {
  return this._myProperty;
},
set_MyProperty : function(value) {
  this._myProperty = value;
}
But what if you want it to have different name on the client side? Easy. Add the ClientPropertyName attribute to the server side property. If we want MyProperty to be called myProp instead this is how it's done:
[ExtenderControlProperty]
[DefaultValue("")]
[ClientPropertyName("myProp")]
public string MyProperty
{
  get
  {
    return GetPropertyValue("MyProperty", "");
  }
  set
  {
    SetPropertyValue("MyProperty", value);
  }
}
On the client side we get:
get_myProp : function() {
  return this._myProperty;
},
set_myProp : function(value) {
  this._myProperty = value;
}
More on attributes: http://ajax.asp.net/ajaxtoolkit/Walkthrough/ExtenderClasses.aspx

Thursday, May 10, 2007

OOP in Javascript

MSDN Magazine May 2007 edition has an interesting article on how to use object oriented techniques in Javascript. A must-read if you are using Microsoft AJAX since the entire client script library is written using these techniques. http://msdn.microsoft.com/msdnmag/issues/07/05/JavaScript/default.aspx

Thursday, March 22, 2007

Validators not working with UpdatePanel??

The validators don't work very well sometimes when put in an UpdatePanel. But they used to... The reason is that in the 1.0 release of Ajax asp.net the validators that were used in place of the the ordinary asp.net validators have been removed. There was supposed to be an update available for the System.Web namespace to overcome this problem but it will take some time before we have the update. In the meantime there is a fix available. Have a look here: http://blogs.msdn.com/mattgi/archive/2007/01/23/asp-net-ajax-validators.aspx

Thursday, February 8, 2007

Don't access the property ClientId to early

The ClientId property on a Control is correct only after the control has been added to a Parent, i.e. added to a Controls collection. The parent must also be connected to a parent, and it's parent, and so on up al the way to the Page control. If you try to get ClientId to early, not only will you get something unusable, it will be cached so all subsequent calls will get the same. It will also prevent postback events from working. Big No-no:
public class MyControl : CompositeControl
{
 protected override void CreateChildControls()
 {
  Button myButton = new Button();
  myButton.Text = "Unclicked";
  myButton.Click += new EventHandler(myButton_Click);
  Controls.Add(myButton);
  
  //MyControl has no parent yet. The following code will prevent
  //the myButton_Click from beeing called when the button is clicked.
  //Remove the line and it will be called.
  string id = myButton.ClientID; 
 }
 
 void myButton_Click(object sender, EventArgs e)
 {
  Button button = (Button)sender;
  button.Text = "clicked";
 }
}
Another example: http://aspadvice.com/blogs/joteke/archive/2007/01/28/Accessing-ClientID-or-UniqueID-too-early-can-cause-issues.aspx

Wednesday, January 31, 2007

Find a control in javascript (Ajax ASP.Net)

To find a control with id "MyControl" us the function $get. Example:
alert($get("MyControl").id);

Show and Hide a ModalPopupExtender from javascript

To show a modal popup handled by a ModalPopupExtender from javascript you need to set the BehaviorID property:
<ajaxToolkit:ModalPopupExtender...
BehaviorID="MyModalPopupExtender"
... /> 
The script for showing and hiding the popup:
<script language="javascript">
   function hidePopup()
   {
       $find('MyModalPopupExtender').show();
   }
   function hidePopup()
   {
       $find('MyModalPopupExtender').hide();
   }
</script>

Tuesday, January 30, 2007

Asp.Net ViewState

A good article explaining ViewState in Asp.Net. http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx Some of the interesting titbits:
  • When a control is tracking ViewState, items changed in the ViewState will be marked dirty. Only dirty items in the ViewState StateBag will be serialized to the hidden __VIEWSTATE field.
  • Controls starts to track ViewState after the it's OnInit.
  • The page's OnInit is called after all controls' so at this stage all controls are tracking viewstate.
  • Data bound during the page's OnInit and OnLoad will go into ViewState since the control is tracking view state. This means, don't set properties on controls in a page's OnInit and OnLoad if you don't want it to go into viewstate.
  • Properties set on a control during the page's OnPreInit, before controls are tracking view state, will not go into ViewState. This can be used to fill controls with data that's easy and cheap to get on every postback.
  • When dynamically creating controls (for example in CreateChildControls in a custom control) set all properties before adding the control to the control collection, or else you are at risk of that the control is already tracking ViewState.