Every extender provides some established functions to handle its client events. These functions is defined as this "add_Event Name".
For example, the AutoCompleteExtender has several client events, such as "GotFocus", "LostFocus", "KeyDown", "CompletionListBlur", "ListMouseOver". We can know their function by the name, the "GotFocus" event means the cursor focus on the AutoComplete's target -- the input TextBox; the "ListMouseOver" event is the mouseover event on the autocomplete flyout(we can say it SuggestionList) . To understand the exact description of these events, please download the AjaxControlToolkit-Framework3.5SP1.zip.(with complete source), and refer to this file:\AjaxControlToolkit-Framework3.5SP1\AjaxControlToolkit\AutoComplete\AutoComplete.aspx
Let's take the "ListMouseOver" event as the sample. The AutoComplete creates a delegate and a handler to the event.
this._mouseOverHandler = Function.createDelegate(this, this._onListMouseOver);
_onListMouseOver: function(ev) {
/// <summary>
/// Handler for the mouseover event on the autocomplete flyout.
/// </summary>
/// <param name="ev" type="Sys.UI.DomEvent" DomElement="false" mayBeNull="false" />
/// <returns />
var item = ev.target;
if(item !== this._completionListElement) {
var children = this._completionListElement.childNodes;
// make sure the selected index is updated
for (var i = 0; i < children.length; ++i) {
if (item === children[i]) {
this._highlightItem(item);
this._selectIndex = i;
break;
}
}
}
}
_onListMouseOver: function(ev) {
/// <summary>
/// Handler for the mouseover event on the autocomplete flyout.
/// </summary>
/// <param name="ev" type="Sys.UI.DomEvent" DomElement="false" mayBeNull="false" />
/// <returns />
var item = ev.target;
if(item !== this._completionListElement) {
var children = this._completionListElement.childNodes;
// make sure the selected index is updated
for (var i = 0; i < children.length; ++i) {
if (item === children[i]) {
this._highlightItem(item);
this._selectIndex = i;
break;
}
}
}
}
Besides, there are two APIs named add_itemOver and remove_itemOver which are used to handle the same event.
add_itemOver : function(handler) {
/// <summary>
/// Add an event handler for the itemOver event
/// </summary>
/// <param name="handler" type="Function" mayBeNull="false">
/// Event handler
/// </param>
/// <returns />
this.get_events().addHandler('itemOver', handler);
},
remove_itemOver : function(handler) {
/// <summary>
/// Remove an event handler from the itemOver event
/// </summary>
/// <param name="handler" type="Function" mayBeNull="false">
/// Event handler
/// </param>
/// <returns />
this.get_events().removeHandler('itemOver', handler);
},
/// <summary>
/// Add an event handler for the itemOver event
/// </summary>
/// <param name="handler" type="Function" mayBeNull="false">
/// Event handler
/// </param>
/// <returns />
this.get_events().addHandler('itemOver', handler);
},
remove_itemOver : function(handler) {
/// <summary>
/// Remove an event handler from the itemOver event
/// </summary>
/// <param name="handler" type="Function" mayBeNull="false">
/// Event handler
/// </param>
/// <returns />
this.get_events().removeHandler('itemOver', handler);
},
Ok, let's use these functions.
Here is a scenario. An AutoComplete should be added into one DIV, another DropDownList is under this AutoComplete's input TextBox. Normally, the generated CompletionList can display upon the DropDownList. like this:

But if we place them inside a relative postion DIV, the behavior is changed. The DropDownList would stay on the top of any controls!(This is the established design of IE6.)

To display the CompletionList on the top, we need add a shared absolute position IFRAME behind the CompletionList.
At the first, we need to handle the CompletionList's ClientShowing event.
<ajaxToolkit:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server" TargetControlID="txtName"
ServicePath="AutoComplete1.asmx" ServiceMethod="GetCompletionListByRandom" MinimumPrefixLength="2"
CompletionInterval="10" EnableCaching="true" OnClientShowing="clientShowing"
CompletionListCssClass="autocomplete_completionListElement" CompletionListHighlightedItemCssClass="autocomplete_highlightedListItem"
CompletionListItemCssClass="autocomplete_listItem">
</ajaxToolkit:AutoCompleteExtender>
ServicePath="AutoComplete1.asmx" ServiceMethod="GetCompletionListByRandom" MinimumPrefixLength="2"
CompletionInterval="10" EnableCaching="true" OnClientShowing="clientShowing"
CompletionListCssClass="autocomplete_completionListElement" CompletionListHighlightedItemCssClass="autocomplete_highlightedListItem"
CompletionListItemCssClass="autocomplete_listItem">
</ajaxToolkit:AutoCompleteExtender>
Second, we need find the Client Behavior and the CompletionList of the AutoComplete in the script.
Third, add the shared absolute position IFRAME.
<script type="text/javascript">
function clientShowing(source, args) {
var popup = source._completionListElement;
var height = popup.scrollHeight;
var width = popup.scrollWidth;
//This iframe's height and width should be smaller than the CompletionList but bigger than the DropDownList
var iframe1 = "<IFRAME id='iframe1' style=' height:" + height + "; width:" + width + "; position:absolute; z-index:-1;border:0px; border-style:none; border-width:0px; ' ></IFRAME>";
popup.innerHTML = iframe1 + popup.innerHTML;
}
</script>
function clientShowing(source, args) {
var popup = source._completionListElement;
var height = popup.scrollHeight;
var width = popup.scrollWidth;
//This iframe's height and width should be smaller than the CompletionList but bigger than the DropDownList
var iframe1 = "<IFRAME id='iframe1' style=' height:" + height + "; width:" + width + "; position:absolute; z-index:-1;border:0px; border-style:none; border-width:0px; ' ></IFRAME>";
popup.innerHTML = iframe1 + popup.innerHTML;
}
</script>
Now we achieve the goal about stay the CompletionList on the top of the DropDownList:

Take a break here.
Beautiful thing is difficult. If you think that's all but that's wrong. I have metioned there is a "MouseOver" event of the CompletionList. If we add the IFRAME, would any chaos be added in? YEAH! That's what I focused.
If the input text is long enough, we can find the options value of the CompletionList are no in same length. What would be raised if hovering over the end of the shorter option? You may think of the result--an error!

The cause is the added IFRAME does not have a valid value to choose. Let's fix it by handling the "MouseOver" event.
Firstly, we need to remove the original evevt delegate in the pageLoad function. Have you remembered how to find the Client Behavior of the Extenders? We need use it now!
Actually, we can use this method $find(the AutoComplete's BehaviorId) instead of the currentBehavior if there is only one extender.
Second, in the customMouseOverHandler function, rewrite the original method by adding the judge of the Hovered Item type:
function customMouseOverHandler(ev) {
/// <summary>
/// Handler for the mouseover event on the autocomplete flyout.
/// </summary>
/// <param name="ev" type="Sys.UI.DomEvent" DomElement="false" mayBeNull="false" />
/// <returns />
var item = ev.target;
// The judge of the MouseOverred Item Type
if (item.tagName == "IFRAME") {
return;
}
if (item !== _currentAutoComplete._completionListElement) {
var children = _currentAutoComplete._completionListElement.childNodes;
// make sure the selected index is updated
for (var i = 0; i < children.length; ++i) {
if (item === children[i]) {
_currentAutoComplete._highlightItem(item);
_currentAutoComplete._selectIndex = i;
break;
}
}
}
}
/// <summary>
/// Handler for the mouseover event on the autocomplete flyout.
/// </summary>
/// <param name="ev" type="Sys.UI.DomEvent" DomElement="false" mayBeNull="false" />
/// <returns />
var item = ev.target;
// The judge of the MouseOverred Item Type
if (item.tagName == "IFRAME") {
return;
}
if (item !== _currentAutoComplete._completionListElement) {
var children = _currentAutoComplete._completionListElement.childNodes;
// make sure the selected index is updated
for (var i = 0; i < children.length; ++i) {
if (item === children[i]) {
_currentAutoComplete._highlightItem(item);
_currentAutoComplete._selectIndex = i;
break;
}
}
}
}
OK! This is the really end of this huge work! I assume you have a basic understanding of how to handle the AjaxControlToolkit extender's client event or rewrite the delegate of the client event. Any questions, feel free to tell me here or post your request to the AJAX forum.
The complete code:
<%@ Page Title="" Language="C#" MasterPageFile="~/Master.Master" AutoEventWireup="true"
CodeBehind="Content.aspx.cs" Inherits="SolluTest_AutoComplete.Content" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<script type="text/javascript">
function clientShowing(source, args) {
var popup = source._completionListElement;
var height = popup.scrollHeight;
var width = popup.scrollWidth;
//This iframe's height and width should be smaller than the CompletionList but bigger than the DropDownList
var iframe1 = "<IFRAME id='iframe1' style=' height:" + height + "; width:" + width + "; position:absolute; z-index:-1;border:0px; border-style:none; border-width:0px; ' ></IFRAME>";
popup.innerHTML = iframe1 + popup.innerHTML;
}
function pageLoad() {
//If any Extender is placed in the DataBind Control, it's hard to defind the BehaviorId and get the Client behavior.
//We can use the method to find all the correct type behaviors.
var currentBehavior = null;
var allBehaviors = Sys.Application.getComponents();
for (var loopIndex = 0; loopIndex < allBehaviors.length; loopIndex++) {
currentBehavior = allBehaviors[loopIndex];
if (currentBehavior.get_name() == "AutoCompleteBehavior") {
_currentAutoComplete = currentBehavior;
var completionListElement = currentBehavior._completionListElement;
$removeHandler(completionListElement, 'mouseover', currentBehavior._mouseOverHandler);
//rewrite the MouseOver event's delegate
currentBehavior._mouseOverHandler = Function.createDelegate(currentBehavior, customMouseOverHandler);
$addHandler(completionListElement, "mouseover", currentBehavior._mouseOverHandler);
}
}
}
function customMouseOverHandler(ev) {
/// <summary>
/// Handler for the mouseover event on the autocomplete flyout.
/// </summary>
/// <param name="ev" type="Sys.UI.DomEvent" DomElement="false" mayBeNull="false" />
/// <returns />
var item = ev.target;
// The judge of the MouseOverred Item Type
if (item.tagName == "IFRAME") {
return;
}
if (item !== _currentAutoComplete._completionListElement) {
var children = _currentAutoComplete._completionListElement.childNodes;
// make sure the selected index is updated
for (var i = 0; i < children.length; ++i) {
if (item === children[i]) {
_currentAutoComplete._highlightItem(item);
_currentAutoComplete._selectIndex = i;
break;
}
}
}
}
</script>
<style type="text/css">
/*AutoComplete flyout */.autocomplete_completionListElement
{
visibility: hidden;
margin: 0px !important;
background-color: inherit;
color: windowtext;
border: buttonshadow;
border-width: 1px;
border-style: solid;
cursor: 'default';
overflow: auto;
height: 200px;
text-align: left;
list-style-type: none;
}
/* AutoComplete highlighted item */.autocomplete_highlightedListItem
{
background-color: #ffff99;
color: black;
padding: 1px;
}
/* AutoComplete item */.autocomplete_listItem
{
background-color: window;
color: windowtext;
padding: 1px;
}
</style>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="contentBody" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:TextBox ID="txtName" runat="server" Width="200px" MaxLength="60" AutoPostBack="false"></asp:TextBox><br />
<ajaxToolkit:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server" TargetControlID="txtName"
ServicePath="AutoComplete1.asmx" ServiceMethod="GetCompletionListByRandom" MinimumPrefixLength="2"
CompletionInterval="10" EnableCaching="true" OnClientShowing="clientShowing"
CompletionListCssClass="autocomplete_completionListElement" CompletionListHighlightedItemCssClass="autocomplete_highlightedListItem"
CompletionListItemCssClass="autocomplete_listItem">
</ajaxToolkit:AutoCompleteExtender>
<asp:DropDownList ID="DropDownList1" runat="server" Height="16px" Width="84px">
<asp:ListItem>123</asp:ListItem>
<asp:ListItem>234</asp:ListItem>
<asp:ListItem>qwe</asp:ListItem>
</asp:DropDownList>
</asp:Content>
CodeBehind="Content.aspx.cs" Inherits="SolluTest_AutoComplete.Content" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<script type="text/javascript">
function clientShowing(source, args) {
var popup = source._completionListElement;
var height = popup.scrollHeight;
var width = popup.scrollWidth;
//This iframe's height and width should be smaller than the CompletionList but bigger than the DropDownList
var iframe1 = "<IFRAME id='iframe1' style=' height:" + height + "; width:" + width + "; position:absolute; z-index:-1;border:0px; border-style:none; border-width:0px; ' ></IFRAME>";
popup.innerHTML = iframe1 + popup.innerHTML;
}
function pageLoad() {
//If any Extender is placed in the DataBind Control, it's hard to defind the BehaviorId and get the Client behavior.
//We can use the method to find all the correct type behaviors.
var currentBehavior = null;
var allBehaviors = Sys.Application.getComponents();
for (var loopIndex = 0; loopIndex < allBehaviors.length; loopIndex++) {
currentBehavior = allBehaviors[loopIndex];
if (currentBehavior.get_name() == "AutoCompleteBehavior") {
_currentAutoComplete = currentBehavior;
var completionListElement = currentBehavior._completionListElement;
$removeHandler(completionListElement, 'mouseover', currentBehavior._mouseOverHandler);
//rewrite the MouseOver event's delegate
currentBehavior._mouseOverHandler = Function.createDelegate(currentBehavior, customMouseOverHandler);
$addHandler(completionListElement, "mouseover", currentBehavior._mouseOverHandler);
}
}
}
function customMouseOverHandler(ev) {
/// <summary>
/// Handler for the mouseover event on the autocomplete flyout.
/// </summary>
/// <param name="ev" type="Sys.UI.DomEvent" DomElement="false" mayBeNull="false" />
/// <returns />
var item = ev.target;
// The judge of the MouseOverred Item Type
if (item.tagName == "IFRAME") {
return;
}
if (item !== _currentAutoComplete._completionListElement) {
var children = _currentAutoComplete._completionListElement.childNodes;
// make sure the selected index is updated
for (var i = 0; i < children.length; ++i) {
if (item === children[i]) {
_currentAutoComplete._highlightItem(item);
_currentAutoComplete._selectIndex = i;
break;
}
}
}
}
</script>
<style type="text/css">
/*AutoComplete flyout */.autocomplete_completionListElement
{
visibility: hidden;
margin: 0px !important;
background-color: inherit;
color: windowtext;
border: buttonshadow;
border-width: 1px;
border-style: solid;
cursor: 'default';
overflow: auto;
height: 200px;
text-align: left;
list-style-type: none;
}
/* AutoComplete highlighted item */.autocomplete_highlightedListItem
{
background-color: #ffff99;
color: black;
padding: 1px;
}
/* AutoComplete item */.autocomplete_listItem
{
background-color: window;
color: windowtext;
padding: 1px;
}
</style>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="contentBody" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:TextBox ID="txtName" runat="server" Width="200px" MaxLength="60" AutoPostBack="false"></asp:TextBox><br />
<ajaxToolkit:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server" TargetControlID="txtName"
ServicePath="AutoComplete1.asmx" ServiceMethod="GetCompletionListByRandom" MinimumPrefixLength="2"
CompletionInterval="10" EnableCaching="true" OnClientShowing="clientShowing"
CompletionListCssClass="autocomplete_completionListElement" CompletionListHighlightedItemCssClass="autocomplete_highlightedListItem"
CompletionListItemCssClass="autocomplete_listItem">
</ajaxToolkit:AutoCompleteExtender>
<asp:DropDownList ID="DropDownList1" runat="server" Height="16px" Width="84px">
<asp:ListItem>123</asp:ListItem>
<asp:ListItem>234</asp:ListItem>
<asp:ListItem>qwe</asp:ListItem>
</asp:DropDownList>
</asp:Content>
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Master.master.cs" Inherits="SolluTest_AutoComplete.Master" %>
<!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></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body style="width:100%;text-align:center;background-color:#666699">
<form id="frmMain" runat="server">
<div id="mainDiv" style="position:relative;top:10px;width:803px;height:auto; background-color:white;border:solid 1px #666666">
<div id="contentDiv" >
<div >
<asp:ContentPlaceHolder ID="contentBody" runat="server"></asp:ContentPlaceHolder>
</div>
</div>
</div>
</form>
</body>
</html>
<!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></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body style="width:100%;text-align:center;background-color:#666699">
<form id="frmMain" runat="server">
<div id="mainDiv" style="position:relative;top:10px;width:803px;height:auto; background-color:white;border:solid 1px #666666">
<div id="contentDiv" >
<div >
<asp:ContentPlaceHolder ID="contentBody" runat="server"></asp:ContentPlaceHolder>
</div>
</div>
</div>
</form>
</body>
</html>
The related thread url: http://forums.asp.net/t/1362145.aspx

