2004年09月08日

准备把所有技术文章和感想搬家到csdn blog

http://blog.csdn.net/blueoxygen

2004年09月04日

有天下无敌的三大绝招,那就是”打不过你就模仿你(这让我想起电影秘密客)。再打不过就和你比流血,看谁流得久(这让我想起吸血鬼)。最后如果再不行的话,那就挖光你的人(这让我想起电影Other People’s Money)”。
—–From 李维<Borland 传奇>

我向来爱做个看客,不喜欢汤浑水,可是现在我越来越热衷于汤浑水了,因为我看到了如此都的人格卑劣的idot却在csdn装作除恶扬善的大侠士。为什么?很简单,只要涉及到mircosoft,那么用任何恶毒的语言攻击好像都不过分,无论这里涉及的是和ms到底是怎么样的关系。
首先,暂时不必回首过去的,因为那是java与.net linux与windows的技术之争,虽然避免不了口水,但是,大家只不过想把对方说成技术上是垃圾,无耻的抄袭 偷窥者而已。本来我喜欢看这种热闹,因为对于我这个菜鸟来说,可以从口水中看到互相技术的比较。
        本来我并非是一个ms的拥护者,看到这种争吵没有立场,只是对其中的攻击感觉丢人,丢中国人的脸。但是,现在,越来越受不了某些人了,好像被洗脑子了一样,好像bill让他妻离子散
看看下面这个   【新闻】天才大师来访!Lippman将现身微软Tech.Ed 2004
        如果lippman不是现在在ms工作呢?那么会有如此的攻击么?多少人在他的经典巨做中受益?可是如今却不惮用最恶劣的语言攻击。ms的销售策略也许是无耻的,但是,作为ms的反对者,本来未必就是一件清高的事情,而如今,反而由于部分人的低等素质,反ms阵营里面,已经慢慢变了味道,有些让人作呕。自己没有为linux做出任何贡献 没有为 c++ java社区贡献任何力量 更本没有体验过什么叫做windows得昂贵,(因为他们一直在盗版),反而向面对世世代代的仇家一样,不惜以对方同样不礼貌的问候自己的母亲为代价,我不想这么说,但是我不得不这么说,as a crazy dog,只要嗅到ms的味道就就要扑上去疯狂的咬上几口。ms的垄断确实危害无穷,比如现在的浏览器行业,停滞不前好久了,即使冲出了firefox等,也只是配角。但是,您真的体验过这些么?ms真的让你那么痛恨了么?更都得,你只是为了与众不同,甚至只是为了潮流,您读过linux内核么?您为linux的某个发行版本掏腰包了么?即使只需要几十块钱….所以,恳请这些人,get out of here,here是哪里?是反ms阵营,因为你们不配,你们当然也不会去ms阵营,那么怎么样?恳求你,不要说自己是个程序员,别丢大家的脸了。程序员首先是个人,您不陪这个字…
        我们再来看看这个 【安全】紧急病毒警报:“快乐耳朵”病毒专偷网上银行
金山和瑞星的那次争吵,我感觉csdn还是比较公正的报道了,而且,csdn偏袒瑞星得到好处了?瑞星比金山给钱多?他们都贿赂csdn了?请用您的脚趾头想一想。我感觉这个报道很及时,因为我再dearbook的所有支付都是招行一卡通,虽然我不去那些不入流的网站,但是如果,一些小站也开始采用如此手段怎么办?可是,居然有人对这则新闻大开杀戒…我感觉还是没有脑子的表现,现在动辄有人上纲上线,说csdn怎怎样了,被xxxx收买了,可能是一时气话,可是居然真有人当真,开始对csdn的大部分新闻戴上有色眼镜去用放大镜看待那些冤家的或者不喜欢的技术的新闻 而对自己喜欢公司的正面报道反而视而不见了….岂不是病态?我还是评论中留下的观点:如果您对csdn有成见,又何必汤这个浑水?既然看不惯,您又何必来?您不是贱么?您真的达到了英雄中,人就是贱,贱就是人,人贱和一,贱人的境界!
        最后,我恳请某些自认为敢爱敢恨,又性格的,所谓的程序员,请长长脑子,程序员是一个从事复杂劳动的,需要高等智慧的职业。不要玷污了他。
2004年09月03日

很不错的文章 推荐

相恋相爱的你们感觉快乐吗,幸福吗?
  记住,不管如何,女人是用来疼的,不是用来心疼的,尽量少的让她伤心,特别是不要因为是你的原因。
  知道什么是所谓的“温柔体贴”吗?其实只要你在平日微不足道的生活里,像你对待工作那样细心的对待她就可以有很好的效果,对,就是要——细心。这是非常非常重要的。
  一起压马路的时候,如果你的手(一只或者两只)是空着的,尽量多的牵着她,女孩子都希望,也需要来自你那或许并不宽大的手的温度(冬天尤其是如此),如果觉得不舒服或是太热(夏天),那就试着轻握她的手腕或是她的手指(手指数目1-5不限),但是千万记得不要自己觉得不爽而将她的手甩开或挥开,不然你会看到她眼中越来越明显的暗涌(如果这时候你留心她的话)。记得一点,这些你要主动去做。
  如果你们住在一起,记得出门和回家的时候给她一个吻或是一个温暖的拥抱,加上上一个微笑。
  如果你确定她不能帮你分担的话,尽量不要将工作上的烦恼带入你与她的生活中,更不要将烦恼转移到她身上,你就是她的榜样,你快乐她一定比谁都开心;你垂头丧气,她会陪着你一起无精打采,不信就试一试,看看结果是不是如此。之后你就应该知道怎么做了吧?
  如果你们在一起的时间比较多,不要只顾自己上网,游戏而把她晾在一边,做一些两个人能一起做的事情,坐在同一张沙发或一张床上一起看看电影电视,晚上适当的出去逛逛,多跟她聊聊天,如果你懂得幽默,哪怕一点点,那已经足够了,有时候她很清楚你是在糊弄她,也知道你说的只是说说而已,但是还是喜欢听,不要怪她。如果说说能让她开心快乐你又没有什么损失,何乐不为呢?
  在她不开心需要你的肩膀的时候,给她靠吧,即使你的肩头不够宽厚。如果她哭了,可以的话不要陪着她哭,不要叹气,更不要说诸如“你总是哭哭啼啼的”之类,唯一要做的,就是安慰她,所有的话,都留到她平静了再说,记住,要安慰她,不要让她一个人哭累了停下。她依赖你,不要怪她,那是她对你特有的,在你以外的生活中,她一样独立,如果你要她独立而不依赖你,在女孩子看来,你这个男朋友是不太合格的。
  出门在外多照顾她,主动问她饿不饿,天热渴不渴,有时候她不说并不代表她不想,她在等你主动说出来,在男人看来是“要什么就直接说啊”,但是女孩子不同,因为她们是女孩子而不是男孩子,这一点你要明白。
  信任,包容,沟通,适当的迁就她的“无理取闹”,不要过于死板,更不要百分百的现实,如果这样,即使你们不想,但是你们也一定会觉得很苦很累。其实绝大多数女孩子都要求不高,只要你在平时的时候细心一点,她就会觉得很幸福了,她不要别人的疼,别人的宠,她只要你疼她你宠她,因为你是她的男朋友,而她是你的女朋友。
  还有…..应该还很多吧,以后慢慢实地考察再说。
  爱她就尽量想办法让她快乐,好男人不该让心爱的女人受一点点伤,兄弟们,拿出你们男人的本色,有女朋友的,好好珍惜好好爱,没有的就一起努力噢!!!!!

作为一个还没有初出茅庐的在读学生,因为大部分时间都在学习各种课程,所以,无论对于java还是.net,由于好奇心都去接触,也许因为我接触的都不深刻,所以无法像csdn一些高手能够一针见血的指出各自的致命的优点缺点…但是我确实无法理解很多人的心态。可以说,由于喜欢上网,所以开始的时候我曾经提到Bill也用无耻来形容,那个时候喜欢php and C++,当学c++郁闷的时候看到了java也是眼前一亮,可是后来接触到了ms的技术,感觉,虽然bill经常看走眼,但是,他的东西并非一大摊shit。渐渐的,我虽然没有什么Java or .net fans的立场,但是感觉两种技术都喜欢,却渐渐开始讨厌部分csdn上的人。我为自己的盗版行为感到羞愧,但是很多人用着盗版的时候却还是在骂娘,这样的做法不符合中国人的传统。ms的垄断确实有太大的坏处,但是,我想,如果各位学过马克思政治经济学就知道什么叫做垄断?垄断的目的是什么…是的,bill的钱已经够多,我想人到了那个程度的时候,钱已经仅仅是一个符号,代表自己的财富和社会地位,那么,他最的梦想便是构造一个帝国。此外,垄断现在往往发展成为集团式的,IBM ORACLE BEA MS SUN BORLAND等等…他们在一起垄断着整个it界。我个人认为,windows office都够贵…但是和国内的开发者开发出来的东西比起来,却不贵了。国内的市场已经混乱到了极致了。
        前阵子有朋友愤愤地跟我说,在网上看到了一个自动关机小软件,居然好几m,更可恨的是,美其名曰 共享软件 要了将近10多块钱的注册费…这个时候,csdn首页有了一个小文章,教人用at和shutdown来实现自动关机,天啊,那么多人在那里骂街,似乎自己是天底下最nx得人,程序员那么nx为什么还要写这种垃圾,而且还要钱?
        哦,对了,刚才说,windows不贵,这便是不贵了理由的一个小侧面反映。再比如,web应用程序,一个论坛程式,价格换算成美元和国外的钱差不多了…动辄还有上千块的。这东西到底先进在哪里?居然和国外那么多经典软件价格差不多,而相反,暴雪的魔兽争霸一套在中国卖了多少钱?
        其实,在中国讨论价格没有意义,4块钱搞定人和世界级的软件,甚至有宽带自己down一个不就完了么。可是,问题的关键在于,我为这种行为感到可耻,可是,更多的人大叫开源,却从来都是为了从中牟利,没想贡献,见到ms的东西卖得一文不值,但是从懂得什么叫做computer那一天起一直到自己羽翼丰满却没有离开过dos windows……成天大喊i’m javaer,其实没有为java社区贡献任何力量,java如此多优秀的框架有中国人的么?他们喊只是为了显示自己高明,显示自己清高,或者冤枉了他们,他们只是没有脑子,人家说什么他就说什么……

        国内的开发者的素质却实在不敢恭维。似乎也过于愤青了一些。因为一旦涉及到了.net vs java便有无穷的口水大战,而我想,更多人只是对自己的领域及其熟悉,比如我学.net那么对java可能仅仅研究过一小段时间而已,那么对自己的开发平台的优点烂熟于胸,而对对方却是一无所知,那么靠的就是网上其他资料,但是网上的评测资料很多时候是别有用心的….但是,我怎么感觉java让无数.net人员倾家荡产,而.net让无数java开发者妻离子散似的呢?否则怎么会每次见面都要眼红,进而用最恶毒的语言开始互相攻击和谩骂….net明知道java的好处却视而不见,java的明知道垄断的坏处,却不想让有.net这么个东西…其实,sun早就提出了“网络就是计算机”,而bill是后来才悟出了道理,但是,ms太强大的,无数公司围攻他,他还是在扩张…他进入pc外设 进入游戏业 进入音乐领域….这个很多人看来无耻,但是我确实感觉这实在平常不过的事情,如果你是如此规模的软件公司的原ceo县首席架构师,难道您不想进入各种拥有前景拥有利润的行业么??看看国内的网游情况,那才叫趋之若鹜…相反,国外的公司还是理性一些,有一些长远规划的。
        任何事物都要辩证的来看,对任何一个公司都不能奉为神明,而对任何公司也不能喻为垃圾。无论ibm ms sun都在不停的壮大,为什么?什么叫做剩余价值?我们仅仅是产生剩余价值的特殊劳动力,虽然现在的剥削不露骨了…只要资本主义存在一天,那么,我们仅仅是劳动力,只是从事工作有复杂性有简单性所以得到的报酬不同,只要中国社会主义,所谓的取之于民用之于民一天没有实现,在中国,我们依然被剥削着…

本是同根生,相煎何太急?

2004年08月20日

Working with Client-Side Script

Scott Mitchell
4GuysFromRolla.com

August 2004

Summary: While ASP.NET performs most of its processing on the server, some actions are better served by client-side processing. Scott Mitchell shows how your ASP.NET pages and controls can add client-side code. (27 printed pages)

Download the source code for this article.

Contents

Introduction
Creating a Base Class as the Foundation for Adding Client-Side Script
Adding Client-Side Script from the Code-Behind Class
Executing Client-Side Code in Response to User Action
Implementing Common Client-Side Functionality
Conclusion
Related Books

Introduction

When working with dynamic Web-based scripting technologies, like classic ASP or PHP, developers must have a keen understanding of the logical, temporal, and physical separation between the client and the server. For a user’s action to trigger the execution of server-side code, for example, a developer working with classic ASP must explicitly cause the user’s browser to make a request back to the Web server. Creating such interactions can easily consume much development time and lead to unreadable code.

Microsoft ASP.NET helped ease the burden of tying user events to execution of specific server-side code through the use of Web Forms, which blur the lines between client and server. Using ASP.NET and a minimum of effort, a developer can quickly create a Web page that has a variety of interactive user interface elements—buttons, drop-down lists, and so on—which, based on the end user’s actions, can cause selective server-side code to run. For example, with ASP.NET to add a drop-down list that performs some action whenever the selected drop-down list item is changed, all you need to do is add a DropDownList Web control, set its AutoPostBack property to True, and create a SelectedIndexChanged event handler for the drop-down list. Accomplishing this same functionality with classic ASP would require you to write oodles of intricate HTML, client-side JavaScript, and server-side script code; with ASP.NET, the necessary script code and server-side event model are provided for you.

While Web Forms in ASP.NET greatly simplify running server-side script when client-side actions are performed, such power, if misused, can lead to unacceptable performance. While Web Forms hide the complexities involved, each time server-side code needs to be executed, the end user’s browser must make a request back to the Web server by resubmitting the form. When submitting the form, all form fields—textboxes, drop-down lists, check boxes, and so on—must have their values sent back as well. Additionally, the page’s view state is sent back to the Web server. In total, each time the Web page is posted back, potentially several kilobytes of data will need to be sent back to the Web server. Frequent postbacks, then, can quickly lead to an unusable Web application, especially for those users still stuck on dial-up. The need for frequent postbacks can be reduced by pushing functionality to the client.

Note   ASP.NET Web Forms emit a hidden form field titled VIEWSTATE, which contains a base-64 encoded representation of the changed state of the Web controls in the Web Form. Depending on the Web controls present, the view state can range anywhere from a few dozen bytes, to tens of kilobytes. To learn more about view state check out my article Understanding ASP.NET View State.

With classic ASP, adding data-driven, custom client-side script was simple, albeit not very readable. To display a popup window in classic ASP that loads a URL based on some ID field, for instance, you would type in the appropriate client-side script, using the <%=id%> syntax to insert the value of the ID field. ASP.NET allows you to create such data-driven client-side script with some assorted methods in the Page class.

This article examines techniques for adding client-side script to your ASP.NET Web pages. Client-side script is, as its name implies, script code that runs in the visitor’s browser. We’ll see how to accomplish common client-side tasks, such as displaying alerts, confirm boxes, and popup windows. (One of the main uses of client-side script—form field validation—is a bit of a moot topic with ASP.NET, since the validator Web controls provide client-side form validation out of the box.) The focus of this article will be on the server-side classes, methods, and techniques for injecting client-side script; we will not be examining the actual client-side script in detail, as this information is covered in numerous other articles and sites around the Web.

Creating a Base Class as the Foundation for Adding Client-Side Script

One of the major differences between classic ASP and ASP.NET is the programming model of each technology. ASP pages are atomic, procedural scripts interpreted on each page visit. ASP.NET, however, is a fully object-oriented programming technology. All ASP.NET Web pages are classes with properties, methods, and events. All Web pages are derived, either directly or indirectly, from the Page class in the System.Web.UI namespace; the Page class contains the base functionality of an ASP.NET Web page.

One of the concepts of object-oriented programming is that of inheritance. Inheritance allows you to create a new class that extends the functionality of another class. (If class B inherits class A, it is said to extend class A; class A is said to be the base class.) When using the code-behind model for creating ASP.NET Web pages, you can quite clearly see that the code-behind class inherits the Page class:

Public Class WebForm1 Inherits System.Web.UI.Page ... End Class 

By having your code-behind class inherit the Page class, it automatically receives the functionality inherent in the Page class, such as the Request, Response, Session, and ViewState objects, as well as common events, like Init, Load, Render, as so on. As we’ll see in this article, if you have a need for some common functionality to be available for all ASP.NET Web pages, one approach is to create a class that derives from the Page class and has additional methods and properties to accomplish these desired enhancements. Then, to have an ASP.NET Web page utilize these enhancements, all we need to do is update the Inherits statement in the page’s code-behind class to use the class that extends the Page class.

In this article we’ll create a class, called ClientSidePage, that derives from the Page class and provides extra methods to help with performing common client-side tasks. By having a code-behind class inherit ClientSidePage, rather than Page, adding script code will be as simple as calling a method and passing in a few parameters. Specifically, this class will contain methods for:

  • Displaying a modal, client-side dialog box.
  • Setting the focus to a specific form field on page load.
  • Using a modal confirm dialog box to determine if a user wants to postback the form or not.
  • Displaying popup windows.

Before we delve into the ClientSidePage class, let’s first examine the pertinent methods in the Page class for injecting client-side script into a Web page. Once we’ve covered these Page methods, we’ll jump into extending their functionality with the ClientSidePage class, and see how to tie everything together and use the extended class in an ASP.NET Web page.

Adding Client-Side Script from the Code-Behind Class

All ASP.NET Web pages must be derived directly or indirectly from the Page class in the System.Web.UI namespace. The Page class contains the base set of methods, properties, and events required for a functioning Web page. Among the class’s many methods are a few methods designed for injecting client-side script into the rendered HTML. These methods are called from the code-behind class and can therefore be used to emit data-driven client-side script. The pertinent Page class methods for emitting client-side script follow.

The base class is derived from the System.Web.UI.Page class, so you can access the Page class’s public methods by calling them directly from your code-behind class.

Note   To access the Page class’s methods, you can either type in the method name directly, or utilize IntelliSense in Microsoft Visual Studio .NET by entering MyBase. (for Microsoft Visual Basic .NET), this. (for C#), or Page. (for either C# or Visual Basic .NET). If you are using Visual Basic .NET as your programming language of choice, be sure to configure Visual Studio .NET to not hide advanced members, or you won’t see these client-side script methods. (To show advanced members, go to Tools | Options | Text Editor | Basic and uncheck Hide advanced members.)

RegisterClientScriptBlock(key, script)

The RegisterClientScriptBlock method adds a block of client-side script after the Web Form’s rendered <form> element, before any Web controls contained within the Web Form. The key input parameter allows you to specify a unique key associated with this script block, whereas the script parameter includes the complete script code to emit. (This script parameter should include the actual <script> element, along with the client-side JavaScript or Microsoft VBScript.)

When emitting client-side script through the code-behind class of an ASP.NET Web page, typically the value of the key parameter isn’t of paramount importance. Simply choose a descriptive key value. The key parameter is more pertinent when injecting client-side script code through a custom, compiled server control. There may be instances where a compiled control requires that there be a set of client-side functions. Multiple instances of the server control on one page might be able to share these common client-side script functions, so these functions need only be emitted once for the entire page, and not once per control instance. For example, the validation controls utilize client-side code to enhance the user experience. This client-side code must be present if there are any validation controls on the page, but if there are multiple validation controls, all can use this single set of shared functions.

By giving a script block a key, a control developer building a control that utilizes a set of common client-side functions can check to see if the required set of common functions has already been added by another instance of the control on the page. If so, it need not re-add the common script. To check if a script block has been added with the same key, use the IsClientScriptBlockRegistered(key) method, which will return a Boolean value indicating whether or not a script block with the same key has been registered. Realize that you can add a script block without first checking if it’s registered. If you attempt to add a script block with a key that’s already registered, the added script block will be ignored and the original script block will remain assigned to that key.

Note   The IsClientScriptBlockRegistered method is particularly useful in two situations. First, it comes in handy when you’re adding similar, but unique script blocks, and you need to insure that each script block is given a unique key. The code we’ll examine later on in this article illustrates the utility of the “is registered” method. A second use is when building a control that needs some common script, especially if the script is not trivially generated. By using the IsClientScriptBlockRegistered method, you can ensure that the script common to all instances of the server control on the page is generated only once per page load, rather than once per control instance on the page.

The RegisterClientScriptBlock method is useful for adding client-side script that does not rely on any of the form fields present within the Web Form. A common use of this method is to display a client-side alert box. For example, imagine that you had a Web page with some TextBox Web controls and a Save Button. The TextBox controls might have particular values from a database. Imagine that this page allowed the user to modify these values and commit their changes by clicking the Save button. When clicking Save, the Web page would be posted back, and the Button’s Click event would fire. You could create a server-side event handler for this event that updates the database. To let the user know that their changes had been saved, you might want to display an alert box that says, “Your changes have been saved.” This could be accomplished by adding the following line of code to the Button’s Click event handler:

RegisterClientScriptBlock("showSaveMessage", _ "<script language=""JavaScript""> _ alert('Your changes have been saved.'); _ </script>") 

The above will add the specified script content within the page’s <form>, but before the content within the form. When the page is rendered in the user’s browser they will see a client-side alert box displayed upon page load, as shown in Figure 1.

<form method="post" ...> <script language="JavaScript"> alert('Your changes have been saved.'); </script> ... </form> 

Figure 1. Result of the client-side JavaScript

Note   One potentially undesirable side effect of the above example is that the alert box will be displayed right after the browser received the <form> tag. The browser will suspend rendering of the Web page until the user clicks the alert box’s OK button. This means that the user will see a white browser page until they click OK. If you want to have the page displayed completely before displaying the alert box, you can have the JavaScript inserted at the end of the <form> element using the RegisterStartupScript method, which we’ll discuss next.

RegisterStartupScript(key, script)

The RegisterStartupScript method is quite similar to the RegisterClientScriptBlock method. The main difference is the location where the client-side script is emitted. Recall that with the RegisterClientScriptBlock the script is emitted after the start of the <form> element, but before the form’s contents. RegisterStartupScript, on the other hand, adds the specified script at the end of the form, after all form fields. Use RegisterStartupScript to place client-side script that interacts with the rendered HTML elements. (Later we’ll look at an example of setting the focus to a form field upon page load; to accomplish this you’ll use the RegisterStartupScript method.)

Like RegisterClientScriptBlock, the script blocks added by RegisterStartupScript need a unique key value. Again, this key value is primarily used by custom control developers. Not surprisingly, there is an IsStartupScriptRegistered(key) method as well, which returns a Boolean value indicating if a script block with the specified key has already been registered or not.

Note   For more information on using RegisterStartupScript and RegisterClientScriptBlock in creating custom, compiled server controls, read an earlier article of mine: Injecting Client-Side Script from an ASP.NET Server Control.

RegisterArrayDeclaration(arrayName, arrayValue)

If you need to create a client-side JavaScript Array object with some set values, use this method to add a value to a specific array. For example, when using validation controls in an ASP.NET Web page, an Array object (Page_Validators) is built that contains references to the set of validation controls on the page. When the form is submitted, this array is enumerated to check if the various validation controls are valid or not.

To add the values 1, 2, and 3 to a client-side Array object named FavoriteNumbers, you’d use the following server-side code:

RegisterArrayDeclaration("FavoriteNumbers", "1") RegisterArrayDeclaration("FavoriteNumbers", "2") RegisterArrayDeclaration("FavoriteNumbers", "3") 

This code would emit the following client-side script:

<script language="javascript"> <!-- var FavoriteNumbers = new Array(1, 2, 3); // --> </script> 

Notice that each array value passed in must be a string; however, the client-side script rendered sets the values of the Array object as the contents of the string. That is, if you wanted to create an Array with the string values “Scott” and “Jisun”, you’d use:

RegisterArrayDeclaration("FavoriteFolks", "'Scott'") RegisterArrayDeclaration("FavoriteFolks ", "'Jisun'") 

Notice that the second input parameters are strings that contain 'Scott' and 'Jisun'—text delimited by a single apostrophe. This would render the following client-side script:

<script language="javascript"> <!-- var FavoriteFolks = new Array('Scott', 'Jisun'); // --> </script> 

RegisterHiddenField(hiddenFieldName, hiddenFieldValue)

In classic ASP there was often the need to pass around various bits of information from one page to another. A common way of accomplishing this was using hidden form fields. (A hidden form field is a form field that is not displayed, but whose value is sent on the form’s submission. The syntax for creating a hidden form field is <input type="hidden" name="name" value="value" />.) The need for passing information around by custom hidden form fields in ASP.NET is greatly reduced since the state of the controls in the page is automatically persisted. If, however, you find that you need to create a custom hidden form field, you can do so through the RegisterHiddenField method.

The RegisterHiddenField method accepts two input parameters: the name of the hidden field and the value. For example, to create a hidden form field with the name foo and the value bar, use the following code:

RegisterHiddenField("foo", "bar") 

This would add a hidden form field within the page’s <form> element, like so:

<form name="_ctl0" method="post" action="test.aspx" id="_ctl0"> <input type="hidden" name="foo" value="bar" /> ... </form> 

Understanding How Client-Side Elements Are Rendered

The Page class contains two internal methods responsible for rendering client-side script registered in the methods discussed above: OnFormRender and OnFormPostRender. (A method marked internal can only be called by other classes in the same assembly. Therefore, you cannot call the Page’s internal methods from the code-behind classes in your ASP.NET Web application.) Both of these methods are called in the HtmlForm class’s RenderChildren method. The HtmlForm class, in the System.Web.UI.HtmlControls namespace, represents a Web Form; that is, the server-side form in an ASP.NET Web page—<form runat="server">...</form>—is loaded as an instance of the HtmlForm class during the page’s instantiation stage.

Since the client-side script registered by the Page class’s assorted methods is rendered in the OnFormRender and OnFormPostRender methods, and since these methods are only called by the HtmlForm class, the client-side script you programmatically add by these methods is only rendered if the Web page contains a Web Form. That is, any script elements you programmatically add through any of the discussed methods above will only be emitted in the page’s final markup if the ASP.NET Web page contains a server-side form (a <form runat="server">...</form>).

A Web Form on an ASP.NET Web page is rendered by first adding the starting <form> element. Following that, the Web Form’s RenderChildren method is called, which contains three lines of code:

Page.OnFormRender(...) MyBase.RenderChildren(...) Page.OnFormPostRender(...) 

The call to the Page class’s OnFormRender method adds the following markup:

  • Any hidden form fields added by calls to RegisterHiddenField.
  • The base-64 encoded view state in a hidden form field named __VIEWSTATE.
  • Any script blocks added by calls to RegisterClientScriptBlock.

The second line of code in the Web Form’s RenderChildren method calls the base class’s RenderChildren method, which renders the contents within the Web Form. After rendering all of the form’s contents, a call is made to the Page class’s OnFormPostRender method, which adds the following client-side content:

  • Any Array objects added by the RegisterArrayDeclaration method.
  • Any script blocks added by calls to RegisterStartupScript.

Finally, after the Web Form’s RenderChildren method completes, the closing form tag (</form>) is rendered. Figure 2 illustrates this rendering process graphically.

Note   Figure 2 assumes you are somewhat familiar with the ASP.NET page life cycle. If you are interested in learning more about the page life cycle, consider reading Understanding ASP.NET View State, focusing on the section titled, “The ASP.NET Page Life Cycle.”

Click here for larger image.

Figure 2. Page rendering in ASP.NET

Examining the Rendering Order of Script Blocks

Upon first glance at the register methods of the Page class, it might seem that the order with which the registered elements are rendered in the Web page correspond to the order with which they were added in the code. That is, imagine that you had the following two lines of code in your ASP.NET Web page’s code-behind class:

RegisterClientScriptBlock("showSaveMessage", _ "<script language=""JavaScript"">var name='" & _ someDataDrivenValue & "'; </script>") RegisterClientScriptBlock("showSaveMessage", _ "<script language=""JavaScript"">alert('Hello, ' + name + '!'); </script>") 

You wouldn’t be too surprised when you found that the page rendered the following client-side script blocks (assuming the value of someDataDriveValue was Sam):

<script language="JavaScript">var name='Sam';</script> <script language="JavaScript">alert('Hello, ' + name + '!');</script> 

The user visiting this page would see an alert box saying “Hello, Sam!”

Based on this test, you might then assume that it was always the case that the order the script blocks were emitted in the HTML page was the order they were specified in the server-side code. However, this would be an incorrect assumption, and one that could cause your pages to break. For example, imagine that the script blocks added above were emitted in the HTML page in the reverse order. Then you’d have:

<script language="JavaScript">alert('Hello, ' + name + '!');</script> <script language="JavaScript">var name='Sam';</script> 

This would display an alert box reading “Hello, !”, since the variable name has not yet been assigned a value. Clearly, there are times when the order with which script blocks are emitted is very important.

The register methods of the Page class—RegisterClientScriptBlock, RegisterStartupScript, RegisterArrayDeclaration, and RegisterHiddenFields—all write the supplied script content to an internal HybridDictionary. A HybridDictionary is a data structure found in the System.Collections.Specialized namespace, and is designed for storing items in a dictionary where the number of items in the dictionary is not known. For a small collection of items, a ListDictionary is the most efficient data structure, but for larger dictionaries, a Hashtable is more efficient. A HybridDictionary splits the difference—it starts by storing items using a ListDictionary. Once the ListDictionary has its ninth item added, the HybridDictionary switches from using a ListDictionary to using a Hashtable.

While this approach is ideal for performance, it can wreck havoc if you are using several script blocks where the order of the script blocks is important. That’s because while a ListDictionary maintains the order with which the elements were added, a Hashtable does not. So, if you add eight or fewer items to any one of the particular register methods, the items will be emitted in the order with which they were added. However, if you add a ninth item, the order that the script is emitted will be seemingly random.

Note   The ListDictionary stores its elements using a linked list, while the Hashtable stores its elements in an array, where the contents are ordered by the hashed value of a sting key. A thorough discussion on linked lists and hashtables is far beyond the scope of this article. For more information, including an analysis of their performance, consider reading An Extensive Examination of Data Structures, specifically Part 2 and Part 4.

If you plan on having cases where there may be more than eight client-side elements added using a particular register method, and the order with which the elements appear matters, you might want to take a look at Peter Blum’s free RegisterScripts library. RegisterScripts provides greater control over the order with which the client-side elements are emitted, and also provides the option to not have to manually add the <script> tags, which you have to add when including client-side scripts with the RegisterClientScriptBlock or RegisterStartupScript methods.

Executing Client-Side Code in Response to User Action

The Page class’s register methods are ideal for injecting client-side code that runs when the page loads, but in many situations we want to run code in response to an end user’s action. For example, we might want to display a confirm dialog box when a user clicks a button, or call a particular client-side JavaScript function when a drop-down list’s selected item is changed.

HTML elements have a variety of client-side events that you can tap into and have client-side code execute when the event fires. The required markup simply goes in the HTML element’s tag as an attribute. For example, to display an alert box when a button is clicked you can do:

<input type="button" value="Click me to see an alert box!" onclick="alert('Here it is!');" /> 

To run client-side code when a client-side event transpires, you can add the appropriate attribute to an HTML element. For a Web control, you can programmatically add a client-side attribute using the Attributes collection. For example, imagine that you had a TextBox Web control that you wanted to be highlighted yellow whenever the rendered textbox gains focus. To accomplish this you’d want the TextBox Web control’s rendered HTML to look something like the following:

<input type="text" onfocus="this.style.backgroundColor='yellow';" onblur="this.style.backgroundColor='white';" /> 

To achieve this markup, we can programmatically set the TextBox Web control’s onfocus and onblur client-side attributes by the Attributes collection, like so:

TextBoxControl.Attributes("onfocus") = "this.style.backgroundColor='yellow';" TextBoxControl.Attributes("onblur") = "this.style.backgroundColor='white';" 

This technique of tying client-side code with client-side events is commonly used to provide a rich, interactive user experience. Later on in this article we’ll see how to employ this technique to display confirm dialog boxes based on a user’s actions.

Implementing Common Client-Side Functionality

Now that we’ve looked at the ASP.NET methods involved in dynamically adding client-side script to a Web page, let’s turn our attention to applying this knowledge. The remainder of this article focuses on common client-side tasks, such as displaying alert boxes, confirm boxes, popup windows, and so on. Specifically we’ll create a class that contains a set of methods that can be used in an ASP.NET project to quickly and easily provide such functionality.

The Visual Basic .NET code we will be examining throughout the remainder of this article is available in this article’s code download.

Displaying an Alert Box

A common client-side requirement is to display an alert box. An alert box is a client-side, modal dialog box typically used to provide some important bit of information to the end user. An example of an alert box can be seen in Figure 1. An alert box is displayed through the client-side JavaScript alert function, which accepts a single parameter—the message to display. Displaying an alert box is fairly simple and straightforward; in fact, an example was shown earlier in the article.

In order to make it as easy as possible for a page developer to display an alert box, let’s create a class called ClientSidePage that contains a method called DisplayAlert(message). This class will inherit the Page class. A page developer that wants to utilize these client-side helper methods, then, will need to have their code-behind class inherit this ClientSidePage class rather than the default Page class. The following code shows this ClientSidePage class with its first method, DisplayAlert.

Public Class ClientSidePage Inherits System.Web.UI.Page Public Sub DisplayAlert(ByVal message As String) RegisterClientScriptBlock(Guid.NewGuid().ToString(), _ "<script language=""JavaScript"">" & GetAlertScript(message) & "</script>") End Sub Public Function GetAlertScript(ByVal message As String) As String Return "alert('" & message.Replace("'", "\'") & "');" End Function End Class 

Notice that this class is derived from the System.Web.UI.Page class. The DisplayAlert method simply uses the RegisterClientScriptBlock method to display the supplied message in an alert box. Since this method may be called multiple times by a single page, each call uses a GUID (Globally Unique Identifier) for its key. The string being passed to the alert function is delimited by apostrophes, any apostrophes in message must be escaped (JavaScript escapes apostrophes as \').

To use this code in your ASP.NET Web application, you will need to add a new class to your ASP.NET application. In Visual Studio .NET, right click on the ASP.NET Web application project name in the Solution Explorer and choose to add a new class. Then, cut and paste the above code into the class. Next, in your ASP.NET Web pages where you want to utilize this code, you’ll need to modify the code-behind class so that it inherits from the ClientSidePage class rather than from Page. The following code shows a sample code-behind class derived from ClientSidePage and that uses the DisplayAlert method.

Public Class WebForm1 Inherits ClientSidePage Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load DisplayAlert("Hello, World!") End Sub ... End Class 

Note that the ClientSidePage class not only has the DisplayAlert method, which generates a full client-side <script> element, but also has a GetAlertScript method, which returns just the client-side script, sans the <script> tag. This second method can be used in cases where you want to display an alert based on some client-side event. For example, if you want to have an alert displayed anytime a particular text box received focus, you could add the following code to your server-side code-behind class:

TextBoxControlID.Attributes("onfocus") = GetAlertScript(message) 

Setting Focus to a Form Field on Page Load

Have you ever noticed that when visiting Google the focus is automatically set to the search text box? This one little “feature” makes searching Google all the more faster—upon visiting Google you don’t have to take the second or two to move your mouse and click on the text box. Rather, you can simply start typing away upon page load. Setting the focus to a form field, be it a text box, radio button, check box, or drop-down list, requires just a few lines of client-side JavaScript code. Let’s add a method to the ClientSidePage class that will automatically add focus to a specified Web control on page load. This method will need to emit client-side script that looks like:

<script language="JavaScript"> function CSP_focus(id) { var o = document.getElementById(id); if (o != null) o.focus(); } </script> ... Form fields ... <input type="..." id="id of element to focus" ... /> ... Form fields ... <script language="JavaScript"> CSP_focus(id of element to focus); </script> 

The client-side function CSP_focus accepts a string parameter, the ID of the form field to set to focus, and retrieves the HTML element from the DOM. The retrieved element’s focus() function is then called. At the bottom of the Web page, after all of the form fields have been specified, we need to call the CSP_focus method passing in the ID of the form field where we want the focus set.

The following method, GiveFocus(Control), uses the RegisterClientScriptBlock and RegisterStartupScript methods to generate the needed client-side script.

Public Sub GiveFocus(ByVal c As Control) RegisterClientScriptBlock("CSP-focus-function", _ "<script language=""JavaScript"">" & vbCrLf & _ "function CSP_focus(id) {" & _ " var o = document.getElementById(id); " & _ "if (o != null) o.focus(); " & _ "}" & vbCrLf & _ "</script>") RegisterStartupScript("CSP-focus", _ "<script language=""JavaScript"">CSP_focus('" & _ c.ClientID & "');</script>") End Sub 

To use the GiveFocus method from an ASP.NET Web page whose code-behind class inherits ClientSidePage, simply call GiveFocus in the Page_Load event handler and pass in the Web control that should have its focus set on page load. For example, to set the focus to the TextBox Web control TextBoxControl, use the following Page_Load event handler:

Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load GiveFocus(TextBoxControl) End Sub 

Opening a Popup Window

While popup windows have gotten a bad rap on the Internet as a nefarious tool for advertisers, popup windows are used in many Web applications to a good end. For example, you might want a page that displays a list of database items in a DataGrid, with a link to edit each particular item. Rather than using the DataGrid’s in-line editing capabilities, you might want to have a popup window opened when the user opts to edit a DataGrid, where the popup window contains a list of text boxes with the editable fields of the DataGrid. (One reason you might want to do this is because there may be a very large number of editable fields, but you only want to show the most pertinent fields in the DataGrid, thereby eliminating the possibility of using the DataGrid’s built-in editing features.)

To display a popup window, use the JavaScript function window.open(), which takes a number of optional input parameters, the three germane ones being:

  • The URL to load in the popup window.
  • A string name for the popup window.
  • The features for the popup window, such as its height and width, whether or not the window is resizable, and so on.

A thorough discussion of the window.open() function is beyond the scope of this article; to learn more refer to the technical documentation.

Like the method to display the alert box, the ClientSidePage class contains two methods for displaying a popup window—one that renders a self-contained <script> block that displays the window, and one that returns just the JavaScript script itself. In addition to the methods to open a popup window, there is also a set of methods to close the current window. (It may be the case that you want to programmatically close the popup window based on some client-side or server-side event.)

Public Sub DisplayPopup(ByVal url As String, ByVal options As String) RegisterStartupScript(Guid.NewGuid().ToString(), _ "<script language=""JavaScript"">" & _ GetPopupScript(url, options) & _ "</script>") End Sub Public Function GetPopupScript(ByVal url As String, _ ByVal options As String) As String Return "var w = window.open(""" & _ url & """, null, """ & options & """);" End Function Public Sub CloseWindow(Optional ByVal refreshParent As Boolean = False) RegisterClientScriptBlock("CSP-close-popup", _ "<script language=""JavaScript"">" & _ GetCloseWindowScript(refreshParent) & "</script>") End Sub Public Function GetCloseWindowScript(Optional _ ByVal refreshParent As Boolean = False) As String Dim script As String If refreshParent Then script &= "window.opener.location.reload();" End If Return "self.close();" End Function 

An example of this code in action can be seen in the code download for this article. There you’ll find a sample Web page that has a DataGrid listing the files in the same directory as the ASP.NET Web page. This DataGrid has two columns: a TemplateColumn that displays a hyperlink that, when clicked, opens a popup window showing the contents of the selected file; and the name of the file (see Figure 3).

Figure 3. DataGrid with popup window

The DataGrid’s markup utilizes the GetPopupScript method, as shown below:

<asp:DataGrid id="dgFiles" runat="server" ...> <Columns> <asp:TemplateColumn HeaderText="View"> <ItemTemplate> <a href='javascript:<%# GetPopupScript("ViewFile.aspx?FileName=" & DataBinder.Eval(Container.DataItem, "Name"), "scrollbars=yes,resizable=yes,width=500,height=400") %>'> View File</a> </ItemTemplate> </asp:TemplateColumn> <asp:BoundColumn DataField="Name" HeaderText="Filename"></asp:BoundColumn> </Columns> </asp:DataGrid> 

The ASP.NET Web page ViewFile.aspx opens the file whose name is specified in the querystring, and displays its contents (see Figure 4).

Figure 4. Displaying the contents of Web.config in a popup window

Note   Popup windows are best suited for intranet applications only, because a number of Internet users utilize some sort of popup blocking software, such as Google Toolbar. In fact, with the Microsoft Windows XP Service Pack 2, Microsoft Internet Explorer will be configured to block popups by default. However, popups will still work when a user visits a site in the Trusted Sites or Local Intranet zones. For more information on the popup blocking features for Internet Explorer in the Windows XP Service Pack 2, be sure to read Changes to Functionality in Microsoft Windows XP Service Pack 2.

Confirming Before Postback

Earlier in this article, we looked at how to display a client-side alert box, which is a modal dialog box with an OK button. JavaScript offers a more interactive flavor of the alert box called a confirm dialog box. The confirm dialog box is displayed using the confirm(message) function and has the effect of displaying a dialog box with the text specified by the message input parameter along with OK and Cancel buttons. The confirm(message) function returns true if the user clicks OK and false if they click Cancel.

Typically confirm dialog boxes are used to ensure that the user wants to continue before submitting a form. When an HTML element is clicked to submit a form (such as a submit button), if that HTML element fires a client-side event handler that returns false, the form submission is canceled. Commonly the confirm dialog box is used in a Web page as follows:

<form ...> <input type="submit" value="Click Me to Submit the Form" onclick="return confirm('Are you sure you want to submit this form?');" /> </form> 

When the user clicks the “Click Me to Submit the Form” button, they’ll see a confirm dialog box that asks them if they are sure they want to submit the form (see Figure 5). If the user clicks OK, confirm() will return true and the form will be submitted. If, however, they click Cancel, confirm() will return false and the form’s submission will be canceled.

Figure 5. Results of the Confirm JavaScript

Imagine you had a DataGrid with a column of buttons labeled “Delete.” Upon clicking this button, the form will postback and the selected record will be deleted. In this instance, you might want to double-check that the user really wanted to delete this record. Here would be a great place to use a client-side confirm dialog box. You could prompt the user with a dialog box stating something like: “This will permanently delete the record. Are you sure you want to continue?” If the user clicks OK, the form will postback and the record will be deleted; if they click Cancel, the form will not be posted back, and hence the record will not be deleted.

To add the client-side JavaScript necessary to display a confirm dialog box on button’s click, simply use the Attributes collection to add a client-side onclick event handler. Specifically, set the onclick event handler code to: return confirm(message);. In order to provide such functionality for a DataGrid’s ButtonColumn, you’ll need to programmatically reference the Button or LinkButton control in either the DataGrid’s ItemCreated or ItemDataBound event handlers and set the onclick attribute there. For more information, see http://aspnet.4guysfromrolla.com/articles/090402-1.aspx.

Confirmation with AutoPostBack DropDownLists

While confirm dialog boxes are typically used when a button is clicked, they can also be used when a drop-down list is changed. For example, you might have a Web page that automatically posts back when a particular DropDownList Web control is changed. (The DropDownList Web control has an AutoPostBack property that, if set to True, causes the form to postback whenever the DropDownList’s selected item is changed.)

Intuitively you might think adding a confirm dialog box for a DropDownList is identical to adding such a dialog box for a Button Web control. That is, simply set the DropDownList’s client-side onchange attribute to something like: return confirm(...);. using:

DropDownListID.Attributes("onchange") = "return confirm(...);" 

Unfortunately, this won’t work as desired because an AutoPostBack DropDownList’s onchange attribute will be set to a bit of JavaScript that causes a postback, namely a call to the client-side __doPostBack function. When setting the onchange attribute programmatically yourself, the end result is that the rendered client-side onchange event handler has both your code and the call to __doPostBack:

<select onchange="return confirm(...);__doPostBack(...);"> ... </select> 

Noting this, what we really want to happen is have the __doPostBack function called if confirm returns true, because then the page will be posted back. We can accomplish this by setting the onchange event by the Attributes collection to: if (confirm(...)), which will render the following markup, which is what we are after:

<select onchange="if (confirm(...)) __doPostBack(...);"> ... </select> 

At first glance this will seem to have the desired effect. If a user selects a different item from the drop-down list, a confirm box appears. If the user clicks OK, the form will postback; if the user clicks Cancel, the form’s postback is halted. The problem, though, is that the drop-down list retains the item the user selected to initiate the drop-down list’s onchange event. For example, imagine the drop-down list loads with item x being selected, and then the user chooses item y. This will trigger the drop-down list’s client-side onchange event, which will display the confirm dialog box. Now, imagine that the user hits Cancel—the drop-down list will still be selected on item y. What we want is to have the selection reverted back to item x.

To accomplish this we need to do two things:

  1. Write a JavaScript function that “remembers” the selected drop-down list item.
  2. In the drop-down list’s client-side onchange event, if the user clicks Cancel, you need to revert the drop-down list back to the “remembered” value.

Step 1 entails creating a global script variable for the drop-down list and a function that runs when the page loads that will record the drop-down list’s value. Step 2 requires changing the client-side onchange attribute for the drop-down list to look like:

if (!confirm(...)) resetDDLIndex(); else __doPostBack(); 

Where resetDDLIndex is a JavaScript function that reverts the drop-down list’s selected value back to the “remembered” value. The client-side script for this needs to look like the following:

<select id="ddlID" onchange="if (!confirm(...)) resetDDLIndex(); else __doPostBack(...);"> ... </select> <script language="JavaScript"> var savedDDLID = document.getElementById("ddlID").value; function resetDDLIndex() { document.getElementById("ddlID").value = savedDDLID; } </script> 

This necessary script can be easily generated by creating a helper method in the ClientSidePage class.

Public Sub ConfirmOnChange(ByVal ddl As DropDownList, ByVal message As String) 'Register the script block If Not IsStartupScriptRegistered("CSP-ddl-onchange") Then RegisterStartupScript("CSP-ddl-onchange", _ "<script language=""JavaScript"">" & _ "var CSP_savedDDLID = " & _ document.getElementById('" & _ ddl.ClientID & "').value;" & vbCrLf & _ "function resetDDLIndex() {" & vbCrLf & _ " document.getElementById('" & " & _ " ddl.ClientID & "').value = CSP_savedDDLID;" & vbCrLf & _ "}" & vbCrLf & _ "</script>") End If ddl.Attributes("onchange") = _ "if (!confirm('" & message.Replace("'", "\'") & _ "')) resetDDLIndex(); else " End Sub 

To use this, simply call this method for each AutoPostBack DropDownList on the Web page that you want to display a confirm dialog box for when its selected item changes.

Confirming When Exiting Without Saving

In most every data-driven Web application I’ve created there’s always been some page where users can edit particular bits of information from the database. A very simple example might be a page with a series of TextBox and DropDownList Web controls, with the database data populated within these controls. The user can make any suitable changes and click the Save button to persist their changes to the database.

When I create these pages, I usually end the page with two Button Web controls: a Save button and a Cancel button. The Save button saves any changes back to the database, while the Cancel button exits the page without persisting any changes. While two buttons may seem like a perfect design, sometimes users accidentally click the Cancel button when they meant to click the Save button, thereby losing any changes they made to the data. To prevent this from happening, you can use a confirm box on the Cancel button that only appears if any of the textboxes or drop-down lists on the Web page have been changed. That is, if the user makes any changes to the data and then clicks Cancel, a confirm box will prompt them to see if they are sure they want to exist without saving. (If the user just clicks Cancel without changing any data, no such confirm box is shown.)

This user experience can be accomplished by a bit of client-side JavaScript. Basically, it entails a JavaScript global variable, isDirty, that is initially false but is set to true whenever any of the form fields’ onchange events fire. There’s also a JavaScript function that displays a confirm dialog box if isDirty is true. The Cancel button’s onclick client-side event handler is wired up to return the result from this JavaScript function. The following HTML illustrates this concept:

<script language="JavaScript"> var isDirty= false; function checkForChange(msg) { if (isDirty) return confirm(msg); else return true; } </script> Name: <input type="text" onchange="isDirty = true;" /> <input type="submit" name="btnSave" value="Save" id="btnSave" /> <input type="submit" name="btnCancel" value="Cancel" id="btnCancel" onclick="return checkForChange('You have made changes to the data since last saving. If you continue, you will lose these changes.');" /> 

This script can be easily generated by moving its generation to the ClientSidePage class. Specifically, we can create the following three methods:

Protected Sub RegisterOnchangeScript() If Not IsClientScriptBlockRegistered("CSP-onchange-function") Then RegisterClientScriptBlock("CSP-onchange-function", _ "<script language=""JavaScript"">" & _ "var isDirty= false;" & vbCrLf & _ "function CSP_checkForChange(msg) {" & vbCrLf & _ " if (isDirty) return confirm(msg); " & _ "else return true;" & vbCrLf & _ "}" & vbCrLf & _ "</script>") End If End Sub Public Sub MonitorChanges(ByVal c As WebControl) RegisterOnchangeScript() If TypeOf c Is CheckBox Or TypeOf c Is CheckBoxList _ Or TypeOf c Is RadioButtonList Then c.Attributes("onclick") = "isDirty = true;" Else c.Attributes("onchange") = "isDirty = true;" End If End Sub Public Sub ConfirmOnExit(ByVal c As WebControl, ByVal message As String) RegisterOnchangeScript() c.Attributes("onclick") = _ "return CSP_checkForChange('" & message.Replace("'", "\'") & "');" End Sub 

To create a Web page that exhibits this behavior, we simply need to have its server-side code-behind class derive from ClientSidePage and in the Page_Load event handler have a call to MonitorChanges for each Web control that needs a client-side onchange event and a call to ConfirmOnExit for each Button, LinkButton, and ImageButton that, when clicked, should display a warning if the user has made changes and is exiting the page.

Note   Notice that the MonitorChanges method uses the onclick client-side event instead of onchange for the CheckBox, CheckBoxList, and RadioButtonList Web controls. This is because these controls wrap a <span> tag or <table> around the check box or series of check boxes or radio buttons. In my tests with Internet Explorer, I found that the onchange event, when applied to the <span> or <table>, was not picked up when a check box or radio button was clicked, but the onclick event was raised.

Figure 6 shows an example ASP.NET Web page with two TextBox Web controls, a DropDownList Web control, and a CheckBox Web control. As the Page_Load event handler below shows, all of these Web controls are being monitored for changes. The Cancel button, btnCancel, is configured so that if it’s clicked after changes have been made, a confirm dialog box will be displayed.

Figure 6. Dialog with confirmation

Public Class ConfirmOnExit Inherits ClientSidePage Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load 'Specify what controls to check for changes MonitorChanges(name) MonitorChanges(age) MonitorChanges(favColor) MonitorChanges(chkSilly) ConfirmOnExit(btnCancel, _ "You have made changes to the data since last saving." & _ " If you continue, you will lose these changes.") End Sub ... End Class 

Note   The client-side onchange event does not work in older versions of Netscape. Also, Internet Explorer 5.0 has had some reported problems with the onchange event (which were fixed in Internet Explorer 5.01, SP 1).

Furthermore, this approach won’t work as desired with DropDownList Web controls with AutoPostBack set to True, as the postback will reset the value of isDirty. There are a couple of workarounds for this problem, such as using a hidden form field that indicates whether or not the postedback form data is dirty to begin with or not. I leave implementing this as an exercise for the reader.

Creating a Client-Side MessageBox Control

While confirm dialog boxes are a great way to prevent accidental clicks and to potentially reduce the number of postbacks to the Web server, there are certain scenarios where you might want to display a confirm dialog box and be able to determine on the server-side whether or not they clicked OK or Cancel. (Recall that with the confirm dialog box, if the user clicks Cancel, the form is not posted back.) Furthermore, the alert and confirm boxes in JavaScript are rather limited in their appearance. Fortunately client-side VBScript offers a richer message box experience through its MsgBox function.

In a past project, I had a need for a client-side, modal message box that would cause a postback no matter what button was clicked. In response, I built a custom compiled ASP.NET server control that met these requirements. In addition, the client-side message box uses VBScript’s MsgBox function to provide a richer message box experience.

Note   VBScript only works as a client-side scripting language in Microsoft’s Internet Explorer browser. To account for this, my server control only uses VBScript if the visiting browser is Internet Explorer. Non-Internet Explorer browsers are sent JavaScript.

A thorough discussion of this custom server control could warrant an entire article in itself, so rather than focus on the inner workings of the control, let’s examine how to use the MessageBox control in an ASP.NET Web page. (The complete source for the control, as well as a sample ASP.NET Web page using the control, is available in this article’s download.)

To use the MessageBox control in an ASP.NET Web page, first add the MessageBox control to the Visual Studio .NET Toolbox. This can be accomplished by right-clicking on the Toolbox and choosing to Add/Remove Items from the Toolbox, and then browsing to the MessageBox assembly. To add the client-side message box to a Web page, simply drag it from the Toolbox onto the Designer. Figure 7 shows the MessageBox control in the Visual Studio .NET Designer.

Click here for larger image.

Figure 7. Displaying a modal messagebox

The MessageBox class has a number of properties that you can configure to tweak the appearance of the message box:

  • Buttons. Specifies what buttons are displayed. The options are defined in the ButtonOptions enumeration and can be: OkOnly, OkCancel, AbortRetryIgnore, YesNoCancel, YesNo, or RetryCancel.
  • DisplayWhenButtonClicked. The ID of the Button Web control that, when clicked, will display the client-side message box. Use this property if you want the message box displayed due to a specific button being clicked.
  • Icon. The icon displayed in the message box; the options are defined in the IconOptions enumeration. The legal values are: Critical, Question, Exclamation, and Information.
  • Prompt. The text displayed within the message box.
  • Title. The title of the message box.

Once you have added the MessageBox control to an ASP.NET Web page, the next challenge is having it displayed due to some client-side action. The DisplayWhenButtonClicked property allows you to specify the ID of a Button Web control on the page that, when clicked, will cause the message box to be displayed. Alternatively, you can have the message box displayed by calling the client-side function mb_show(id), where ID is the ID of the MessageBox control.

Regardless of what button configuration you choose to display in the message box, when any button is clicked, a postback ensues and the MessageBox control’s Click event fires. You can create an event handler for this event by simply double-clicking on the MessageBox in the Designer. The event handler’s second input parameter is of type MessageBoxClickedEventArgs, which contains a ButtonClicked property that returns information on what message-box button the user clicked.

The MessageBox control is useful in situations where you want to quickly present the user with a modal dialog box that, regardless of the user’s choice, results in a postback. To see the MessageBox control in action, check out the MsgBoxDemo.aspx page in the source code download.

Conclusion

This article began with a look at common uses of client-side script in a Web page, and then turned to examine the methods and techniques for injecting client-side script into an ASP.NET Web page. As we saw, the Page class contains a number of methods designed for programmatically inserting client-side script blocks from the server-side code-behind class. These methods are also commonly used from custom, compiled server controls, as discussed in an earlier article of mine: Injecting Client-Side Script from an ASP.NET Server Control.

In addition to adding script blocks, client-side functionality often must be tied to a client-side event raised by some HTML element. To programmatically specify a Web control’s client-side event handler through the server-side code-behind class, use the Attributes collection, which is available as a property to all Web controls.

The second half of this article applied the topics covered in the first half, showing how to implement common client-side functionality in an ASP.NET Web page. We saw how to extend the Page class so that from a code-behind class we could easily display an alert box, set the focus upon page load to a specific Web control, how to display a popup, and how to display a confirm dialog box. We also looked at creating a custom server control that used VBScript to provide a richer client-side message box user experience that caused a postback regardless of the button clicked.

Happy Programming!

Special Thanks To…

Before submitting my article to my MSDN editor, I have a handful of volunteers help proofread the article and provide feedback on the article’s content, grammar, and direction. Primary contributors to the review process for this article include Maxim Karpov, Carlos Santos, Milan Negovan, and Carl Lambrecht. If you are interested in joining the ever-growing list of reviewers, drop me a line at mitchell@4guysfromrolla.com.

Related Books

 


About the author

Scott Mitchell, author of five books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies for the past five years. Scott works as an independent consultant, trainer, and writer. He can be reached at mitchell@4guysfromrolla.com or through his blog, which can be found at http://ScottOnWriting.NET.

 foxmail原创

IIs创建虚拟目录
http://www.eggheadcafe.com/articles/20040112.asp

把两个表绑定到一个datagrid里
http://datawebcontrols.com/faqs/CustomizingAppearance/CombiningTwoFieldsIntoOneColumn.shtml

弹出日历:
http://authors.aspalliance.com/Colt/Articles/Article4.aspx

鼠标移动,变色的datagrid:
http://authors.aspalliance.com/Colt/Articles/Article3.aspx

Hosting .NET Windows Forms Controls in IE
http://www.15seconds.com/issue/030610.htm

Retrieving Images from SqlServer and displaying in a DataGrid – ASP .NET
http://aspalliance.com/articleViewer.aspx?aId=141&pId=

Adding a confirmation dialog to a DataGrid
http://authors.aspalliance.com/aldotnet/examples/cd.aspx

outlookBar的菜单:
http://www.abderaware.com
http://www.codeproject.com/cs/miscctrl/Group_Panel.asp

asp.net菜单:
http://www.aspnetmenu.com

winform控件:
http://www.codeproject.com/cs/miscctrl/
http://www.windowsforms.net/Default.aspx?tabindex=10&tabid=50

日期控件:
http://asp.net/ControlGallery/default.aspx?Category=43&tabindex=2

得到Sql服务器列表:
http://www.codeproject.com/cs/database/LocatingSql.asp

Data Tier Generator
http://sourceforge.net/projects/csharpdatatier/

2004年08月15日

http://daringfireball.net/projects/    markdown

十分榜 比现在国内的什么UBB之类的好多了 快的很
http://daringfireball.net/projects/markdown/dingus  可以来这里体验一下

  • Web design

  • Web standards – more than just ‘table-free sites’

    The term web standards can mean different things to different people. For some, it is ‘table-free sites‘, for others it is ‘using valid code‘. However, web standards are much broader than that. A site built to web standards should adhere to standards (HTML, XHTML, XML, CSS, XSLT, DOM, MathML, SVG etc) and pursue best practices (valid code, accessible code, semantically correct code, user-friendly URLs etc).

    In other words, a site built to web standards should ideally be lean, clean, CSS-based, accessible, usable and search engine friendly.

    About the checklist

    This is not an uber-checklist. There are probably many items that could be added. More importantly, it should not be seen as a list of items that must be addressed on every site that you develop. It is simply a guide that can be used:

    • to show the breadth of web standards
    • as a handy tool for developers during the production phase of websites
    • as an aid for developers who are interested in moving towards web standards

    The checklist

    1. Quality of code

    1. Does the site use a correct Doctype?
      http://www.w3.org/QA/2002/04/valid-dtd-list.html
    2. Does the site use a Character set?
      http://www.w3.org/International/O-charset.html
    3. Does the site use Valid (X)HTML?
      http://validator.w3.org/
    4. Does the site use Valid CSS?
      http://jigsaw.w3.org/css-validator/
    5. Does the site use any CSS hacks?
      http://css-discuss.incutio.com/?page=CssHack
    6. Does the site use unnecessary classes or ids?
    7. Is the code well structured?
      http://www.w3.org/2003/12/semantic-extractor.html
    8. Does the site have any broken links?
      http://validator.w3.org/checklink
    9. How does the site perform in terms of speed/page size?
      http://www.websiteoptimization.com/services/analyze/
    10. Does the site have JavaScript errors?

    2. Degree of separation between content and presentation

    1. Does the site use CSS for all presentation aspects (fonts, colour, padding, borders etc)?
    2. Are all decorative images in the CSS, or do they appear in the (X)HTML?

    3. Accessibility for users

    1. Are “alt” attributes used for all descriptive images?
    2. Does the site use relative units rather than absolute units for text size?
    3. Do any aspects of the layout break if font size is increased?
    4. Does the site use visible skip menus?
    5. Does the site use accessible forms?
    6. Does the site use accessible tables?
    7. Is there sufficient colour brightness/contrasts?
    8. Is colour alone used for critical information?
    9. Is there delayed responsiveness for dropdown menus (for users with reduced motor skills)?
    10. Are all links descriptive (for blind users)?

    4. Accessibility for devices

    1. Does the site work acceptably across modern and older browsers?
    2. Is the content accessible with CSS switched off or not supported?
    3. Is the content accessible with images switched off or not supported?
    4. Does the site work in text browsers such as Lynx?
    5. Does the site work well when printed?
    6. Does the site work well in Hand Held devices?
    7. Does the site include detailed metadata?
    8. Does the site work well in a range of browser window sizes?

    5. Basic Usability

    1. Is there a clear visual hierarchy?
    2. Are heading levels easy to distinguish?
    3. Is the site’s navigation easy to understand?
    4. Is the site’s navigation consistent?
    5. Does the site use consistent and appropriate language?
    6. Does the site have a sitemap page and contact page? Are they  easy to find?
    7. For large sites, is there a search tool?
    8. Is there a link to the home page on every page in the site?
    9. Are links underlined?
    10. Are visited links clearly defined with a unique colour?

    6. Site management

    1. Does the site have a meaningful and helpful 404 error page that works from any depth in the site?
    2. Does the site use friendly URLs?
    3. Does the site’s URL work without “www”?
    4. Does the site have a favicon?

    This list was first outlined in a rough form on the Web Standards Mail list in May 2004. It was presented to the Sydney Web Standards Group on 5 August 2004. It is also available as a downloadable pdf checklist for developers.

    The presentation is also available in:
    Bulgarian, thanks to Boby Dimitrov
    Chinese, thanks to Jjgod Jiang
    Spanish, thanks to Osvaldo Rainero

    Thanks as always to Rose for proof reading and Lea de Groot for her developer checklist suggestions.

    Russ Weakley
    13-August-04