Tuesday, June 30, 2009

Bubbling an Event

The ASP.NET page framework provides a technique called event bubbling that allows a child control to propagate events up its containment hierarchy. Event bubbling enables events to be raised from a more convenient location in the controls hierarchy and allows event handlers to be attached to the original control as well as to the control that exposes the bubbled event.

Event bubbling is used by the data-bound controls (Repeater, DataList, and DataGrid) to expose command events raised by child controls (within item templates) as top-level events. While ASP.NET server controls in the .NET Framework use event bubbling for command events (events whose event data class derives from CommandEventArgs), any event defined on a server control can be bubbled.

A control can participate in event bubbling through two methods that it inherits from the base class System.Web.UI.Control. These methods are OnBubbleEvent and RaiseBubbleEvent. The following code shows the signatures of these methods.

[C#]
protected virtual bool OnBubbleEvent
(
object source,
EventArgs args
);
protected void RaiseBubbleEvent(
object source,
EventArgs args
);
[Visual Basic]
Overridable Protected Function OnBubbleEvent( _
ByVal source As Object, _
ByVal args As EventArgs _
) As Boolean
Protected Sub RaiseBubbleEvent( _
ByVal source As Object, _
ByVal args As EventArgs _
)

The implementation of RaiseBubbleEvent is provided by Control and cannot be overridden. RaiseBubbleEvent sends the event data up the hierarchy to the control's parent. To handle or to raise the bubbled event, a control must override the OnBubbleEvent method.

A control that has an event bubbled to it does one of the following three things.

  • It does nothing, in which case the event is automatically bubbled up to its parent.
  • It does some processing and continues to bubble the event. To accomplish this, a control must override OnBubbleEvent and invoke RaiseBubbleEvent from OnBubbleEvent. The following code fragment bubbles an event after checking for the type of the event arguments.
    [C#]
    protected override bool OnBubbleEvent(object source, EventArgs e) {           if (e is CommandEventArgs) {
    // Adds information about an Item to the
    // CommandEvent.
    TemplatedListCommandEventArgs args =
    new TemplatedListCommandEventArgs(this, source, (CommandEventArgs)e);
    RaiseBubbleEvent(
    this, args);
    return true;
    }
    return false;
    }
    [Visual Basic]
    Protected Overrides Function OnBubbleEvent(source As Object, e As EventArgs) As Boolean
    If TypeOf e Is CommandEventArgs Then
    ' Adds information about an Item to the
    ' CommandEvent.
    Dim args As New TemplatedListCommandEventArgs(Me, source, CType(e, CommandEventArgs))
    RaiseBubbleEvent(Me, args)
    Return True
    End If
    Return False
    End Function

  • It stops bubbling the event and raises and/or handles the event. Raising an event involves invoking the method that dispatches the event to listeners. To raise the bubbled event, a control must override OnBubbleEvent to invoke the OnEventName method that raises the bubbled event. A control that raises a bubbled event generally exposes the bubbled event as a top-level event. The following code fragment raises a bubbled event.
    [C#]
    protected override bool OnBubbleEvent(object source, EventArgs e) {
    bool handled = false;

    if (e is TemplatedListCommandEventArgs) {
    TemplatedListCommandEventArgs ce = (TemplatedListCommandEventArgs)e;

    OnItemCommand(ce);
    handled =
    true;
    }
    return handled;
    }
    [Visual Basic]
    Protected Overrides Function OnBubbleEvent(source As Object, e As EventArgs) As Boolean
    Dim handled As Boolean = False

    If TypeOf e Is TemplatedListCommandEventArgs Then
    Dim ce As TemplatedListCommandEventArgs = CType(e, TemplatedListCommandEventArgs)

    OnItemCommand(ce)
    handled = True
    End If
    Return handled
    End Function

For samples that demonstrate event bubbling, see Event Bubbling Control Sample and Templated Data-Bound Control Sample.

Note While the method that enables event bubbling, OnBubbleEvent, follows the standard .NET Framework naming pattern for methods that raise events, there is no event named BubbleEvent. The bubbled event is exposed as a top-level event in the control that stops event bubbling. For example, the DataList control exposes Command events from controls in its template as ItemCommand events. Note also that the standard signature of OnEventName methods in the .NET Framework has one argument (protected void OnEventName (EventArgs e)). However, OnBubbleEvent has two arguments because the event originates outside the control; the second argument supplies the source.

The discussion so far shows how a control can respond to an event that is bubbled up to it. The following section shows how to author a control that defines a bubbled event.

Defining a Bubbled Event

If you want your control to enable event bubbling for an event that it defines, it must invoke the RaiseBubbleEvent from the OnEventName method that raises the event. No additional work needs to be done from within the control. The following code fragment shows a control that defines a Command event that enables bubbling.

[C#]
protected virtual void OnCommand(CommandEventArgs e) {
CommandEventHandler handler = (CommandEventHandler)Events[EventCommand];
if (handler != null)
handler(
this,e);

// The Command event is bubbled up the control hierarchy.
RaiseBubbleEvent(
this, e);
}
[Visual Basic]
Protected Overridable Sub OnCommand(e As CommandEventArgs)
Dim handler As CommandEventHandler = CType(Events(EventCommand), CommandEventHandler)
If Not (handler Is Nothing) Then
handler(Me, e)
End If
' The Command event is bubbled up the control hierarchy.
RaiseBubbleEvent(Me, e)
End Sub

Note Event bubbling is not limited to command events. You can use the mechanism described here to bubble any event.

Event Bubbling

Event Bubbling



Suppose you have a element inside an element

-----------------------------------
| element1 |
| ------------------------- |
| |element2 | |
| ------------------------- |
| |
-----------------------------------


and both have an onClick event handler. If the user clicks on element2 he causes a click event in both element1 and element2. But which event fires first? Which event handler should be executed first? What, in other words, is the event order?
Two models

Not surprisingly, back in the bad old days Netscape and Microsoft came to different conclusions.


  • Netscape said that the event on element1 takes place first. This is called event capturing.
  • Microsoft maintained that the event on element2 takes precedence. This is called event bubbling.


The two event orders are radically opposed. Explorer only supports event bubbling. Mozilla, Opera 7 and Konqueror support both. Older Opera's and iCab support neither.

Event capturing

When you use event capturing

               | |
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 \ / | |
| ------------------------- |
| Event CAPTURING |
-----------------------------------



the event handler of element1 fires first, the event handler of element2 fires last.
Event bubbling

When you use event bubbling

               / \
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 | | | |
| ------------------------- |
| Event BUBBLING |
-----------------------------------



the event handler of element2 fires first, the event handler of element1 fires last.

W3C model

W3C has very sensibly decided to take a middle position in this struggle. Any event taking place in the W3C event model is first captured until it reaches the target element and then bubbles up again.

                 | |  / \
-----------------| |--| |-----------------
| element1 | | | | |
| -------------| |--| |----------- |
| |element2 \ / | | | |
| -------------------------------- |
| W3C event model |
------------------------------------------



You, the web developer, can choose whether to register an event handler in the capturing or in the bubbling phase. This is done through the addEventListener() method explained on the Advanced models page. If its last argument is true the event handler is set for the capturing phase, if it is false the event handler is set for the bubbling phase.

Suppose you do

element1.addEventListener('click',doSomething2,true)
element2.addEventListener('click',doSomething,false)


If the user clicks on element2 the following happens:

1. The click event starts in the capturing phase. The event looks if any ancestor element of element2 has a onclick event handler for the capturing phase.
2. The event finds one on element1. doSomething2() is executed.
3. The event travels down to the target itself, no more event handlers for the capturing phase are found. The event moves to its bubbling phase and executes doSomething(), which is registered to element2 for the bubbling phase.
4. The event travels upwards again and checks if any ancestor element of the target has an event handler for the bubbling phase. This is not the case, so nothing happens.



The reverse would be


element1.addEventListener('click',doSomething2,false)
element2.addEventListener('click',doSomething,false)


Now if the user clicks on element2 the following happens:

1. The click event starts in the capturing phase. The event looks if any ancestor element of element2 has a onclick event handler for the capturing phase and doesn’t find any.
2. The event travels down to the target itself. The event moves to its bubbling phase and executes doSomething(), which is registered to element2 for the bubbling phase.
3. The event travels upwards again and checks if any ancestor element of the target has an event handler for the bubbling phase.
4. The event finds one on element1. Now doSomething2() is executed.


Use of event bubbling

Few web developers consciously use event capturing or bubbling. In Web pages as they are made today, it is simply not necessary to let a bubbling event be handled by several different event handlers. Users might get confused by several things happening after one mouse click, and usually you want to keep your event handling scripts separated. When the user clicks on an element, something happens, when he clicks on another element, something else happens.

Of course this might change in the future, and it’s good to have models available that are forward compatible. But the main practical use of event capturing and bubbling today is the registration of default functions.

It always happens

What you first need to understand is that event capturing or bubbling always happens. If you define a general onclick event handler for your entire document

document.onclick = doSomething;
if (document.captureEvents) document.captureEvents(Event.CLICK);

any click event on any element in the document will eventually bubble up to the document and thus fire this general event handler. Only when a previous event handling script explicitly orders the event to stop bubbling, it will not propagate to the document.

Uses

Because any event ends up on the document, default event handlers become possible. Suppose you have this page:

------------------------------------
| document |
| --------------- ------------ |
| | element1 | | element2 | |
| --------------- ------------ |
| |
------------------------------------


element1.onclick = doSomething;
element2.onclick = doSomething;
document.onclick = defaultFunction;

Now if the user clicks on element1 or 2, doSomething() is executed. You can stop the event propagation here, if you wish. If you don’t the event bubbles up to defaultFunction(). If the user clicks anywhere else defaultFunction() is also executed. This might be useful sometimes.

Setting document–wide event handlers is necessary in drag–and–drop scripts. Typically a mousedown event on a layer selects this layer and makes it respond to the mousemove event. Though the mousedown is usually registered on the layer to avoid browser bugs, both other event handlers must be document–wide.

Remember the First Law of Browserology: anything can happen, and it usually does when you’re least prepared for it. So it may happen that the user moves his mouse very wildly and the script doesn’t keep up so that the mouse is not over the layer any more.

  • If the onmousemove event handler is registered to the layer, the layer doesn’t react to the mouse movement any more, causing confusion.
  • If the onmouseup event handler is registered on the layer, this event isn’t caught either so that the layer keeps reacting to the mouse movements even after the user thinks he dropped the layer. This causes even more confusion

.

So in this case event bubbling is very useful because registering your event handlers on document level makes sure they’re always executed.

Turning it off


But usually you want to turn all capturing and bubbling off to keep functions from interfering with each other. Besides, if your document structure is very complex (lots of nested tables and such) you may save system resources by turning off bubbling. The browser has to go through every single ancestor element of the event target to see if it has an event handler. Even if none are found, the search still takes time.

In the Microsoft model you must set the event’s cancelBubble property to true.

window.event.cancelBubble = true

In the W3C model you must call the event’s stopPropagation() method.

e.stopPropagation()

This stops all propagation of the event in the bubbling phase. Stopping event propagation in the capturing phase is impossible. One wonders why.

For a complete cross-browser experience do

function doSomething(e)
{
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}

Setting the cancelBubble property in browsers that don’t support it doesn’t hurt. The browser shrugs and creates the property. Of course it doesn’t actually cancel the bubbling, but the assignment itself is safe.

currentTarget

As we’ve seen earlier, an event has a target or srcElement that contains a reference to the element the event happened on. In our example this is element2, since the user clicked on it.

It is very important to understand that during the capturing and bubbling phases (if any) this target does not change: it always remains a reference to element2.

But suppose we register these event handlers:

element1.onclick = doSomething;
element2.onclick = doSomething;

If the user clicks on element2 doSomething() is executed twice. But how do you know which HTML element is currently handling the event? target/srcElement don’t give a clue, they always refer to element2 since it is the original source of the event.

To solve this problem W3C has added the currentTarget property. It contains a reference to the HTML element the event is currently being handled by: exactly what we need. Unfortunately the Microsoft model doesn’t contain a similar property.

You can also use the this keyword. In the example above it refers to the HTML element the event is handled on, just like currentTarget.

Problems of the Microsoft model

But when you use the Microsoft event registration model the this keyword doesn’t refer to the HTML element. Combined with the lack of a currentTarget–like property in the Microsoft model, this means that if you do

element1.attachEvent('onclick',doSomething)
element2.attachEvent('onclick',doSomething)

you cannot know which HTML element currently handles the event. This is the most serious problem with the Microsoft event registration model.

Wednesday, June 3, 2009

Microsoft Web Platform Installer

Microsoft Web Platform Installer

One of the cool new releases coming out this year is a small download manager - the Microsoft Web Platform Installer - that makes installing and configuring web server and web development stacks really easy. It is a free tool that you can download from the www.microsoft.com/web site (here is the direct link to the installer – choose the 2.0 version). It works with Windows XP, Vista, Windows 7, Windows Server 2003 and Windows Server 2008.

The Web Platform Installer provides an easy way to quickly install and customize all the software you need to develop or deploy web sites and applications on a Windows machine. The tool automatically analyses what your system currently has installed, allows you to easily mark additional components to be added, and then automates installing them all at once when you click the install button (saving you from having to manually install each one yourself).

View Complete Detail

showModelessDialog Method

Opens a modeless dialog window.

Syntax:

window.showModelessDialog(param1, param2, param3)

Parameters:
param1 Required; the URL of the document to display.
param2 Optional; an object with added properties. The modeless window will
receive this object using its dialogArguments property.
param3 Optional; a semicolon-delimited list of one or more of the style

attributes listed at
http://msdn.microsoft.com/en-us/library/ms536761(VS.85).aspx..

Tuesday, June 2, 2009

showModalDialog Method

showModalDialog Method

Creates a modal dialog box that displays the specified HTML document.

Syntax


vReturnValue = object.showModalDialog(sURL [, vArguments] [, sFeatures])

Parameters

sURL
Required.

String that specifies the URL of the document to load and display.

vArguments
Optional.

Variant that specifies the arguments to use when displaying the document. Use this parameter to pass a value of any type, including an array of values. The dialog box can extract the values passed by the caller from the dialogArguments property of the window object.

sFeatures Optional.

String that specifies the window ornaments for the dialog box, using one or more of the following semicolon-delimited values:



dialogHeight:sHeight

Sets the height of the dialog window.

dialogLeft:sXPos
Sets the left position of the dialog window relative to the upper-left corner of the desktop.

dialogTop:sYPos
Sets the top position of the dialog window relative to the upper-left corner of the desktop.

dialogWidth:sWidth
Sets the width of the dialog window.

center:{ yes | no | 1 | 0 | on | off }
Specifies whether to center the dialog window within the desktop. The default is yes.

dialogHide:{ yes | no | 1 | 0 | on | off }
Specifies whether the dialog window is hidden when printing or using print preview. This feature is only available when a dialog box is opened from a trusted application. The default is no.

edge:{ sunken | raised }
Specifies the edge style of the dialog window. The default is raised.

resizable:{ yes | no | 1 | 0 | on | off }
Specifies whether the dialog window has fixed dimensions. The default is no.

scroll:{ yes | no | 1 | 0 | on | off }
Specifies whether the dialog window displays scrollbars. The default is yes.

status:{ yes | no | 1 | 0 | on | off }
Specifies whether the dialog window displays a status bar. The default is yes for untrusted dialog windows and no for trusted dialog windows.

unadorned:{ yes | no | 1 | 0 | on | off }
Specifies whether the dialog window displays the border window chrome. This feature is only available when a dialog box is opened from a trusted application. The default is no.

Return Value

Variant. Returns the value of the returnValue property as set by the window of the document specified in sURL.


How to use:


  • Write yourself a couple of easy to use JavaScript functions to take care of opening and closing them.

function closeDialog(returnValue)

{

window.returnValue = returnValue;

window.close();

}

function GetDialogFeatures(dialogWidth, dialogHeight, resizable)

{

return "dialogWidth: " + dialogWidth + "px;dialogHeight: " + dialogHeight + "px;status: no;unadorned: yes;scroll: no;help: no;" + (resizable ? "resizable: yes;" : "");

}

// Usage Example.

var retValue window.showModalDialog("home.aspx?id=" + id, "", GetDialogFeatures(500, 240, false));

if (retValue)

window.location.reload(true);

  • Include in the section of your page the following tag:

<base target="_self">base>


when an HTML form is submitted within a ModalDialog window, the behaviour is different (opens in a new window). There IS a workaround to that behaviour: Add inside of the tags in the .aspx file of the ModalDialog window.