Hello World
Spiga

为WebForms说几句话,以及一些ASP.NET开发上的经验(3)

2007-12-23 18:44 by 老赵, 10797 visits

四、生成复杂的ID难以使用JavaScript操作

我在上一篇文章的最后提到了,虽然使用WebForms我们能够对于页面上的HTML属性和样式等进行自由的定制和控制,但是有一点是毋庸置疑的,我们没有办法(正常的办法吧,Hack不算)让服务器端控件在客户端生成一个简单的ID。例如,一个TextBox控件,在服务器端的ID是txtUserName,但是最终在客户端生成的ID可能是LoginForm_txtUserName,因为它被放在一个ID为LoginForm的NamingContainer中。

有了组件模型,就出现了大量控件。控件最主要的目的之一就是复用,而复用的一个特点就是应该高度内聚,而不依赖于外部环境。因此,为了使组件内部的服务器控件最终生成的客户端ID能够在页面上唯一,WebForms引入了NamingContainer这个概念。在NamingContainer中的服务器端控件最终在客户端生成的ID,会使用NamingContainer的“客户端ID”作为前缀。如此“递归”的做法保证了服务器控件在客户端的ID唯一。

Web 2.0在业界风卷残云般的势头至今还未停歇,与其有密切相关的AJAX技术也被广泛使用。AJAX技术从根本上讲,是一种在浏览器中使用JavaScript实现的技术,因此使用JavaScript操作DOM元素的情况非常多见。在非WebForms的页面中我们可以编写如下的代码:

<input type="text" id="textBox" />

<script language="javascript" type="text/javascript">
    document.getElementById("textBox").value = "Hello World!";
</script>

但是由于NamingContainer的缘故,我们在使用WebForms的服务器端的控件时就可能无法通过textBox在客户端获得文本框(生成的<input />元素)。为了解决这个问题,服务器端的控件模型提供了一个ClientID属性,通过这个属性,我们就可以在服务器端得到控件最终在客户端的ID。例如,如果上面的代码放在一个用户控件里的话,就一定必须写成如下形式:

<%@ Control Language="C#" AutoEventWireup="true" %> 

<asp:TextBox runat="server" ID="textBox" />

<script language="javascript" type="text/javascript">
    document.getElementById("<%= this.textBox.ClientID %>").value = "Hello World!";
</script>

此时,当控件被放到页面上之后,它在客户端生成的代码则会是:

<input name="DemoControl1$textBox" type="text" id="DemoControl1_textBox" />

<script language="javascript" type="text/javascript">
    document.getElementById("DemoControl1_textBox").value = "Hello World"!;
</script>

请注意<input />元素的name和id,它们都留下了NamingContainer的痕迹。由于我们在页面上使用了<%= %>标记直接输出了服务器控件的ID,这样在客户端的JavaScript代码也就可以正确访问到服务器端<asp:TextBox />对应的客户端<input />元素了。

这种在设计器很难预测的客户端ID,就是使用WebForms时所谓的“客户端ID污染”。

接下来我们不妨来看一个略为复杂点的例子:

<%@ Control Language="C#" AutoEventWireup="true" %> 

<asp:TextBox runat="server" ID="textBox" />

<script language="javascript" type="text/javascript">
    var counter = 0;

    function increase()
    {
        document.getElementById("<%= this.textBox.ClientID %>").value = (counter++);

        window.setTimeout(increase, 500);
    }

    increase();
</script>

上面这段JavaScript代码的作用是每500为一个计数器加1,并且显示在文本框上。随着项目的发展,页面上复杂的JavaScript代码会越来越多,于是我们就会想办法将其转移到js文件中并且在页面上引用它们。使用js文件的好处很多,便于进行代码管理是一方面,但是最重要的好处之一还是对于性能的提高。如果JavaScript代码完全写在页面上,这样每次加载页面都需要下载这些JavaScript代码,而js文件可以缓存,这样客户端只需要在第一次加载时下载这个文件就可以了。减少了客户端与服务器之间数据通信的大小,也就加快页面加载的速度,提高了性能。

不过问题就此出来了:为了能够正确引用到页面上的某个服务器控件生成的DOM元素,我们就必须在页面中使用<%= %>标记来输出控件的ClientID,但是<%= %>无法写在js文件中,这可怎么办?于是很多人着急了起来,我也不时会收到此类问题,似乎很难找到合适的解决办法。于是“客户端ID污染”似乎也就成了一个使用WebForms时非常严重的问题。

有些朋友会说:“这个没有问题啊,仔细观察ClientID的组成方式能够很容易找到规律的。”服务器控件的ClientID是由自身ID和它所在的NamingContainer“树”来共同决定的,因此在理论上我们也完全可以在设计器得到“已经放置在页面中”的某个服务器控件的客户端ID,并将其写进JavaScript代码中。话虽如此,的确没错,但是这个解决方案实在不好,因为它违背了控件的重要特性:“复用”。作为一个控件来说,它可能会被放在任意的NamingContainer树下,也就是说,它的客户端ID在不同的环境中并不固定。另外,如果控件上层NamingContainer树中有任何一个的服务器端ID被修改的话,js文件中使用的ID就需要进行改变,这样实在不利于的维护,随着项目增大,此类问题会愈发明显。

那么我们究竟该怎么做呢?

在设法解决这个问题之前,我们先来思考一下这个问题。如果我们没有使用WebForms进行开发,就在普通的页面上编写代码,那么我们对于上面的功能会如何将其提取到js文件中呢?嗯,就直接在代码中通过textBox这个ID来获得DOM元素吧。那么好,请您先回答我以下几个疑问:

  1. 为什么要写textBox而不是其他ID呢?
  2. 如果其他页面上有个同样需要实现的功能,而那个文本框的id是txtCounter,那么该怎么作呢?
  3. 如果一张页面上有两个文本框需要显示这样的计数器,那么又该怎么做呢?

上面的几个疑问其实只反应了一件事情,那就是这个计数器的复用性实在太差。什么叫做好的复用性呢?那么我们来看一下一个典型的示例,MaskedEditExtender。我们来看看它是怎么做的:

<ajaxToolkit:MaskedEditExtender
    TargetControlID="TextBox1"
    Mask="9,999,999.99"
    MessageValidatorTip="true"
    OnFocusCssClass="MaskedEditFocus"
    OnInvalidCssClass="MaskedEditError"
    MaskType="Number"
    InputDirection="RightToLeft"
    AcceptNegative="Left"
    DisplayMoney="Left"
    ErrorTooltipEnabled="True" />

MaskedEditExtender的第一个属性TargetControlID,就可以决定了究竟是为哪个文本框添加效果,然后效果的样式可以由MaskType和Mask决定,获得焦点的样式和输入错误的样式可以由OnFocusCssClass和OnInvalidCssClass属性决定,连字符输入的顺序都可以定制。

这就是复用:爱怎么用,就怎么用。爱给谁用,就给谁用。想什么时候用,就什么时候用。

要复用,一般总需要组件化或模块化,内部实现通用的功能,而具体的信息应该由外部传入。例如我们上面的计数器就应该进行改造(用到了MS AJAX Lib里的Function.createDelegate方法):

function Counter(textBoxId, interval)
{
    this._counter = 0;
    this._textBox = document.getElementById(textBoxId);
    this._interval = interval;
}
Counter.prototype =
{
    run : function()
    {
        this._textBox.value = (this._counter ++);
        window.setTimeout(
            Function.createDelegate(this, this.run), this._interval);           
    }
};

现在这个技术器的复用性已经有质的飞跃了,因为我们可以随意指定一个客户端的文本框进行显示,并且可以自由地设置计数器增长的间隔时间。于是我们在WebForms页面中就可以写如下的代码了:

<asp:TextBox runat="server" ID="textBox1" />
<asp:TextBox runat="server" ID="textBox2" />

<script language="javascript" type="text/javascript">
    new Counter("<%= this.textBox1.ClientID %>", 500).run();
    new Counter("<%= this.textBox2.ClientID %>", 1000).run();
</script>

现在WebForms客户端ID污染已经不构成问题了吧!

其实解决客户端ID污染的做法用一句话就能说清:“将不变的部分提取至js文件,将变化的部分(例如服务器控件的客户端ID)留在页面中”。但是我在这里将它上升到组件化的高度,因为它能让我们开发出更优秀的客户端程序。组件化的客户端编程方式较之传统的零散function的做法,更有利于代码的管理,并且增强了复用性和可维护性。有人说,客户端ID污染问题使脚本代码很难做到“内聚”——可能他的意思是将脚本代码提取到js文件中吧——但是我认为,这种污染“迫使”我们使用组件化的方式进行客户端开发,而这种组件化或者模块化的做法恰恰提高了代码的内聚性。

不过,似乎组件化的编程方式会写更多的代码,不是吗?从理论上来说,可能的确是。不过需要注意的是,我上面提出的例子非常简单,简单到了其中的一半代码是用于“组件化”编程的“骨架”上。而对于一个略为复杂的功能来说,例如一个通用的表单验证组件,或者客户端级联组件,增加的这点“骨架”还算得了什么呢?

这也算是一种因祸得福吧。

 

相关文章:

为WebForms说几句话,以及一些ASP.NET开发上的经验(1):ViewState、性能

为WebForms说几句话,以及一些ASP.NET开发上的经验(2): 生成丑陋的HTML,难以进行样式控制

未完待续:

五、MVC

六、单元测试

所属话题:WebForms与MVC
Creative Commons License

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

Add your comment

71 条回复

  1. lovecherry
    *.*.*.*
    链接

    lovecherry 2007-12-23 18:54:00

    沙发

  2. ilovedotnet
    *.*.*.*
    链接

    ilovedotnet 2007-12-23 18:59:00

    期待老赵接下来的两篇文章!支持!

  3. birdshome
    *.*.*.*
    链接

    birdshome 2007-12-23 19:06:00

    hehe,现在我一般用这种模型:

    javascript控件:
    function Control() {}
    Control.Initialize(clientId) {};

    ASP.NET控件输出:
    <tagName id='tagA'>[nested tags]</tagName>

    然后在HTML页面中输出:
    <Script>Control.Initialize($('tagA'));</Script>

    在[nested tags]中,查找元素不再依赖id,都根据tags的hiberarchy来获取
    原来写过文章有说道:设计有复杂客户端Script的服务器控件,不过这个文章很old了,还有很多细节没有讲到。

  4. henry
    *.*.*.*
    链接

    henry 2007-12-23 19:13:00

    其实对于很多系统来说特别是企业自身的系统,其维护成本非常重要.
    面对需求的改进和变更代码的可以维护性非常重要,front controller(大家所说的MVC)的好处action行为明确,而page controller(大家所说的webfrom)通常是几个action(事件)混合处理来处理逻辑,从容易而引起代码混乱难以维护.
    一个系统好维护的逻辑代码比什么html,样式或那点性能都重要得多;道理很简单系统及其代码的好坏只会和编写的人有关系,对于这么上层的应用模式来说可以说搭不上边.

  5. SZW
    *.*.*.*
    链接

    SZW 2007-12-23 19:33:00

    对于这种“ID污染”谈一点个人的想法和做法。
    在WebForm里面,ID需要复用的话(不止是一个方法内的复用),我通常会这么写:


    <asp:TextBox runat="server" ID="textBox1" />
    <asp:TextBox runat="server" ID="textBox2" />

    <script language="javascript" type="text/javascript">
        var textBox1_CID = "<%= this.textBox1.ClientID %>";
        var textBox2_CID = "<%= this.textBox2.ClientID %>";

        new Counter(textBox1_CID , 500).run();
        new Counter(textBox2_CID , 1000).run();
        new Counter2(textBox1_CID , 500).run();
        new Counter2(textBox2_CID , 1000).run();
    </script>



    在比较多的复用情况下,这样效率还是挺高的,并且可读性比较强。

    但是通常这样还是需要“过渡”一下,所以有时候,结合jQuery开发的时候,我干脆舍去ID不考虑,但就设置它的CSS样式,只要建立一套自己的命名规则,可以保证页面上没有重复对象,也可以故意制造一组对象同时操作。这样就把这“污染源”绕开了。

  6. 蛙蛙池塘
    *.*.*.*
    链接

    蛙蛙池塘 2007-12-23 19:45:00

    赵兄真是神速呀,呵呵,我先吃完饭再回来看。我记webControls生成clientid是有一个接口来控制的,后来找不到了,也许这个接口没有对外公开吧,我一会儿反编译一下system.web.controls看看

  7. 老赵
    admin
    链接

    老赵 2007-12-23 19:59:00

    --引用--------------------------------------------------
    birdshome: hehe,现在我一般用这种模型:

    javascript控件:
    function Control() {}
    Control.Initialize(clientId) {};

    ASP.NET控件输出:
    <tagName id='tagA'>[nested tags]</tagName>

    然后在HTML页面中输出:
    <Script>Control.Initialize($('tagA'));</Script>

    在[nested tags]中,查找元素不再依赖id,都根据tags的hiberarchy来获取
    原来写过文章有说道:设计有复杂客户端Script的服务器控件,不过这个文章很old了,还有很多细节没有讲到。
    --------------------------------------------------------
    如果只是要找一个元素的话,还是不要通过hierarchy来获得了八,这个也是容易变得东西。

  8. Leepy
    *.*.*.*
    链接

    Leepy 2007-12-23 20:00:00

    @蛙蛙池塘
    WebControl是继承自Control,它提供了一个虚拟属性ClientID

  9. 老赵
    admin
    链接

    老赵 2007-12-23 20:00:00

    @SZW:
    你说的这个做法和我说的不是一模一样的嘛……
    其实样式和ID的概念还是不同的,在合理的概念下编程还是比仅仅为了获取对象而设置样式来的妥当吧。当然,如果你的目的是“批量取对象”而不是“绕开ID”,那么还是值得使用的做法,呵呵。

  10. 老赵
    admin
    链接

    老赵 2007-12-23 20:04:00

    --引用--------------------------------------------------
    henry: 其实对于很多系统来说特别是企业自身的系统,其维护成本非常重要.
    面对需求的改进和变更代码的可以维护性非常重要,front controller(大家所说的MVC)的好处action行为明确,而page controller(大家所说的webfrom)通常是几个action(事件)混合处理来处理逻辑,从容易而引起代码混乱难以维护.
    一个系统好维护的逻辑代码比什么html,样式或那点性能都重要得多;道理很简单系统及其代码的好坏只会和编写的人有关系,对于这么上层的应用模式来说可以说搭不上边.
    --------------------------------------------------------
    用WebForms会不会造成混乱其实也是看如何编写的,如果要说WebForm多个Action混在一起的话,MVC框架中的Controller也不是定义了多个Action吗?可是并没有引起任何混乱阿。
    主要还是看开发方式,这个开发方式可以从使用经验中总结,虽然是微软的东西也并不一定要完全跟着微软走。比如可以抛弃dataset,gridview等东西。

  11. 老赵
    admin
    链接

    老赵 2007-12-23 20:11:00

    @金色海洋(jyk)
    不好意思,你的输入破坏了页面结构,我只能删除了。:)
    要得到文本框客户端id自然只需要this.textBox.ClientID,如果文本框在其他框架里,那么在Page中去操作它本身就是不合理的。
    至于绑定控件里的TextBox,就是批量取对象了,那么不适合通过ID,通过name/tagName或class等能够批量获取对象的方式都可以。

  12. kiler
    *.*.*.*
    链接

    kiler 2007-12-23 20:13:00

    @henry

    MVC做企业最大的缺点就是表现层不如webform好用,webform可以通过webcontrol实现很复杂页面操作,而使用者无须具备丰富的js和html开发能力,不要说MVC有Jquery之类的东东,这些东西不是一般的菜鸟可以玩的转的,但是webcontrol可以很快学会使用。

    --引用--------------------------------------------------
    front controller(大家所说的MVC)的好处action行为明确,而page controller(大家所说的webfrom)通常是几个action(事件)混合处理来处理逻辑,从容易而引起代码混乱难以维护
    --------------------------------------------------------

    对于以上问题,使用分层体系结构可以很好的解决,page controller只是处理一些表现层上的显示逻辑以及页面跳转即可,具体业务处理通过调用业务层类即可完成,不存在难以维护的问题。

    我觉得不管是MVC还是webform都可以做出可维护性好的程序,左右程序质量是最重要的因素是开发者本身,而不是框架。

  13. 恶灵旧都
    *.*.*.*
    链接

    恶灵旧都 2007-12-23 20:16:00

    这样做也是很麻烦啊!!!

    ClientID确实很麻烦

  14. SZW
    *.*.*.*
    链接

    SZW 2007-12-23 20:30:00

    @Jeffrey Zhao
    是的,从处理逻辑上来说确实不好。"绕开ID"只是我在用jQuery一起开发的时候用的方法,毕竟这也是jQuery符合样式表查询格式的一个特色,一般情况下还是ClientID,但总归没有直接区ID方便。

  15. 老赵
    admin
    链接

    老赵 2007-12-23 23:06:00

    --引用--------------------------------------------------
    kiler: @henry
    对于以上问题,使用分层体系结构可以很好的解决,page controller只是处理一些表现层上的显示逻辑以及页面跳转即可,具体业务处理通过调用业务层类即可完成,不存在难以维护的问题。

    我觉得不管是MVC还是webform都可以做出可维护性好的程序,左右程序质量是最重要的因素是开发者本身,而不是框架。
    --------------------------------------------------------
    这话说得不得不赞啊,无论MVC框架还是WebForms其实都只是业务逻辑的触发,而不是业务逻辑的容器。
    怎么写都是看人的。

  16. 老赵
    admin
    链接

    老赵 2007-12-23 23:07:00

    --引用--------------------------------------------------
    恶灵旧都: 这样做也是很麻烦啊!!!

    ClientID确实很麻烦
    --------------------------------------------------------
    麻烦吗?不麻烦啊,呵呵。

  17. 静水≈深流
    *.*.*.*
    链接

    静水≈深流 2007-12-24 08:43:00

    好文

  18. craboYang
    *.*.*.*
    链接

    craboYang 2007-12-24 08:51:00

    支持 SZW , 俺也是这么干的.


    不麻烦么? 麻烦,哈.
    --------------------------------------------------------
    麻烦吗?不麻烦啊,呵呵。

  19. henry
    *.*.*.*
    链接

    henry 2007-12-24 08:53:00

    @Jeffrey Zhao
    MVC框架中的Controller也不是定义了多个Action吗?
    问题在于front controller的每一个action是就针对page服务的,多个action之并不存在相关干扰.不过代码好坏是人写的你也可以在一个front controller的action作非常复杂的东西.总之你想要那种模式下的代码写得多烂就有多烂是非简单相反要写得好几乎很难.

    @kiler
    问题本来就是那样,系统和代码的好坏基本就与人有关系,并不存在着那模式才适合所谓企业级应用的说法.真正做过规模比较大的企业系统的人都清楚如何把逻辑代码写得便于维护和修改才是解决问题的跟本.

  20. 蛙蛙池塘
    *.*.*.*
    链接

    蛙蛙池塘 2007-12-24 09:16:00

    可以给dom元素分配一个自定义属性customid,然后自己写一个getbycustomid的方法来获取dom

  21. 蛙蛙池塘
    *.*.*.*
    链接

    蛙蛙池塘 2007-12-24 09:22:00

    如果服务器控件不好自定义属性的话,用css冒充clientid也行

  22. beyondjay
    *.*.*.*
    链接

    beyondjay 2007-12-24 09:33:00

    Good Topic!

  23. 老赵
    admin
    链接

    老赵 2007-12-24 10:18:00

    --引用--------------------------------------------------
    henry: @Jeffrey Zhao
    MVC框架中的Controller也不是定义了多个Action吗?
    问题在于front controller的每一个action是就针对page服务的,多个action之并不存在相关干扰.不过代码好坏是人写的你也可以在一个front controller的action作非常复杂的东西.总之你想要那种模式下的代码写得多烂就有多烂是非简单相反要写得好几乎很难.
    --------------------------------------------------------
    还是和开发者相关了,我现在发现MVC框架和WebForms其实只是把某些代码写到不同的地方,逻辑真的很像……

  24. 木野狐(Neil Chen)
    *.*.*.*
    链接

    木野狐(Neil Chen) 2007-12-24 10:32:00

    不倾向于把 action 拆分到最小,很多时候这样做反而造成代码到处散落、难以理解和调试。因为你做出那么多 action, 最终还要做很复杂的 controller 来管理这些 action 的跳转关系,再去 render 不同的 view.. 想想就复杂。

    asp.net 的 page controller + user control + custom control .. 的方式,不明白有什么不好?这么多人反对。

  25. 老赵
    admin
    链接

    老赵 2007-12-24 10:35:00

    --引用--------------------------------------------------
    木野狐(Neil Chen): 不倾向于把 action 拆分到最小,很多时候这样做反而造成代码到处散落、难以理解和调试。因为你做出那么多 action, 最终还要做很复杂的 controller 来管理这些 action 的跳转关系,再去 render 不同的 view.. 想想就复杂。

    asp.net 的 page controller + user control + custom control .. 的方式,不明白有什么不好?这么多人反对。
    --------------------------------------------------------
    关键还是合理使用,比如开发时遵守一定准则,免得产生逻辑混乱的代码。

  26. 木野狐(Neil Chen)
    *.*.*.*
    链接

    木野狐(Neil Chen) 2007-12-24 10:35:00

    特别在一个页面上有复杂的 ajax 交互时更是如此。
    action/view 如何跳转,如何选择?

    我一直觉得做复杂的 web 应用 mvc 并不是好的架构。
    其实分离了 template 就可以了,其他的分离完全是自找麻烦。

  27. 驿路梨花
    *.*.*.*
    链接

    驿路梨花 2007-12-24 10:41:00

    是篇好帖子。知道了一些东西。也不妄加评论了。支持一下。

  28. 木野狐(Neil Chen)
    *.*.*.*
    链接

    木野狐(Neil Chen) 2007-12-24 10:45:00

    我开发时最喜欢用页面继承,master page, user control 等方式进行逻辑复用,尽量满足 DRY 的要求,这些特征我感觉 mvc 是没有的。

    mvc 模式有点把软件开发想像的简单了,如果都要靠多个不同视图的跳转,控制器操纵来解决问题,表面上似乎拆分的很细,其实不然。
    遇到复杂页面时,mvc 将付出比 page controller 多好几倍的代价才能解决。

    我觉得,不管用何种模式,只要能做到便于重用,做到 DRY,就是好模式。
    在这方面,master page / user control / 以及后台类可继承的种种特征,是 asp.net 的精华!因为他们都能很好的实现重用。把这些都抛弃掉去弄什么 mvc,意思不大。

  29. Ray  Zhang[未注册用户]
    *.*.*.*
    链接

    Ray Zhang[未注册用户] 2007-12-24 11:48:00

    老赵的这个系列和讨论很不错。

    比大家评比年终总结的更有技术意义:)

  30. henry
    *.*.*.*
    链接

    henry 2007-12-24 11:52:00

    @木野狐(Neil Chen)
    你所说的master page / user control / 以及后台类可继承的种种特征在front controller里都可以使用并不需要抛充(可能有些在使用方式上有所改变,要不是MS也没有必要在webform的基础实现其front controller版本),只是事件有所冲突被抛充而已.

  31. 木野狐(Neil Chen)
    *.*.*.*
    链接

    木野狐(Neil Chen) 2007-12-24 12:02:00

    @henry
    你说的没错,我知道这些在 asp.net mvc 中有保留,但其实他们的内涵已经变了,变成了 template 的一种复用/组织方式; 事件不支持很可惜。

  32. henry
    *.*.*.*
    链接

    henry 2007-12-24 12:25:00

    @木野狐(Neil Chen)
    事件对某部分人来说就是邪恶产生的源头,因为方便所以很多人直接在里添加逻辑代码+几个事件组合完成逻辑处理.这样的代码在功能变更和维护时对相关人员来说可以说恶梦.front controller尽可以把完成功能的代码域缩小来达到一个比较规范的编写规则.
    其实这并没有什么可惜,现在不是更好MS提供两种方式给使用者选择.我们不能认为有了模式就把程序员弱化,人是本身也是非常邪恶的可以把好的变成不好的:)

  33. 蛙蛙池塘
    *.*.*.*
    链接

    蛙蛙池塘 2007-12-24 12:28:00

    同志们给贴一个front controller和page controller的链接,我忘了,那天没细看,谢谢。

  34. thisisbody
    *.*.*.*
    链接

    thisisbody 2007-12-24 12:28:00

    good

  35. 老赵
    admin
    链接

    老赵 2007-12-24 13:29:00

    --引用--------------------------------------------------
    henry: @木野狐(Neil Chen)
    事件对某部分人来说就是邪恶产生的源头,因为方便所以很多人直接在里添加逻辑代码+几个事件组合完成逻辑处理.这样的代码在功能变更和维护时对相关人员来说可以说恶梦.front controller尽可以把完成功能的代码域缩小来达到一个比较规范的编写规则.
    其实这并没有什么可惜,现在不是更好MS提供两种方式给使用者选择.我们不能认为有了模式就把程序员弱化,人是本身也是非常邪恶的可以把好的变成不好的:)
    --------------------------------------------------------
    事件模型还是很好的,直观的操作,呵呵——关键还在于规范。在这个层面上就不太应该说是WebForms的问题了。

  36. henry
    *.*.*.*
    链接

    henry 2007-12-24 13:51:00

    @Jeffrey Zhao
    所以听到别人说webform不适合企业应用感到很郁闷,当这种想法在那些人脑子里形成主观意识的情况下基本不可能扭转他的看法.不知是一朝被蛇咬十年怕草绳还是出于别的原因.

  37. longer[未注册用户]
    *.*.*.*
    链接

    longer[未注册用户] 2007-12-24 19:44:00

    将不变的部分提取至js文件,将变化的部分(例如服务器控件的客户端ID)留在页面中


    J大侠 令我豁然开朗啊

  38. Cat Chen
    *.*.*.*
    链接

    Cat Chen 2007-12-24 22:28:00

    Jeffz已经把该说的都说了,哈哈……觉得你和Bean都一样,把Microsoft的东西剥到剩下自己需要的,再重新创造之后才拿来用。

  39. 老赵
    admin
    链接

    老赵 2007-12-25 00:27:00

    @Cat Chen
    还好还好,还不算再创造,只是使用而已,呵呵。

  40. 小謝[未注册用户]
    *.*.*.*
    链接

    小謝[未注册用户] 2007-12-31 17:10:00

    期待后2篇文章

  41. 武眉博<活靶子.Net>
    *.*.*.*
    链接

    武眉博<活靶子.Net> 2007-12-31 17:39:00

    webforms中还有一个污染源就是验证控件 每个验证控件都在页面底部生成一堆javascript脚本 如果一个页面上用到10个以上验证控件,那些脚本体积还是不小的。

  42. 老赵
    admin
    链接

    老赵 2007-12-31 19:03:00

    @武眉博<活靶子.Net>
    不过Validator实在不实用。

  43. Bob5[未注册用户]
    *.*.*.*
    链接

    Bob5[未注册用户] 2008-01-03 14:35:00

    真是佩服.无语....

  44. llinzzi[未注册用户]
    *.*.*.*
    链接

    llinzzi[未注册用户] 2008-01-05 11:43:00

    老赵说得这些的确是asp.net中会遇到的问题,特别是asp等转向.net的朋友,
    讨厌的viewstate,乱七八糟的html,恐怖的ID。这些起初也让我非常反感asp.net,觉着很多东西都没法自己控制,但慢慢的漫漫的,我爱上了webforms,对了,还有webforms的生命周期,也很棒,不知道mvc有么?

  45. 老赵
    admin
    链接

    老赵 2008-01-05 11:51:00

    @llinzzi
    MVC和WebForms是两个模型,没有关注生命周期。

  46. zhangy[未注册用户]
    *.*.*.*
    链接

    zhangy[未注册用户] 2008-01-06 02:25:00

    LZ我自己做了一下实验,可是好像这个控件ID污染的现象没有啊,我是VSTS05 SP1.两种方式都可以实现结果.代码如下.如果方便回复一下哦,或者邮件也可以,谢谢了哦
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

    <!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>

    <script language="javascript" type="text/javascript">
    function Hello()
    {
    document.getElementById("<%= this.TxtBox1.ClientID %>").value = "Hello World!";
    document.getElementById("TextBox1").value="Hello";
    }
    </script>

    </head>
    <body>
    <form id="form1" runat="server">
    <div>
    <asp:Button ID="Btn1" runat="server" Text="Btn1" OnClientClick="Hello();" />
    <asp:TextBox ID="TxtBox1" runat="server"></asp:TextBox>
    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox></div>
    </form>
    </body>
    </html>

  47. 老赵
    admin
    链接

    老赵 2008-01-07 01:29:00

    @zhangy
    没有放在NamingContainer中

  48. 小鹿
    *.*.*.*
    链接

    小鹿 2008-01-18 09:51:00

    我的问题和@zhangy 一样
    LZ您的回答我是不怎么理解,没有放在NamingContainer中是什么 意思
    哪种情况是在NamingContainer中的 哪种不是呢

  49. 老赵
    admin
    链接

    老赵 2008-01-18 09:59:00

    @小鹿
    放在NamingContainer中会导致客户端ID变化,NamingContainer是指实现了INamingContainer的接口

  50. philipLee[未注册用户]
    *.*.*.*
    链接

    philipLee[未注册用户] 2008-01-31 10:07:00

    好像在DataList套的服务器控件不能实现?

  51. 老赵
    admin
    链接

    老赵 2008-01-31 11:24:00

    @philipLee
    可以阿

  52. 老钱
    *.*.*.*
    链接

    老钱 2008-03-14 16:08:00

    一口气看完三往篇,单元测试我很期待,望加快步伐

  53. 游客[未注册用户]
    *.*.*.*
    链接

    游客[未注册用户] 2008-04-09 00:22:00

    好文章哈,感觉相当于构建一个asp.net 和 js 组成的 客户端组件了哈!

  54. 艾面条
    *.*.*.*
    链接

    艾面条 2008-05-04 11:31:00

    将不变的部分提取至js文件,将变化的部分留在页面中.
    ----
    实在是好。
    改变了我很多不理智的想法。
    真的谢谢。

  55. asp.net爱好者[未注册用户]
    *.*.*.*
    链接

    asp.net爱好者[未注册用户] 2008-06-02 03:05:00

    恩,不错,我最近也悟到了和这三篇文章相似的道理,不过没有博主的思路清晰。学习了

  56. Gapple[未注册用户]
    *.*.*.*
    链接

    Gapple[未注册用户] 2008-06-03 16:18:00

    个人感觉,扎实的JavaScript基础才是王道。其实我路过这里实在没资格发表评论。因为我是从ASP.NET脱离以后在摸索一种可以自由发挥的模式的人。以前用master page的时候,因为控件ID污染的问题,几乎改动了所有的JavaScript,从那以后,我就发现真的无法驾驭ASP.NET这个猛兽,因为我看到太灵活的HTML和JavaScript的组合要被限定到框架中是一件多么痛苦的事情。我本身也不会接触到大型项目,所以,干脆放弃用ASP.NET框架去做今后的小项目。让页面灵活一些,看来只有自己用一种服务器端语言简单做一个符合自己习惯的框架比较好一些。拿来的框架总是会感觉别扭。目前本人正在自由散漫的瞎转,今天看看JSP,明天看看ASP.NET,这阵子回归到了自己的最爱:PHP。

  57. 爱在戏院前
    *.*.*.*
    链接

    爱在戏院前 2008-07-05 19:17:00

    我一般用class.....作为获取的id

  58. 一抹微蓝
    *.*.*.*
    链接

    一抹微蓝 2008-08-29 16:24:00

    赵兄,继续写啊

  59. xyfwef[未注册用户]
    *.*.*.*
    链接

    xyfwef[未注册用户] 2008-11-29 15:48:00

    请问老赵:Counter.prototype =
    {
    run : function()
    {
    this._textBox.value = (this._counter ++);
    window.setTimeout(
    Function.createDelegate(this, this.run), this._interval);
    }
    };
    为什么要用prototype
    而不是
    this._counter = 0;
    this._textBox = document.getElementById(textBoxId);
    this._interval = interval;
    this.run =run;
    呢,直接在对象上+个run方法撒,为什么非要用prototype

    ,是因为有之就用之?

  60. AlexChen
    *.*.*.*
    链接

    AlexChen 2009-02-22 14:45:00

    看老赵写的文章就是舒服... :-)

  61. 老赵
    admin
    链接

    老赵 2009-02-22 17:51:00

    @AlexChen
    谢谢支持

  62. 老赵
    admin
    链接

    老赵 2009-02-22 17:52:00

    @xyfwef
    之间this.run,会让每个Counter实例多一个方法,增加内存开销。prototype的话,相当于定义在“类型”上了,是公用的。

  63. bravf[未注册用户]
    *.*.*.*
    链接

    bravf[未注册用户] 2009-03-05 22:31:00

    太牛了,老赵,期待你写更多的关于webForms的文章。

  64. 猪小广
    *.*.*.*
    链接

    猪小广 2009-10-16 13:40:00

    假如我的一个js函数中间用到了10个被染ID的control,那我企不是要传十个参数进去? 迷惑中……

  65. 老赵
    admin
    链接

    老赵 2009-10-16 14:03:00

    @猪小广
    如果这10个control都是无关的,那么的确要这么传。
    但是,其实在很多场景下,往往只要一两个控件的id,其他的通过DOM结构等关系就可以了。

  66. Hank.Wen
    *.*.*.*
    链接

    Hank.Wen 2009-12-29 14:48:00

    这个不错 就是为什么我按照这样写了以后 居然文本框中只有 0呢。 郁闷中 你哪些代码是放到普通的 JS文件中的吗?

  67. allentranks
    *.*.*.*
    链接

    allentranks 2010-03-09 11:12:00

    未完待续:

    五、MVC

    六、单元测试
    -----
    以上没有了吗??1年后继续期待ing

  68. 正义
    124.207.163.*
    链接

    正义 2010-09-17 10:02:14

    鄙视你------------------

    做为一个小有水平的程序员,你怎么可以攻击人家北大青岛?有本事你去教那么多学生。 这是说明你学会了吃饭的技术而丢弃了做人的品质,这么差的人口还有脸出来混?垃圾……

  69. 正义
    124.207.163.*
    链接

    正义 2010-09-17 10:07:33

    光有技术没人口怎么混???

  70. 正义
    124.207.163.*
    链接

    正义 2010-09-17 10:08:06

    没人品怎么混?你?

  71. 正义
    124.207.163.*
    链接

    正义 2010-09-17 10:08:08

    没人品怎么混?你?

发表回复

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

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

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

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

使用Live Messenger联系我