日期:2010-11-09  浏览次数:20479 次

     [注:此段与标题内容无关,可略过] 在看完两集Stargate并且洗了一个澡之后,我终于决定要开始写这篇文章。这是我第一篇真正意义上的原创技术文章,不管技术含量如何,我总算是迈出了这一步。博客其实开过不少,从最早的校园大巴,到博客园,以及我那个用来发牢骚的新浪博客,其实开博客最初的目的就是用来在写程序的同时,记录一下自己的学习的过程。但是后来演变成了用来发牢骚的东西,这也算是我一直以来不能专心钻研的恶果吧,不过所谓亡羊补牢为时未晚,就从这篇文章开始,变得专注一点,再专注一点。由这种专注的思想引导,我最近终于又开始好好的写程序,这次是真的放下了那些不想干的东西,专心致志的开始写我喜欢的C#代码,在我所知道的编程语言里面我最喜欢的是C#和Javascript,后者是种脚本语言,准确地说j是我最近才喜欢上的,我原来以为它也就同我小时候玩的Basic一般,小巧也简单,但是事实证明不是这个样子的,虽然它和VBS一样也是脚本语言,但是在它C语言的外表之下,其实隐藏着更多的内容,这个我可能会写另外的一篇文章来描述它,现在切入正题,我喜欢的.NET平台,不知道为什么01年的时候第一次使用C#语言写代码,就觉得它很漂亮,然后就爱上了他,不过那个时候由于环境的问题,所以一度中断,一直到了04年,才又重新拾起来,但是一年多的时候,我也只是在拉着一堆堆的控件,然后在属性面板里调整啊调整,似乎忘记了Web原来有的样子是怎么样的,后来终于有一样东西换起了我的回忆 -------- Ajax。

        到处都是Ajax开发框架,其实在ASP.NET 2.0发布的时候内部其实就整合了一些类似的内容,在一些数据控件比如GridView上面就有使用,在05年一月份的MSDN Magazine中的一篇《Custom Script Callback in ASP.NET》(中文版 | English)让我认识到了asp.net 里面异步调用的魅力(里面的实现方法仅限于在beta1版本中实现,关于脚本回调部分beta1、beta2以及正式版本之间都有所不同,有兴趣者可以自己参见最近发布的MSDN内容),不过当时也只是玩了一下,后来使用Atlas,也就对它没怎么上心,不过前一段时间一个朋友和我讨论asp.net实现ajax时讲到,atlas实现太过于繁琐,而他要实现的只是几个非常小的内容不需要那么麻烦,由于我对除了这些之外的.NET的ajax框架不熟悉,所以自然而然的就想起了内置的脚本回调机制,利用(经过他本人同意的)朋友的项目,我们编写了很多关于这个的代码,在写完之后我突然发现了一个问题,就是代码太乱了。每个页面都是类似的东西,而且只能传递一个字符串参数让我们在除了交互方面对于一些大开销的数据展示只好使用内嵌框架来实现了。前两天到海图买了一本《Ajax 高级语言程序设计》,看了一部分之后突然想搞明白asp.net 2.0里面的脚本回调又是如果实现的?其实现在转回来头看,《Custom Script Callback in ASP.NET》一文中很多地方已经讲的很明白了,可以无奈当时的水平,很多东西看的都是云里雾里的,光顾者看效果了先贴一个我认为最简洁的实现效果,然后再进行剖析。
        新建一个Default.aspx的页面,在页面上添加一个CheckBox控件,然后打开Default.aspx.cs文件,_Default类添加三个继承的接口ICallbackContainer、ICallbackEventHandler和INamingContainer:

[代码1]

#region ICallbackContainer 成员
public string GetCallbackScript(IButtonControl buttonControl, string argument)
{
    throw new Exception("The method or operation is not implemented.");
}
#endregion

#region ICallbackEventHandler 成员
string temp;

public string GetCallbackResult()
{
    //throw new Exception("Sample Error");
    return temp;
}

public void RaiseCallbackEvent(string eventArgument)
{
    temp = "_____" + eventArgument + " is succeed._____";
}
#endregion

 
转到Default.aspx.cs页面的Page_Load方法中加入下面代码:


[代码2]
proected void Page_Load(object sender, EventArgs e)
{
    string temp = Page.ClientScript.GetCallbackEventReference(this,  "arg",  "Callback",  "context", "OnError", true);
    string script = "function CallServer(arg,context){" + temp + "}";
    Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "abc", script, true);
    CheckBox1.Attributes.Add("onclick", "CallServer('I call Server ','context');");
}

在编辑完CS代码之后,打开Default.aspx文件,在<head>...</head>之间加入下列代码:


[代码3]
<script type="text/javascript">
function OnError(err,context)
{
    alert(err);
}

function Callback(arg,context)
{
    alert(arg);
}
</script>


        这里的CheckBox控件是随便拉上去的,有需要可以随便更改,不过用Button控件的时候可能要注意一下,它默认就会激活OnSubmit事件,所以可能要设置或是直接使用HTML控件就好了。以上的代码算是脚本回调最小化的实现,都是必须的缺一不可。
        使用基本回调的控件必须实现三个接口分别是:ICallbackContainer,INamingContainer和ICallbackEventHandler。其实INamingContainer没有需要实现的接口内容,它只是“标识在 Page 对象的控件层次结构内创建新 ID 命名空间的容器控件”(引自MSDN)。至于ICallbackContainer这个接口,在MSDN(中文版本)里面给出的解释比较模糊,相关联的一些文章也都是介绍脚本回调和ICallbackEventHandler接口的,因为我们这里是用页面作为回调的基础,所以没有使用这个接口要实现的方法GetCallbackScript,但是如果是封装自己的Ajax控件那这个方法就十分有用了,这里我们只是用了ICallbackEventHandler实现的方法来处理数据,因为在Page_Load方法中我注册了一个CallServer的方法,然后依附于CheckBox的OnClick事件上触发,这样我们就可以看法一个比较清晰的调用过程了。
        后面[代码3]我实现了两个Javascript方法,一个是用来处理调用出错的,另外一个就是用来处理调用成功之后处理返回信息的了。在[代码1]里面有一段抛出异常的代码被我注释掉了,通过这句代码就可以模拟调用OnError方法了。