Hello World
Spiga

分清ASP.NET AJAX中的Extender和Behavior模型

2007-06-04 13:32 by 老赵, 7769 visits

ASP.NET AJAX提出了多种模型,在客户端有Component、Control和Behavior模型,在服务器端有ScirptControl和Extender模型。这些模型各有各的用途,但是请注意非常重要的一点:客户端模型和服务器端模型是相互独立的。

ASP.NET AJAX的重要组件之一是Ajax Control Toolkit,其中包括了大量的Extender和Behavior。其中的Extender使用ASP.NET AJAX提出的Extender模型,在客户端使用了Microsoft AJAX Library提出的Behavior模型。Extender和Behavior模型的组合提供了丰富的效果。那么,究竟什么是Extender模型,什么是Behavior模型呢?

服务器端的Extender控件其实是一个继承了Control类并且实现了IExtenderControl接口的类,我们在开发时也可以直接继承ExtenderControl类,它已经满足了上述条件并且定义了一些常用的方法。Extender控件的作用,简单说来只是想客户端输出脚本,更确切地说,是将需要在页面上执行的脚本告诉ScriptManager,ScriptManager会根据目前的状况(普通加载还是异步回送)选择不同的输出方式。从理论上来说,Extender可以输出任意脚本。因此我们只能说“Ajax Control Tookit中的Extender在客户端使用了Behavior”而不能说“Extender模型在客户端使用了Behavior模型”。

Behavior模型在客户端提供了丰富的功能,它操作的完全是客户端对象,有些可能会访问Web Service方法,但是这并不影响它仅仅是在客户端工作的这个特性。Behavior完全可以独立于服务器端工作,客户端(浏览器)只是按部就班地执行客户端的代码,它也不会知道究竟是何种服务器技术生成了这些代码。

因此,我们在使用Ajax Control Tookit时,也必须牢记以下几条:

  1. Extender模型和Behavior模型没有必然联系。
  2. Behavior可以独立于Extender执行。
  3. 所有效果是由Behavior提供的。

关于第1条已经在上文中解释过了。在我之前的一篇文章“ModalUpdateProgress控件”中利用了第2条特性。在ModalUpdateProgress控件中我使用了ModalPopupBehavior,我的做法是从ModalPopupExtender中提取所有需要的JavaScript文件,并输出至页面,如下:

private IEnumerable<ScriptReference> GetExtenderReferences()
{
    if (extenderReferences == null)
    {
        lock (typeof(ModalUpdateProgess))
        {
            if (extenderReferences == null)
            {
                extenderReferences = 
		    (new ModalPopupExtender() as IExtenderControl).GetScriptReferences();
            }
        }
    }
    
    return extenderReferences;
}

因此,我就能够在客户端使用ModalPopupBehavior来构造我所需要的效果了,这里没有Extender,这里只有Behavior。

关于第3条特性,我认为是最重要的,也是最常利用的一条。我经常会收到例如“如何点击另一个按钮让CollapsiblePanel收缩或打开”或者“如何切换ToggleButton状态”这样的提问,其实这些问题的答案是相同的,使用JavaScript来操作Behavior。Ajax Control Toolkit在服务期端提供的控件实在是太好用了,以至于官方将其托托放放的功能演示了一遍又一遍,乐此不疲。大量的演示却让人忘记了客户段的Behavior才是关键,Behavior才是让客户端丰富多彩的功臣。

最近有位朋友问我,如何在客户端使用Authentication Service登陆用户以后,用ModalPopupExtender的方式将结果显示给用户呢?其实关键还是在于使用JavaScript来操作ModalPopupBehavior。我在这里演示一下使用JavaScript操作ModalPopupBehavior的方法。

首先,在服务器端放置一个ScriptManager、一个TextBox、一个Panel和一个ModalPopupBehavior。

<asp:ScriptManager ID="ScriptManager1" runat="server" />

<asp:TextBox ID="TextBox1" runat="server" style="display:none;" />

<asp:Panel runat="server" ID="popupPanel"
    style="border: solid 1px black; padding: 10px; width: 300px; display:none;">
    <b style="font-size: 15pt;">Here's the Message</b>
    <br />
    <asp:Button ID="Button1" runat="server" Text="Button" />
</asp:Panel>

<ajaxToolkit:ModalPopupExtender runat="server"
    TargetControlID="TextBox1" PopupControlID="popupPanel"
    OkControlID="Button1" BehaviorID="modalPopup" />

一切都是最平常的使用方式,只是以下几点需要注意:

  1. TextBox的display设为none:因为ModalPoupBehavior必须要有一个TargetControl,而这个TargetControl就作为弹出窗口的触发器。我们现在必须把这个触发器隐藏掉,不过请注意不能将其Visible设为False,否则客户端的DOM结构中就没有这个文本框了。
  2. 弹出Panel的display设为了none:这个已经是使用ModalPoupExtender的规则之一了,如果不将其display设为none,在页面打开的瞬间Panel会出现在页面上,然后马上消失。这样除了让用户看到了Panel之外,还可能影响布局,让页面显得一片混乱。
  3. ModalPopupExtender设置了BehaviorID:这是使用JavaScript操作Ajax Control Toolkit中Behavior的关键。在客户端构造Behavior时可以没有ID,但是如果没有ID的话则无法在客户端操作Behavior对象了。

   然后,我们就可以在客户端放置一个按钮,然后使用JavaScript弹出窗口了。请注意,我们使用了$find通过BehaviorID来得到了ModalPopupBehavior实例,然后调用它的show方法:

<input type="button" value="Popup" onclick="$find('modalPopup').show();" />

这样,窗口就弹出了。其实一切就是这么简单。

可能唯一的问题就是开发人员并不清楚该调用Behavior的哪个方法来工作。这其实并不构成障碍,我们只要查看Behavior的源代码,看看那些没有下划线前缀的方法(即公有方法)中名字和功能比较接近的即可。这就是使用合适方法名的好处,根本不需要些注释就能明白方法的作用——更何况Ajax Control Toolkit中的Behavior注释非常详细。:)

这才是灵活使用Extender的方式。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

29 条回复

  1. 周松柏[未注册用户]
    *.*.*.*
    链接

    周松柏[未注册用户] 2007-06-04 13:44:00

    我是第一个,ohye

  2. Artech
    *.*.*.*
    链接

    Artech 2007-06-04 13:54:00

    很久没见老赵的文章了,终于回归了,呵呵。

  3. Leepy
    *.*.*.*
    链接

    Leepy 2007-06-04 14:07:00

    刚还在研究这个问题呢,没想到就马上看到了,幸运了:)

  4. yinix
    *.*.*.*
    链接

    yinix 2007-06-04 14:31:00

    在项目中我还不怎么敢用关于controltoolkit的相关东西,怕性能低。特别是当一个页面当中 有很多项目的时候,更是不能用。现在只能用extension里面的updatepanel,所以对相关的客户端编程非常地关注。

  5. yinix
    *.*.*.*
    链接

    yinix 2007-06-04 14:56:00

    赵老师:我想问一下,如果不用纯的Ajax(不用asp.net ajax控件),可不可以只使用scriptmanager而不使用Extender控件来实现controltoolkit中那些效果呢?我对behavior还是不太了解。因为我看到你还用了
    <ajaxToolkit:ModalPopupExtender runat="server"
    TargetControlID="TextBox1" PopupControlID="popupPanel"
    OkControlID="Button1" BehaviorID="modalPopup" />

    这样一个控件。

  6. 老赵
    admin
    链接

    老赵 2007-06-04 15:03:00

    @yinix
    UpdatePanel的性能低,AjaxControlTookit里的东西性能高阿,而且用的越多平均性能越高,呵呵。

  7. 老赵
    admin
    链接

    老赵 2007-06-04 15:05:00

    @yinix
    Extender控件只是在客户端使用了Behavior而已,您完全可以直接使用Behavior。

  8. chy710
    *.*.*.*
    链接

    chy710 2007-06-04 15:40:00

    好久没看到老赵的文章了,呵呵,

  9. yinix
    *.*.*.*
    链接

    yinix 2007-06-04 17:27:00

    updatepanel一定要用了,因为项目中要保持样式的一致性,对于页面复杂度高的就直接拉了一个updatepanel了。呵呵。controltoolkit发现页面加载一次发生的请求太多了,所以就放弃了,不过,见到里面很多好的效果,真有点动心啊。因为时间比较紧,也没有很多的时间去研究它,跟您比,.....呵呵,不能比啊。所以每天一开机就把你的博客打开来,看看有没有提高我这方面水平的好文章出现!在此,再一次感谢啊!

  10. 老赵
    admin
    链接

    老赵 2007-06-04 17:31:00

    @yinix
    加载的东西的确多,但是优化手段也比较多阿,预加载,压缩,缓存等等,呵呵。:)

  11. yinix
    *.*.*.*
    链接

    yinix 2007-06-04 18:02:00

    (刚才去吃饭去了)这方面的知识还是比较欠缺的啊。。。还好能遇到赵老师,希望赵老师有空的时候不吝赐教:)

  12. Cat Chen
    *.*.*.*
    链接

    Cat Chen 2007-06-04 18:28:00

    Behavior是不错的模型,然而所有东西都要手动封装为服务器端Control工作量就很大。

  13. FengYan[未注册用户]
    *.*.*.*
    链接

    FengYan[未注册用户] 2007-06-04 19:09:00

    老赵最近忙啊,等了好长时间才看到新的文章。

  14. 沧桑雨迢迢
    *.*.*.*
    链接

    沧桑雨迢迢 2007-06-04 20:10:00

    很需要这样的模型意义分析的文章...嘿嘿,来喘口气

  15. ╃小〥斌╄
    *.*.*.*
    链接

    ╃小〥斌╄ 2007-06-04 21:46:00

    关注下~~

  16. win yee[未注册用户]
    *.*.*.*
    链接

    win yee[未注册用户] 2007-06-05 09:12:00

    支持一下。

  17. yinix
    *.*.*.*
    链接

    yinix 2007-06-05 15:51:00

    赵老师:有一个问题想咨询一下,我想用RenderControl这个方法把在后台实例化的一个用户控件出输出成HTML,可是老是出现问题:XXX控件必须放置在Runat=server的form内才可以。

    这个问题不知道赵老师有没有遇到过。
    本想通过这个方法结合Ajax动态地把用户控件的内容输出来实现的。

  18. 老赵
    admin
    链接

    老赵 2007-06-05 16:59:00

    @yinix
    必须把它加到控件树里去的说。

  19. yinix
    *.*.*.*
    链接

    yinix 2007-06-05 18:12:00

    加进去也不行.
    主要通过以下的方法:
    protected void Page_Load(object sender, EventArgs e)
    {
    if ( Request.Params["Action"] == "getData" )
    {
    Response.Clear();
    Response.Expires = 0;
    Response.ContentType = "application/xml";
    Response.Write(ViewManager.renderControl("myControl.ascx"));
    Response.End();
    }
    }
    //---------------------ViewManager.cs-----------------
    public static string renderControl(string path)
    {

    Page pageHolder = new Page();
    UserControl viewControl = (UserControl)pageHolder.LoadControl(path);
    pageHolder.Controls.Add(viewControl);
    StringWriter output = new StringWriter();
    HttpContext.Current.Server.Execute(pageHolder, output, false);
    return output.ToString();
    }

    //----通过这种方法不行.
    我不明白的地方是:
    为什么使用服务器端普通的控件就可以呢?:
    protected void Page_Load(object sender, EventArgs e)
    {
    if ( Request.Params["Action"] == "getData" )
    {
    Panel pnl = new Panel();
    pnl.ID = "pnl0";
    Button btn = new Button();
    btn.ID = "btn0";
    btn.Text = "动态产生的按键";
    Label lbl = new Label();
    lbl.ID = "lbl0";
    lbl.Text = "动态产生的文本";
    TextBox txt = new TextBox();
    txt.ID = "txt0";
    txt.Text = "我是yinix";
    pnl.Controls.Add(btn);
    pnl.Controls.Add(lbl);
    pnl.Controls.Add(txt);
    StringBuilder strBuilder = new StringBuilder();
    StringWriter strWriter = new StringWriter(strBuilder);
    HtmlTextWriter strHtmlWriter = new HtmlTextWriter(strWriter);
    pnl.RenderControl(strBuilder );
    Response.Clear();
    Response.Expires = 0;
    Response.ContentType = "application/xml";
    Response.Write(strBuilder.toString());
    Response.End();
    }

    真是郁闷哦....

  20. yinix
    *.*.*.*
    链接

    yinix 2007-06-05 18:45:00

    赵老师:我觉得现在很多想用Asp.net Ajax的人都非常想很仔细地学习 Microsoft Ajax Library 里面的客户端编程,虽然官方网站上的Docs也很多,但是总觉得例子不够多,也许是英文不好的原因吧,学起来还是很费力的。
    Dflying(陈黎夫)好像出了第2卷的Asp.net Ajax了,看了他的目录,觉得应该是对官方文档的解释吧。我觉得赵老师可以在空闲的时候一一给出官方文档对对应的示例讲解,那我们可就太幸福啦。:)

  21. 老赵
    admin
    链接

    老赵 2007-06-05 23:54:00

    @yinix
    您的意思是,客户端那些API的示例吗?

  22. 怪怪[未注册用户]
    *.*.*.*
    链接

    怪怪[未注册用户] 2007-06-06 01:44:00

    @Cat Chen
    感觉没什么工作量啊.. 不过是把客户端需要做的事,需要的参数,做个说明就够了..,更多的都是本来就应该做的事

  23. 老赵
    admin
    链接

    老赵 2007-06-06 09:51:00

    @怪怪
    关键是Extender模型封装的好。

  24. 老赵
    admin
    链接

    老赵 2007-06-06 09:51:00

    @Jeffrey Zhao
    补充一下,是Ajax Control Toolkit的Extender模型扩展封装的很好。:)

  25. yinix
    *.*.*.*
    链接

    yinix 2007-06-07 08:55:00

    赵老师:不好意思,来晚了,我指的就是客户端API相关的例子。

  26. 助燃
    *.*.*.*
    链接

    助燃 2007-07-12 19:38:00

    受到了很大的启发,上次一直在找ValidatorCallout控件的气泡提示的效果的method,不过是在输出的html里面找,汗~

  27. 助燃
    *.*.*.*
    链接

    助燃 2007-08-26 20:33:00

    使用ModalPoupExtender要把弹出Panel的display设为了none:最近用到了CollapsiblePanelExtender,默认想让它的状态是收缩的,结果出现了跟ModalPoupExtender一样的情况,页面上展开的Panel一闪而过然后才变成收缩,若将Panel的display设为none,则Panel无法展开,请问赵老师有什么方便的解决方案?

  28. hptnt[未注册用户]
    *.*.*.*
    链接

    hptnt[未注册用户] 2008-05-30 14:42:00

    老赵,能不能用js控制ModalPopupExtender 的关闭,相当于CancelControlID的功能?

  29. shp_yt
    *.*.*.*
    链接

    shp_yt 2009-12-10 22:07:00

    老赵,能不能通过后台代码改变PopupControlID的值来达到让ModalPopupExtender在一个页面内根据不同的按钮弹出不同的ModalPanel呢?

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我