It was mentioned in my last post that AjaxControlToolkit Extender client classes provide many useful APIs which can bebound to other events and provide handlers to them. Now, let's see how it works.(How to Find the Client Behavior of the Extender which is placed inside the DataBind Control)
Each extender provides some established functions to handle its client events which are defined as "add_Event Name".
For example, AutoCompleteExtender has several client events, such as "GotFocus", "LostFocus", "KeyDown", "CompletionListBlur", "ListMouseOver". We can easily understand the functions by their names: "GotFocus" event happens when the cursor focus on the AutoComplete's target -- the input TextBox; "ListMouseOver" event is like a mouseover event of the autocomplete flyout(we can call it SuggestionList) . For exact descriptions of these events, please download this file: AjaxControlToolkit-Framework3.5SP1.zip.(with complete source), and refer to this page:\AjaxControlToolkit-Framework3.5SP1\AjaxControlToolkit\AutoComplete\AutoComplete.aspx
Here, I would like to take "ListMouseOver" event as the sample control in the test demo below. The AutoComplete control creates a delegate and a handler to the event.
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
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;
}
}
}
}
Besides, there are two APIs named add_itemOver and remove_itemOver which are used to handle the same event.
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
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);
},
Ok, let's use these functions.
Here is a scenario. An AutoComplete should be added into a DIV while another DropDownList is under its input TextBox. Normally, the generated CompletionList can be displayed upon the DropDownList. Like this:
![](http://farm4.static.flickr.com/3116/3151775317_b927c1bc77_o.gif)
But if we place them inside a relative position DIV, the behavior is changed. The DropDownList will stay above any other controls! (This is the established design of IE6.)![](http://farm4.static.flickr.com/3393/3198934348_8de359db59_o.gif)
To make the CompletionList locate on the top, we need to add a shared absolute position IFRAME behind the CompletionList. Here are the steps to reach it:
Firstly, we need to handle the CompletionList's ClientShowing event.
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
<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>
Then, we need to find the Client Behavior and the CompletionList of the AutoComplete in the script.
In the end, add the shared absolute position IFRAME.
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
<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>
Now, we finally achieve the goal of keeping the CompletionList on the top of the DropDownList:![](http://farm4.static.flickr.com/3304/3198949008_3f1c11b173_o.gif)
Take a break
here.
A good gain takes long pain. If you think that's all, then you may be wrong here. 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 option values in the CompletionList are not in the 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.
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
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") {
var completionListElement = currentBehavior._completionListElement;
_currentAutoComplete = currentBehavior;
$removeHandler(completionListElement, 'mouseover', currentBehavior._mouseOverHandler);
//rewrite the MouseOver event's delegate
currentBehavior._mouseOverHandler = Function.createDelegate(currentBehavior, customMouseOverHandler);
$addHandler(completionListElement, "mouseover", currentBehavior._mouseOverHandler);
}
}
}
Actually, we can use this method $find(the AutoComplete's BehaviorId) instead of the currentBehavior if there is only one extender.
Secondly, in the customMouseOverHandler function, rewrite the original method by adding the judge of the Hovered Item type:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
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;
}
}
}
}
OK! This is the really end! 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 let me know here or post your request to the
AJAX forum.
The complete code:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
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>
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
<%@ 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>