这篇文章简要的介绍了通过使用Atlas UpdatePanel控件进行局部页面渲染的概念。如果你理解了什么是Atlas,你将从这篇文章中受益匪浅。

这篇文章包含了一个很简单的代码示例,教您如何使用UpdatePanel控件来局部渲染页面。使用UpdatePanel的主要优点有:
1、减少了数据页面更新导致的页面刷新次数
2、减少了页面更新传送的数据量(因为在数据回送postback的时候,并不是整个页面都需要完全重新渲染)
3、通过加快UI响应速度提高了用户使用体验。

下面这个例子展示了如何为应用程序增加UpdatePanel控件。
http://atlas.asp.net/docs/Walkthroughs/Samples/datepicker.aspx

从这个示例中我们可以看到,点击页面中心的大的日历整个页面都会刷新,而点击左上方的小日历选择某个日子,页面并不会刷新,而且反应非常迅速。这就是因为这个日历被UpdatePanel包裹了,所以具有了局部页面无刷新渲染的特性。

因此,为一个ASP.NET控件增加AJAX的无刷新效果非常的简单,只要把其放在UpdatePanel内就可以了。

示例源代码如下:

<%@ page language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
protected void ChosenDate_TextChanged(object sender, EventArgs e)
{
DateTime dt = new DateTime();
DateTime.TryParse(ChosenDate.Text, out dt);

CalendarPicker.SelectedDate = dt;
CalendarPicker.VisibleDate = dt;
}

protected void Close_Click(object sender, EventArgs e)
{
SetDateSelectionAndVisible();
}

protected void ShowDatePickerPopOut_Click(object sender, ImageClickEventArgs e)
{
DatePickerPopOut.Visible = !DatePickerPopOut.Visible;

// corrdinates are relative to the control, so we need to get the control's
// position too
int h = (int)ShowDatePickerPopOut.Height.Value;
SetDatePickerPopOutStyle(e.X + h, e.Y);
}

protected void CalendarPicker_SelectionChanged(object sender, EventArgs e)
{
SetDateSelectionAndVisible();
}

private void SetDateSelectionAndVisible()
{
ChosenDate.Text = CalendarPicker.SelectedDate.ToShortDateString();
DatePickerPopOut.Visible = false;
}

private void SetDatePickerPopOutStyle(int x, int y)
{
DatePickerPopOut.CssClass = "PopUpShow";
DatePickerPopOut.Attributes.Add("style", "top:" + x + "px;left:" + y + "px;");
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Untitled Page</title>
<style type="text/css">

.PopUpShow
{
background-color:lightblue;
position:absolute;
visibility:show;
width:150px;
height:150px;
z-index:1;
border: solid 2px black;
}

</style>
</head>
<body>
<form id="form1" runat="server">
<atlas:scriptmanager id="ScriptManager" runat="server"
enablepartialrendering="true" />
<h4>With an UpdatePanel</h4>
<!– This section of the page is wrapped by an UpdatePanel. –>
<atlas:updatepanel id="up" runat="server" mode="Conditional"
rendermode="Inline">
<triggers>
<atlas:controleventtrigger controlid="CalendarPicker"
eventname="SelectionChanged" />
</triggers>
<contenttemplate>
<asp:textbox runat="server" id="ChosenDate"
ontextchanged="ChosenDate_TextChanged" autopostback="true" />
</contenttemplate>
</atlas:updatepanel>
<span style="position: relative;">
<asp:imagebutton runat="server" id="ShowDatePickerPopOut"
onclick="ShowDatePickerPopOut_Click" imageurl="~/images/calendar.gif"
height="20px" width="20px" />
<!– This section is also wrapped by an UpdatePanel. –>
<atlas:updatepanel runat="server" id="up1" mode="Conditional"
rendermode="inline">
<triggers>
<atlas:controleventtrigger controlid="ShowDatePickerPopOut"
eventname="Click" />
</triggers>
<contenttemplate>
<asp:panel runat="server" id="DatePickerPopOut" visible="false">
<asp:calendar id="CalendarPicker" runat="server" backcolor="White"
bordercolor="White" borderwidth="1px" font-names="Verdana"
font-size="6pt" forecolor="Black" height="139px"
nextprevformat="FullMonth" width="100px"
onselectionchanged="CalendarPicker_SelectionChanged">
<selecteddaystyle backcolor="#333399" forecolor="White" />
<todaydaystyle backcolor="#CCCCCC" />
<othermonthdaystyle forecolor="#999999" />
<nextprevstyle font-bold="True" font-size="6pt"
forecolor="#333333" verticalalign="Bottom" />
<dayheaderstyle font-bold="True" font-size="6pt" />
<titlestyle backcolor="White" bordercolor="Black" borderwidth="4px"
font-bold="True" font-size="8pt" forecolor="#333399" />
</asp:calendar>
<br />
<asp:linkbutton id="CloseDatePickerPopOut" runat="server"
font-names="Tahoma" font-size="small" onclick="Close_Click"
tooltip="Close Pop out">
Close
</asp:linkbutton>
</asp:panel>
</contenttemplate>
</atlas:updatepanel>
</span>
<hr />
<br />
<!– The remainder of the page does not have an UpdatePanel, so it cannot
participate in the benefits of partial page rendering on postbacks. –>
<div style="text-align: center;">
<h4>Without an UpdatePanel</h4>
<asp:calendar id="Calendar1" runat="server"></asp:calendar>
</div>
<p>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed
diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam
erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et
ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem
ipsum dolor sit amet.
</p>
<p>
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie
consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et
accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit
augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt
ut laoreet dolore magna aliquam erat volutpat.
</p>
<p>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed
diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam
erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et
ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem
ipsum dolor sit amet.
</p>
<p>
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie
consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et
accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit
augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt
ut laoreet dolore magna aliquam erat volutpat.
</p>
</form>
</body>
</html>

转自 http://blog.csdn.net/psyl/archive/2006/03/17/627496.aspx

  我要从徐家汇赶去机场,于是匆匆结束了一个会议,在美罗大厦前搜索出租车。一辆大众发现了我,非常专业的、径直的停在我的面前。这一停,于是有了后面的这个让我深感震撼的故事,象上了一堂生动的MBA案例课。为了忠实于这名出租车司机的原意,我凭记忆尽量重复他原来的话。
  “去哪里……好的,机场。我在徐家汇就喜欢做美罗大厦的生意。这里我只做两个地方。美罗大厦,均瑶大厦。你知道吗?接到你之前,我在美罗大厦门口兜了两圈,终于被我看到你了!从写字楼里出来的,肯定去的不近~~~”
  “哦?你很有方法嘛!”我附和了一下。
  “做出租车司机,也要用科学的方法。”他说。我一愣,顿时很有些兴趣“什么科学的方法?”
  “要懂得统计。我做过精确的计算。我说给你听啊。我每天开17个小时的车,每小时成本34.5元……”
  “怎么算出来的?”我追问。
  “你算啊,我每天要交380元,油费大概210元左右。一天17小时,平均每小时固定成本22元,交给公司,平均每小时12.5元油费。这是不是就是34.5元?”,我有些惊讶。我打了10年的车,第一次听到有出租车司机这么计算成本。以前的司机都和我说,每公里成本0.3元,另外每天交多少钱之类的。
  “成本是不能按公里算的,只能按时间算。你看,计价器有一个“检查”功能。你可以看到一天的详细记录。我做过数据分析,每次载客之间的空驶时间平均为7分钟。如果上来一个起步价,10元,大概要开10分钟。也就是每一个10元的客人要花17分钟的成本,就是9.8元。不赚钱啊!如果说做浦东、杭州、青浦的客人是吃饭,做10元的客人连吃菜都算不上,只能算是撒了些味精。”
  强!这位师傅听上去真不象出租车司机,到象是一位成本核算师。“那你怎么办呢?”我更感兴趣了,继续问。看来去机场的路上还能学到新东西。
  “千万不能被客户拉了满街跑。而是通过选择停车的地点,时间,和客户,主动地决定你要去的地方。”我非常惊讶,这听上去很有意思。“有人说做出租车司机是靠运气吃饭的职业。我以为不是。你要站在客户的位置上,从客户的角度去思考。”这句话听上去很专业,有点象很多商业管理培训老师说的“put yourself into others' shoes.”
  “给你举个例子,医院门口,一个拿着药的,一个拿着脸盆的,你带哪一个。”我想了想,说不知道。
  “你要带那个拿脸盆的。一般人病小痛的到医院看一看,拿点药,不一定会去很远的医院。拿着脸盆打车的,那是出院的。住院哪有不死人的?今天二楼的谁死了,明天三楼又死了一个。从医院出来的人通常会有一种重获新生的感觉,重新认识生命的意义,健康才最重要。那天这个说:走,去青浦。眼睛都不眨一下。你说他会打车到人民广场,再去做青浦线吗?绝对不会!”
  我不由得开始佩服。
  “再给你举个例子。那天人民广场,三个人在前面招手。一个年轻女子,拿着小包,刚买完东西。还有一对青年男女,一看就是逛街的。第三个是个里面穿绒衬衫的,外面羽绒服的男子,拿着笔记本包。我看一个人只要3秒钟。我毫不犹豫地停在这个男子面前。这个男的上车后说:延安高架、南北高架~~~还没说后面就忍不住问,为什么你毫不犹豫地开到我面前?前面还有两个人,他们要是想上车,我也不好意思和他们抢。我回答说,中午的时候,还有十几分钟就1点了。那个女孩子是中午溜出来买东西的,估计公司很近;那对男女是游客,没拿什么东西,不会去很远;你是出去办事的,拿着笔记本包,一看就是公务。而且这个时候出去,估计应该不会近。那个男的就说,你说对了,去宝山。”
  “那些在超市门口,地铁口打车,穿着睡衣的人可能去很远吗?可能去机场吗?机场也不会让她进啊。”
  有道理!我越听越有意思。
  “很多司机都抱怨,生意不好做啊,油价又涨了啊,都从别人身上找原因。我说,你永远从别人身上找原因,你永远不能提高。从自己身上找找看,问题出在哪里。”这话听起来好熟,好像是“如果你不能改变世界,就改变你自己”,或者Steven Corvey的“影响圈和关注圈”的翻版。“有一次,在南丹路一个人拦车,去田林。后来又有一次,一个人在南丹路拦车,还是去田林。我就问了,怎么你们从南丹路出来的人,很多都是去田林呢?人家说,在南丹路有一个公共汽车总站,我们都是坐公共汽车从浦东到这里,然后搭车去田林的。我恍然大悟。比如你看我们开过的这条路,没有写字楼,没有酒店,什么都没有,只有公共汽车站,站在这里拦车的多半都是刚下公共汽车的,再选择一条最短路经打车。在这里拦车的客户通常不会高于15元。”
  “所以我说,态度决定一切!”我听十几个总裁讲过这句话,第一次听出租车司机这么说。
  “要用科学的方法,统计学来做生意。天天等在地铁站口排队,怎么能赚到钱?每个月就赚500块钱怎么养活老婆孩子?这就是在谋杀啊!慢性谋杀你的全家。要用知识武装自己。学习知识可以把一个人变成聪明的人,一个聪明的人学习知识可以变成很聪明的人。一个很聪明的人学习知识,可以变成天才。”
  “有一次一个人打车去火车站,问怎么走。他说这么这么走。我说慢,上高架,再这么这么走。他说,这就绕远了。我说,没关系,你经常走你有经验,你那么走50块,你按我的走法,等里程表50块了,我就翻表。你只给50快就好了,多的算我的。按你说的那么走要50分钟,我带你这么走只要25分钟。最后,按我的路走,多走了4公里,快了25分钟,我只收了50块。乘客很高兴,省了10元钱左右。这4公里对我来说就是1块多钱的油钱。我相当于用1元多钱买了25分钟。我刚才说了,我一小时的成本34.5块,我多合算啊!”
  “在大众公司,一般一个司机3、4千,拿回家。做的好的大概5千左右。顶级的司机大概每月能有7000。全大众2万个司机,大概只有2~3个司机,万里挑一,每月能拿到8000以上。我就是这2~3个人中间的一个。而且很稳定,基本不会大的波动。”
  太强了!到此为止,我越来越佩服这个出租车司机。
  “我常常说我是一个快乐的车夫。有人说,你是因为赚的钱多,所以当然快乐。我对他们说,你们正好错了。是因为我有快乐、积极的心态,所以赚的钱多。”
  说的多好啊!
  “要懂得体味工作带给你的美。堵在人民广场的时候,很多司机抱怨,又堵车了!真是倒霉。千万不要这样,用心体会一下这个城市的美,外面有很多漂亮的女孩子经过,非常现代的高楼大厦,虽然买不起,但是却可以用欣赏的眼光去享受。开车去机场,看着两边的绿色,冬天是白色的,多美啊。再看看里程表,100多了,就更美了!每一样工作都有她美丽的地方,我们要懂得从工作中体会这种美丽。”
  “我10年前是强生公司的总教练。8年前在公司作过三个不同部门的部门经理。后来我不干了,一个月就3、
5千块,没意思。就主动来做司机。我愿意做一个快乐的车夫。哈哈哈哈。”
  到了机场,我给他留了一张名片,说:“你有没有兴趣这个星期五,到我办公室,给微软的员工讲一讲你怎么开出租车的?你就当打着表,60公里一小时,你讲多久,我就付你多少钱。给我电话。”
  我迫不及待的在飞机上记录下他这堂生动的MBA课。
  ============================
  [注一]关于真实性。事情绝对是真实的,并且我尽最大努力忠实于这名司机的原意,包括数字、选词、语气、构句等。除了我记忆力所限不能100%精确外,基本重现了当时的场景。我没有“润色”,因为我以为他的感染力比我要大。
  [注二]关于星期五。我发出了诚挚的邀请,希望他能来公司做一场演讲。但这要尊重司机本人的意愿,如果他并不愿意、或者不感觉合适而未能成行,只能表示遗憾了。希望文章能够弥补希望参加的人的一些遗憾,也不枉我写了这么长。


最近研究了一下微软的Atlas(MS的AJAX解决方案),打算翻译一些资料,即学技术又练英语 [smile] 。今天先翻译了一篇“Atlas概述”,如果有不对的地方欢迎指正。后续打算翻译几篇实例讲解的文章。

标题:ASP.NET “Atlas” 概述
翻译:吴飞(Felix)
原文:http://atlas.asp.net/docs/Overview/Overview.aspx

介绍

很多网页开发人员一直以来都在努力提高HTML的UI使用体验,包括JavaScript的复杂性以及跨浏览器的兼容性。在很多情况下,开发人员不得不为了兼容不同浏览器通过创建基于服务器端的动态网页而牺牲丰富的用户体验。

在过去的几年里,浏览器的很多新特性促使网页开发人员重新探索是否有可能创建基于客户端应用程序。目前,所有主流浏览器都支持“可编程文档对象模型”(DOM),最新的几个版本中还增加了服务器端和客户端直接通信的能力,而不用再使用“回送”(Postback)。因此,新一代的网页程序应运而生,比如Microsoft Virtual Earth和Microsoft Windows Live,这些网站都提供了像拖拽(drag-and-drop)和实时处理数据的UI特性。

然而,开发这样的网页程序并不简单。你不得不了解浏览器的DOM并用JavaScript编写代码,而且也因不同的浏览器而不同。此外,JavaScript并没有面向对象(object-oriented)和类型安全(type-safe)等.NET所具有的特性。简而言之,创建面向客户端的网页程序需要精通一门新的编程语言和一个新的开发平台。

在这样的情况下,ASP.NET ‘Atlas’横空出世。Atlas是一种整合了客户端脚本库和ASP.NET 2.0服务器端开发平台的新的ASP.NET网页开发技术。这种网页由Atlas提供客户端支持,由ASP.NET提供服务器端支持。由于Atlas是ASP.NET的扩展,因此他完全整合了服务器端的服务。使用了Atlas,你就可以只把网页中的重要部分提供给客户端,而不用处理整个页面,并且可以在后台与服务器进行通讯。由此可见,你可以创建响应快、表现力丰富的UI和服务器通讯。

Atlas与AJAX

在网页开发业界,众所周知AJAX(Asynchronous JavaScript and XML)技术能够创建客户端服务器通讯和丰富的UI。AJAX是一种创建响应快、互动的网页的手段。Atlas可以让你创建AJAX样式的应用程序,而且超越了AJAX,能够为创建应用程序提供一个完整的开发平台。Atlas创建的应用程序可以针对应用需求而平衡客户端和服务器端的开发,并且为客户端和服务器端提供相同级别的编程能力。

Atlas提供了什么?
Atlas的主要目标就是整合客户端脚本和服务器端ASP.NET以提供一个完整的开发平台。

客户端特性
为了客户端开发,Atlas降低了基于JavaScript开发的复杂性,并提供了以下特性:
1、一致的、面向对象的JavaScript API组。可以使用.NET中很熟悉的OOP特性编码客户端程序。
2、浏览器自适用。可以不用再为不同的浏览器编写不同的代码。
3、客户端脚本API和组件支持丰富的UI特性,比如拖拽(drag-and-drop)。几乎使用很少的代码就可以为你的HTML控件加入这些特性。
4、类似ASP.NET服务器控件的客户端声明模型。

服务器端特性
Atlas也整合了客户端脚本与ASP.NET服务端,因此可以控制应用程序任务,无论在哪里都是有意义的。ASP.NET为Atlas应用程序提供以下特性:
1、Web Service可以与Atlas应用程序整合
2、ASP.NET网页服务器控件会自动加入Atlas应用程序所需要的客户端脚本,因此不用再为这些控件编写JavaScript代码。
3、为客户端开发整合了Visual Studio 开发工具,提供了debug、statement completion和其他高效开发的特性。


北京->贵阳->灵堂->公墓->北京…

刚下飞机,疲惫的回到了宿舍。就在这之前的48小时,我送走了我最亲爱的爷爷。您的后事举办的很顺利,也非常体面,您安息吧。

第一次送走自己的亲人,让我感到了生命的短暂和渺小。从一个有机的细胞生命到最后无机的灰飞烟灭,从茫然的降临人世到坦然的离开人间,其实我们别无选择。能够选择的只有离开时的心情,只愿我们走完生命的最后一刻可以无怨无悔,无论对自己还是对别人。

虽然我没有自己的宗教信仰,但我宁愿相信生命轮回、阴阳转世,因为人生最后的留给自己和带给亲人的痛苦是无以寄托的…

3月18日,我会每年为您上一柱香。

新注册了个域名www.thinkpage.cn,打算做点东西

东软的C#编程规范,与大家分享。
点击下载

感觉挺有趣的,就转过来给大家看了。

紧耦合
  从前,在南方一块奇异的土地上,有个工人名叫彼得,他非常勤奋,对他的老板总是百依百顺。但是他的老板是个吝啬的人,从不信任别人,坚决要求随时知道彼得的工作进度,以防止他偷懒。但是彼得又不想让老板呆在他的办公室里站在背后盯着他,于是就对老板做出承诺:无论何时,只要我的工作取得了一点进展我都会及时让你知道。彼得通过周期性地使用“带类型的引用”(原文为:“typed reference” 也就是delegate??)“回调”他的老板来实现他的承诺,如下:

class Worker {
public void Advise(Boss boss) { _boss = boss; }
public void DoWork() {
Console.WriteLine(“工作: 工作开始”);
if( _boss != null ) _boss.WorkStarted();
Console.WriteLine(“工作: 工作进行中”);
if( _boss != null ) _boss.WorkProgressing();
Console.WriteLine("“工作: 工作完成”");
if( _boss != null ) {
int grade = _boss.WorkCompleted();
Console.WriteLine(“工人的工作得分=” + grade);
}
}
private Boss _boss;
}
class Boss {
public void WorkStarted() { /* 老板不关心。 */ }
public void WorkProgressing() { /*老板不关心。 */ }
public int WorkCompleted() {
Console.WriteLine(“时间差不多!”);
return 2; /* 总分为10 */
}
}
class Universe {
static void Main() {
Worker peter = new Worker();
Boss boss = new Boss();
peter.Advise(boss);
peter.DoWork();
Console.WriteLine(“Main: 工人工作完成”);
Console.ReadLine();
}
}

接口
  现在,彼得成了一个特殊的人,他不但能容忍吝啬的老板,而且和他周围的宇宙也有了密切的联系,以至于他认为宇宙对他的工作进度也感兴趣。不幸的是,他必须也给宇宙添加一个特殊的回调函数Advise来实现同时向他老板和宇宙报告工作进度。彼得想要把潜在的通知的列表和这些通知的实现方法分离开来,于是他决定把方法分离为一个接口:

interface IWorkerEvents {
void WorkStarted();
void WorkProgressing();
int WorkCompleted();
}
class Worker {
public void Advise(IWorkerEvents events) { _events = events; }
public void DoWork() {
Console.WriteLine(“工作: 工作开始”);
if( _events != null ) _events.WorkStarted();
Console.WriteLine(“工作: 工作进行中”);
if(_events != null ) _events.WorkProgressing();
Console.WriteLine("“工作: 工作完成”");
if(_events != null ) {
int grade = _events.WorkCompleted();
Console.WriteLine(“工人的工作得分=” + grade);
}
}
private IWorkerEvents _events;
}
class Boss : IWorkerEvents {
public void WorkStarted() { /* 老板不关心。 */ }
public void WorkProgressing() { /* 老板不关心。 */ }
public int WorkCompleted() {
Console.WriteLine(“时间差不多!”);
return 3; /* 总分为10 */
}
}

委托
  不幸的是,每当彼得忙于通过接口的实现和老板交流时,就没有机会及时通知宇宙了。至少他应该忽略身在远方的老板的引用,好让其他实现了IWorkerEvents的对象得到他的工作报告。(”At least he'd abstracted the reference of his boss far away from him so that others who implemented the IWorkerEvents interface could be notified of his work progress” 原话如此,不理解到底是什么意思 )
  他的老板还是抱怨得很厉害。“彼得!”他老板吼道,“你为什么在工作一开始和工作进行中都来烦我?!我不关心这些事件。你不但强迫我实现了这些方法,而且还在浪费我宝贵的工作时间来处理你的事件,特别是当我外出的时候更是如此!你能不能不再来烦我?”
  于是,彼得意识到接口虽然在很多情况都很有用,但是当用作事件时,“粒度”不够好。他希望能够仅在别人想要时才通知他们,于是他决定把接口的方法分离为单独的委托,每个委托都像一个小的接口方法:

delegate void WorkStarted();
delegate void WorkProgressing();
delegate int WorkCompleted();
class Worker {
public void DoWork() {
Console.WriteLine(“工作: 工作开始”);
if( started != null ) started();
Console.WriteLine(“工作: 工作进行中”);
if( progressing != null ) progressing();
Console.WriteLine("“工作: 工作完成”");
if( completed != null ) {
int grade = completed();
Console.WriteLine(“工人的工作得分=” + grade);
}
}
public WorkStarted started;
public WorkProgressing progressing;
public WorkCompleted completed;
}
class Boss {
public int WorkCompleted() {
Console.WriteLine("Betterhttp://www.cnblogs.com/Images/dot.gif");
return 4; /* 总分为10 */
}
}
class Universe {
static void Main() {
Worker peter = new Worker();
Boss boss = new Boss();
peter.completed = new WorkCompleted(boss.WorkCompleted);
peter.DoWork();
Console.WriteLine(“Main: 工人工作完成”);
Console.ReadLine();
}
}

静态监听者
  这样,彼得不会再拿他老板不想要的事件来烦他老板了,但是他还没有把宇宙放到他的监听者列表中。因为宇宙是个包涵一切的实体,看来不适合使用实例方法的委托(想像一下,实例化一个“宇宙”要花费多少资源…..),于是彼得就需要能够对静态委托进行挂钩,委托对这一点支持得很好:

class Universe {
static void WorkerStartedWork() {
Console.WriteLine("Universe notices worker starting work");
}
static int WorkerCompletedWork() {
Console.WriteLine("Universe pleased with worker's work");
return 7;
}
static void Main() {
Worker peter = new Worker();
Boss boss = new Boss();
peter.completed = new WorkCompleted(boss.WorkCompleted);
peter.started = new WorkStarted(Universe.WorkerStartedWork);
peter.completed = new WorkCompleted(Universe.WorkerCompletedWork);
peter.DoWork();
Console.WriteLine(“Main: 工人工作完成”);
Console.ReadLine();
}
}

事件
  不幸的是,宇宙太忙了,也不习惯时刻关注它里面的个体,它可以用自己的委托替换了彼得老板的委托。这是把彼得的Worker类的的委托字段做成public的一个无意识的副作用。同样,如果彼得的老板不耐烦了,也可以决定自己来激发彼得的委托(真是一个粗鲁的老板):
// Peter's boss taking matters into his own hands
if( peter.completed != null ) peter.completed();
  彼得不想让这些事发生,他意识到需要给每个委托提供“注册”和“反注册”功能,这样监听者就可以自
己添加和移除委托,但同时又不能清空整个列表也不能随意激发彼得的事件了。彼得并没有来自己实现这些功能,相反,他使用了event关键字让C#编译器为他构建这些方法:

class Worker {
//http://www.cnblogs.com/Images/dot.gif
public event WorkStarted started;
public event WorkProgressing progressing;
public event WorkCompleted completed;
}

  彼得知道event关键字在委托的外边包装了一个property,仅让C#客户通过+= 和 -=操作符来添加和移除,强迫他的老板和宇宙正确地使用事件。

static void Main() {
Worker peter = new Worker();
Boss boss = new Boss();
peter.completed += new WorkCompleted(boss.WorkCompleted);
peter.started += new WorkStarted(Universe.WorkerStartedWork);
peter.completed += new WorkCompleted(Universe.WorkerCompletedWork);
peter.DoWork();
Console.WriteLine(“Main: 工人工作完成”);
Console.ReadLine();
}

“收获”所有结果
  到这时,彼得终于可以送一口气了,他成功地满足了所有监听者的需求,同时避免了与特定实现的紧耦合。但是他注意到他的老板和宇宙都为它的工作打了分,但是他仅仅接收了一个分数。面对多个监听者,他想要“收获”所有的结果,于是他深入到代理里面,轮询监听者列表,手工一个个调用:

public void DoWork() {
http://www.cnblogs.com/Images/dot.gif
Console.WriteLine("“工作: 工作完成”");
if( completed != null ) {
foreach( WorkCompleted wc in completed.GetInvocationList() ) {
int grade = wc();
Console.WriteLine(“工人的工作得分=” + grade);
}
}
}

异步通知:激发 & 忘掉
  同时,他的老板和宇宙还要忙于处理其他事情,也就是说他们给彼得打分所花费的事件变得非常长:

class Boss {
public int WorkCompleted() {
System.Threading.Thread.Sleep(3000);
Console.WriteLine("Betterhttp://www.cnblogs.com/Images/dot.gif"); return 6; /* 总分为10 */
}
}
class Universe {
static int WorkerCompletedWork() {
System.Threading.Thread.Sleep(4000);
Console.WriteLine("Universe is pleased with worker's work");
return 7;
}
http://www.cnblogs.com/Images/dot.gif
}

  很不幸,彼得每次通知一个监听者后必须等待它给自己打分,现在这些通知花费了他太多的工作事件。于是他决定忘掉分数,仅仅异步激发事件:

public void DoWork() {
http://www.cnblogs.com/Images/dot.gif
Console.WriteLine("“工作: 工作完成”");
if( completed != null ) {
foreach( WorkCompleted wc in completed.GetInvocationList() )
{
wc.BeginInvoke(null, null);
}
}
}

异步通知:轮询
  这使得彼得可以通知他的监听者,然后立即返回工作,让进程的线程池来调用这些代理。随着时间的过去,彼得发现他丢失了他工作的反馈,他知道听取别人的赞扬和努力工作一样重要,于是他异步激发事件,但是周期性地轮询,取得可用的分数。

public void DoWork() {
http://www.cnblogs.com/Images/dot.gif
Console.WriteLine("“工作: 工作完成”");
if( completed != null ) {
foreach( WorkCompleted wc in completed.GetInvocationList() ) {
IAsyncResult res = wc.BeginInvoke(null, null);
while( !res.IsCompleted ) System.Threading.Thread.Sleep(1);
int grade = wc.EndInvoke(res);
Console.WriteLine(“工人的工作得分=” + grade);
}
}
}

异步通知:委托
  不幸地,彼得有回到了一开始就想避免的情况中来,比如,老板站在背后盯着他工作。于是,他决定使用自己的委托作为他调用的异步委托完成的通知,让他自己立即回到工作,但是仍可以在别人给他的工作打分后得到通知:

 public void DoWork() {
http://www.cnblogs.com/Images/dot.gif
Console.WriteLine("“工作: 工作完成”");
if( completed != null ) {
foreach( WorkCompleted wc in completed.GetInvocationList() ) {
wc.BeginInvoke(new AsyncCallback(WorkGraded), wc);
}
}
}
private void WorkGraded(IAsyncResult res) {
WorkCompleted wc = (WorkCompleted)res.AsyncState;
int grade = wc.EndInvoke(res);
Console.WriteLine(“工人的工作得分=” + grade);
}

宇宙中的幸福
  彼得、他的老板和宇宙最终都满足了。彼得的老板和宇宙可以收到他们感兴趣的事件通知,减少了实现的负担和非必需的往返“差旅费”。彼得可以通知他们,而不管他们要花多长时间来从目的方法中返回,同时又可以异步地得到他的结果。彼得知道,这并不*十分*简单,因为当他异步激发事件时,方法要在另外一个线程中执行,彼得的目的方法完成的通知也是一样的道理。但是,迈克和彼得是好朋友,他很熟悉线程的事情,可以在这个领域提供指导。
  他们永远幸福地生活下去……

前段时间帮朋友做的网站Logo设计方案,也不知道现在网站做的怎么样了,祝他们好运。

http://www.felixwoo.com/wp-content/uploads/attachments/200603/06_112016_yohologoshow.jpg

京ICP备05053527号
经过26次查询历时3.006秒终于生成了此页面
Powered by WordPress & Designed by Felix © 2008