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.
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.
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:
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.)
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.
<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.
<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:
Take a break here.
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.
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;
}
}
}
}
<%@ 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>
<%@ 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>