How to Handle the AjaxControlToolkit's Client Event or Rewrite the Delegate of the Client Event

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.

ContractedBlock.gif ExpandedBlockStart.gif Code
    this._mouseOverHandler = Function.createDelegate(thisthis._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.

ContractedBlock.gif ExpandedBlockStart.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:

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.

ContractedBlock.gif ExpandedBlockStart.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.

ContractedBlock.gif ExpandedBlockStart.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:

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.
 
Firstly, we need to remove the original event delegate in the pageLoad function. Do you remember how to find the Client Behavior of the Extenders? We need it now!
ContractedBlock.gif ExpandedBlockStart.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:
ContractedBlock.gif ExpandedBlockStart.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:
ContractedBlock.gif ExpandedBlockStart.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>
ContractedBlock.gif ExpandedBlockStart.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>
 
The related thread url: http://forums.asp.net/t/1362145.aspx

转载于:https://www.cnblogs.com/Zhi-QiangNi/archive/2009/01/15/1376514.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值