﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>博客园-Cat in dotNET</title><link>http://www.cnblogs.com/cathsfz/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 24 Jul 2008 20:23:58 GMT</lastBuildDate><pubDate>Thu, 24 Jul 2008 20:23:58 GMT</pubDate><ttl>60</ttl><item><title>英语阅读推荐：创建Silverlight用户控件 &amp; A*路径搜索中使用二叉堆</title><link>http://www.cnblogs.com/cathsfz/archive/2008/04/07/1139710.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Sun, 06 Apr 2008 20:07:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/04/07/1139710.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1139710.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/04/07/1139710.html#Feedback</comments><slash:comments>14</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1139710.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1139710.html</trackback:ping><description><![CDATA[<p>本期<a href="http://www.cnblogs.com/cathsfz/category/76688.html">Random Clippings</a>推荐两篇文章，一篇关于时下热门的Silverlight，而另一篇则是相对学术风格的二叉堆使用方法介绍。</p>
<h3>创建Silverlight用户控件 (<a href="http://weblogs.asp.net/scottgu/archive/2008/04/04/tip-trick-creating-and-using-silverlight-and-wpf-user-controls.aspx">Creating and Using Silverlight and WPF User Controls</a>)</h3>
<p>Scott Guthrie的文章总是那么简单易懂，有时候还有丰富的插图，简直就如看连环画一般容易，因此作为入门级别的英语阅读练习文章就最适合不过了。这次Scott讲的是如何创建Silverlight（或WPF）的用户控件，不过用的不是VS2008，而是Expression Blend。</p>
<p>文章开头应该只有一个词是需要查字典的，也就是&#8220;encapsulate&#8221;，而这正是重点。为什么我们需要用户控件？因为我们需要对重复的逻辑进行&#8220;封装&#8221;，这样才能复用描述这些逻辑的代码，&#8220;encapsulate&#8221;正是&#8220;封装&#8221;的意思。在看懂了这个词之后，就是看图说话了，文章一步一步地教你如何将一组已有的控件圈选出来，然后生成一个用户控件。我想你看完图片，就一定能读懂图片下方对应的文字，甚至你可以为这张图配上更好的英文描述。</p>
<p>在完成了用户控件的创建后，Scott以数据绑定为例介绍了其使用方式。首先，你要定义待绑定的类型，实例化并填充数据，最后在XAML中加上绑定语句，之后就是继续看图说话了。在此问大家一个问题，知道阅读英语文章时你的障碍除了来自于你个人的英语能力，还来自于什么吗？答案是文化背景的差异，甚至是文章结构风格的差异，中国人喜欢把重点（或者是真正要表述的意思）放到文章的最后，并称之为&#8220;压轴&#8221;，然而美国人的思维习惯恰好是相反的，打个比喻就是——&#8220;重点请先说，后面的可能我没时间听下去&#8221;。</p>
<p>文化背景差异造成的障碍就更大了，一些约定俗成的东西可能你无法理解，从而某些幽默可能你当成了事实，这就导致更大范围的误解了。举一个简单的例子，知道Scott这篇文章中的这张图片有什么好笑吗？</p>
<p><img src="http://www.scottgu.com/blogposts/extractusercontrol/step11.png"  alt="" /> </p>
<p>如果你理解使用信用卡时&#8220;ship to&#8221;和&#8220;bill to&#8221;的用途，并且你知道上述两个地址分别是哪里，那么你看到这样图就会哈哈大笑——&#8220;货物送往<a href="http://www.google.com/search?q=One+Microsoft+Way%2C+98052&amp;sourceid=navclient-ff&amp;ie=UTF-8&amp;rlz=1B3GGGL_enCN250">Microsoft</a>，并请<a href="http://www.google.com/search?q=One+Infinite+Loop%2C+95014&amp;sourceid=navclient-ff&amp;ie=UTF-8&amp;rlz=1B3GGGL_enCN250">Apple</a>买单&#8221;，这太恶搞了！（如果你还是不明白的话，请点击Microsoft与Apple上面的链接。）</p>
<p>在这里，你就看到了文化背景的影响。然而英语是一个不能逃避的问题，要说因为背景不同从而避免阅读英文文章，还不如多读从而逐步了解这些背景。在新东方，我碰到过一个教TOEFL的老师，他说他从来没到过美国读大学，但却对美国大学里面的生活情景了如指掌，例如如何申请宿舍，停车场是区分教工车位和学生车位，代号101的课程通常是入门课程，等等。为什么呢？他说因为他做了大量的TOEFL听力题，而一般听力题都是这类情景下的对话，因此即使你不是生活在那种文化中你也可以对它有所掌握。</p>
<h3>A*路径搜索中使用二叉堆 (<a href="http://www.policyalmanac.org/games/binaryHeaps.htm">Using Binary Heaps in A* Pathfinding</a>)</h3>
<p>如果你要深入研究某些技术，不可不勉地你必须阅读一些很学术的英文文章，这篇文章就是一个例子。</p>
<p>在这篇文章中，首先说的是一维列表的解决方案，并且说明为什么效率是问题。然后解决方案自然是binary heap，这就要说说binary heap的二叉树结构如何能够保存在一维数组中。接下来是对binary heap添加删除元素操作的简单说明，并且解释了为什么binary heap的效率比简单的一维列表要高。请注意，到此为止文章都没有深入binary heap的实线细节，这就是美国人比较习惯的写法，先briefing一次，再深入，因此后面的部分你看不懂也至少懂了一般。如果在前面就直接引入细节，你看不懂，就算后面还是有显浅的内容你可能也会错过。</p>
<p>在文章的后半部分中，作者深入地解释了binary heap的数据结构、操作算法，读完这一部分你就知道如何在自己的程序中实现binary heap了。并且在文章的最后，还有若干个延伸阅读的链接。通过读这篇文章，你就能了解到美国人一般是如何组织科学类文章的主干是如何安排的。</p>
<p>最后，如果你觉得Random Clipping的推荐不错，可以考虑长期<a href="http://feeds.feedburner.com/CatChen/dotNET">订阅Cat in dotNET</a>，这样你将不会错过将来的任何一篇推荐。</p>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1139710.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41284/" target="_blank">[新闻]奇虎回应:瑞星半年免费版像是一个恶意软件</a>]]></description></item><item><title>救救 Web Developers ，拒绝 IE6 ！</title><link>http://www.cnblogs.com/cathsfz/archive/2008/04/06/1139262.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Sun, 06 Apr 2008 08:41:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/04/06/1139262.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1139262.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/04/06/1139262.html#Feedback</comments><slash:comments>55</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1139262.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1139262.html</trackback:ping><description><![CDATA[<p>这是最近的一场于web developers相关的campaign，官方站点是<a href="http://www.savethedevelopers.org/">SaveTheDevelopes.org</a>。在上面你可以下载一段脚本和对应的图片，放到你自己的网站上，然后只要有用户使用IE6访问你的网站，他就会看到一个小小的提示框，建议他升级到IE7或选用其它非IE浏览器。当然，你也可以直接引用SaveTheDevelopers.org上面的脚本文件，但大家都知道潜在的风险，因此最好不要这样做，如果你有自己的空间的话最好还是下载下来放到自己的空间上。</p>
<p>为了支持这个campaign，我特意为他们做了一个<a href="http://www.savethedevelopers.org/lang/zh/">中文翻译</a>。我本来是想和<a href="http://www.awflasher.com/blog/">aw</a>一起做的，不过他们把内容发给我的那个晚上找不到aw，于是有翻译问题就直接找<a href="http://blog.wangjunyu.net/">Junyu</a>问了，最后在Junyu的帮忙下把翻译搞定了。我在想是不是应该多做一个粤语翻译，这样会比较好玩，反正也就一个晚上的事情而已。</p>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1139262.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41283/" target="_blank">[新闻]鲍尔默致员工信：部署09年微软5大工作重心</a>]]></description></item><item><title>讲座资源：Silverlight 2.0</title><link>http://www.cnblogs.com/cathsfz/archive/2008/03/31/1130959.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Mon, 31 Mar 2008 04:17:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/03/31/1130959.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1130959.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/03/31/1130959.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1130959.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1130959.html</trackback:ping><description><![CDATA[<p>这是2008年3月30日微软广州.NET俱乐部活动上Silverlight 2.0这一部分讲座的资源，包括了<a href="http://www.cnblogs.com/Files/cathsfz/Silverlight_2_0.zip">pptx</a>以及<a href="http://www.cnblogs.com/Files/cathsfz/SilverlightDemo.zip">演示网站</a>（演示网站中的SilverlightDemoHost项目需要部署为<a href="http://localhost/SilverlightDemo/">http://localhost/SilverlightDemo/</a>）。</p>
<p>在这次的讲座上，讲的主要是Silverlight 2.0的新特性，而上次Silverlight 1.0所讲过的内容没有再次重复。不过在问答环节，现在还是有一部分的听众比较关心之前Silverlight 1.0讲过的内容，例如为什么需要RIA，或者是如何实现动画等等。建议大家如果没有听过上次Silverlight 1.0的讲座，可以先看看上次的pptx，<a href="http://www.cnblogs.com/cathsfz/archive/2007/11/17/962876.html">讲座资源：Silverlight In Action</a>。</p>
<p>最后，如果大家对活动有什么反馈信息，欢迎直接留言。</p>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1130959.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41282/" target="_blank">[新闻]陈一舟:Facebook也抄袭过校内 不怕打官司</a>]]></description></item><item><title>深入理解 ASP.NET 动态控件 (Part 6 - 模板控件)</title><link>http://www.cnblogs.com/cathsfz/archive/2008/03/26/1122275.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Tue, 25 Mar 2008 16:39:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/03/26/1122275.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1122275.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/03/26/1122275.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1122275.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1122275.html</trackback:ping><description><![CDATA[<p>在之前的文章中，我极力推荐大家使用Repeater和MultiView这类TemplateControl，为什么呢？因为只有这样做，才算是符合MVP或MVC模式。（到底是MVP还是MVC，这视乎你选用什么呈现引擎了。）</p>
<p>虽然我们要动态创建控件，但实际上这部分控件仍然属于View的部分，我们应该尽量采用ASPX的声明性名义来描述这些控件，避免用C#代码来创建控件、设置属性并添加为子控件。就拿最简单的例子来说，创建一个LinkButton，通常我们都需要设置它的ID、Text、OnClick属性/事件，甚至还要设置OnCommand、CommandName、CommandArgument等属性/事件，那就是大概3到5个属性了，用ASPX来声明只需要1~2行代码，而用C#代码则需要写至少5行（把new和Add()也算上的话），由此可见在定义控件这类声明上ASPX比C#代码的可读性要高。</p>
<p>接下来，我们来研究一下TemplateControl是如何工作的，这自然要从如何编写一个TemplateControl讲起。</p>
<h3>编写模板控件</h3>
<p>在这里，我们假设要编写一个SimpleRepeater控件，自身不支持数据绑定，只有唯一一个名为ItemTemplate的模板，并且就按照Count属性指定的次数重复出现该模板。首先，让我们来定义这两个属性：<br />
public ITemplate ItemTemplate { get; set; }<br />
public int Count { get; set; }</p>
<p>因为ItemTemplate属性不是以键值对的形式在SimpleRepeater的声明中给出的，而是以内嵌一对标签的方式定义的，因此我们需要让解释器去把<strong>&lt;ItemTemplate&gt;...&lt;/ItemTemplate&gt;</strong>中间的内容读取出来，并把解释结果作为ItemTemplate属性的值处理。这时候，我们就需要为SimpleRepeater类加上ParseChildrenAttribute，也就是这样子：<br />
<strong>[ParseChildren(true)] public class SimpleRepeater {...}</strong></p>
<p>最后，我们需要重载一下CreateChildControl()方法，把ItemTemplate的内容作为子控件添加到SimpleRepeater之内：<br />
protected override void CreateChildControls()<br />
{<br />
&nbsp; if (ItemTemplate != null)<br />
&nbsp; {<br />
&nbsp;&nbsp;&nbsp; Controls.Clear();<br />
&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; Count; i++)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Control control = new Control();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ItemTemplate.InstantiateIn(control);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Controls.Add(control);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
}</p>
<p>这段代码的用意应该是相当清晰的了，就是循环Count指定那么多次，每次循环创建一个空白的Control，用ItemTemplate.InstantiateIn()方法填充它，最后把它添加到SimpleRepeater.Controls里面，就那么简单。那么这个神秘的InstantiateIn()方法到底是干什么的呢？后面来解释。</p>
<h3>编译模板控件</h3>
<p>在之前的《<a href="http://www.cnblogs.com/cathsfz/archive/2006/11/05/550985.html">深入理解 ASP.NET 动态控件 (Part 2 - 编译过程)</a>》里面，我详细地解释了ASP.NET 2.0的编译模型。在《<a href="http://www.cnblogs.com/cathsfz/archive/2008/03/24/1119465.html">深入理解 ASP.NET 动态控件 (Part 5 - 编译实验)</a>》中，我们又做了一个动手实验，亲眼看到了ASPX和C#代码是如何编译到一起的。现在让我们来看看当碰上模板控件时，代码会被如何编译吧。我们把上面编写的SimpleRepeater注册到页面上，前缀为ctrl，并且编写如下一段代码：<br />
&lt;ctrl:SimpleRepeater ID="SimpleRepeater1" Count="10" runat="server"&gt;<br />
&nbsp; &lt;ItemTemplate&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;asp:Button ID="Button1" Text="Button" runat="server" /&gt;<br />
&nbsp; &lt;/ItemTemplate&gt;<br />
&lt;/ctrl:SimpleRepeater&gt;</p>
<p>然后还是用aspnet_compiler编译一下，并且用Reflector打开编译出来的dll看看。我们可以看到构造SimpleRepeater实例是通过这样一个语句完成的：<br />
<strong>return new SimpleRepeater { ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control1)), Count = 10 };</strong></p>
<p>这个语句其实就是一个普通的new语句，并且给ItemTemplate和Count两个属性赋值了，唯一值得关注的就是ItemTemplate的值。ItemTemplate的类型是ITemplate，因此任何实现了ITemplate接口的类都可以复制给它，然而我们却从来没指定过到底要赋值什么类型的实例给它，因为这已经由ASP.NET帮我们想好了，假若我们不指定的话，那就是CompiledTemplateBuilder类型。还是熟悉的Builder模式，它只需要已委托的形式接受一个实例化ITemplate的函数，然后就能返回实例化好的ITemplate控件子树。可能你会问，既然我已经有实例化ITemplate的函数，干什么要先传给你CompiledTemplateBuilder，让你来调用一下，再把实例化好的给我？我自己实例化不好吗？在此，ASP.NET引擎的做法只是为了保持Builder模式的一致性，处处用Builder模式来分离逻辑而已。</p>
<p>那么这个用于实例化ITemplate的函数从哪来呢？在解释器进入到<strong>&lt;ItemTemplate&gt;...&lt;/ItemTemplate&gt;</strong>内部时，它会继续层层构建Builder模式，就如同在整个页面内执行的一样。因此，整个<strong>&lt;ItemTemplate&gt;...&lt;/ItemTemplate&gt;</strong>会被解释器转化为一个函数，它也是通过层层调用内部函数完成自身的控件子树的构建，传递给BuilderTemplateBuilder构造函数的委托正是指向此函数。</p>
<p>因此，模板控件里面的内容将如同模板外的内容一样，被无缝地解释和构建到一起来。</p>
<h3>INamingContainer</h3>
<p>如果你查看SimpleRepeater输出的HTML代码，你会发现里面有10个<strong>&lt;input id="Button1" name="Button1" type="button" value="Button" /&gt;</strong>。我们都知道，重复的id是不符合标准的，因此我们需要通过INamingContainer把这个问题解决掉。因为重复的控件是ITemplate，所以应该对它加上INamingContainer，然而它的实例编译时自动使用了CompiledTemplateBuilder，我们如何把INamingContainer加上去呢？我们就只能把INamingContainer加到它的父控件上面去。此时，我们需要一个实现了INamingContainer的简单控件：<br />
<strong>public class SimpleRepeaterItem : System.Web.UI.Control, System.Web.UI.INamingContainer {}</strong></p>
<p>然后我们把SimpleRepeater.CreateChildControls()方法的这个语句：<strong>Control control = new Control()</strong>，替换为：<strong>SimpleRepeaterItem control = new SimpleRepeaterItem()</strong>。这样，ITemplate的容器就变成了一个具有INamingContainer接口的控件，这时候各个Button的客户端id就会自动加上其容器的id作为前缀，因为容器的服务器端ID是自动变好的，所以必然是各不相同的，这样就解决了Button客户端id相同的问题。</p>
<p>通过这个例子，我们了解到了编写模板控件时必须为模板的容器加上INamingContainer，因为模板内的控件ID命名是可能重复的，加上INamingContainer就可以避免它们的客户端id重复。</p>
<h3>小结</h3>
<p>这次的文章解释了为什么我们应该尽量使用模板控件来实现动态控件，并且也说明了如何编写自己的模板控件，以及模板控件最终是被如何编译为Builder模式的代码的。</p>
<ul>
    <li><a href="http://chinese.catchen.biz/">Cat in Chinese</a> (feed: <a href="http://feeds.feedburner.com/CatChen/Chinese">http://feeds.feedburner.com/CatChen/Chinese</a>)  </li>
    <li><a href="http://dotnet.catchen.biz/">Cat in dotNET</a> (feed: <a href="http://feeds.feedburner.com/CatChen/dotNET">http://feeds.feedburner.com/CatChen/dotNET</a>) </li>
</ul>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1122275.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41281/" target="_blank">[新闻]微软重组视窗与在线业务</a>]]></description></item><item><title>深入理解 ASP.NET 动态控件 (Part 5 - 编译实验)</title><link>http://www.cnblogs.com/cathsfz/archive/2008/03/24/1119465.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Mon, 24 Mar 2008 04:04:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/03/24/1119465.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1119465.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/03/24/1119465.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1119465.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1119465.html</trackback:ping><description><![CDATA[<p>这次的文章是一个小小的动手实验，你需要准备好Visual Studio 2005或者Visual Studio 2008，以及最新版本的Reflector。通过这次的实验，你将对ASPX与C#代码如何合并编译为一个dll代码有所理解。</p>
<p>在实验开始之前，首先来一个小问题：如果不允许你使用ASPX，要你完全使用C#代码写一个具备复杂控件树的页面你会怎么写？把声明控件的代码都放在Page_Load里面吗？或者有更好的代码编写方法？先想想这个问题，然后继续往下看。</p>
<p>实验的第一步，也就是在Visual Studio里面创建一个ASP.NET项目，并编写一个简单的ASPX页面。例如下面这个例子：（以下代码仅包括HtmlForm内的主体部分）<br />
&lt;asp:MultiView ID="MultiView1" runat="server"&gt;<br />
&nbsp; &lt;asp:View ID="View1" runat="server"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;div&gt;Please choose either of the followings:&lt;/div&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;asp:RadioButton ID="RadioButton1" runat="server" /&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;asp:RadioButton ID="RadioButton2" runat="server" /&gt;<br />
&nbsp; &lt;/asp:View&gt;<br />
&nbsp; &lt;asp:View ID="View2" runat="server"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;div&gt;Please choose any of the following:&lt;/div&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;asp:CheckBox ID="CheckBox1" runat="server" /&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;asp:CheckBox ID="CheckBox2" runat="server" /&gt;<br />
&nbsp; &lt;/asp:View&gt;<br />
&lt;/asp:MultiView&gt;</p>
<p>在这个例子中，我们构建了一个简单的控件树，同时又不至于过于复杂，确保了编译出来的代码相对简单一些。接下来我们就需要将它编译了，最简单的手动编译方法就是用ASP.NET 2.0自带的<strong>aspnet_compiler.exe</strong>，这个文件默认会在这个目录中：<strong>C:\Windows\Microsoft.NET\Framework\v2.0.50727</strong>。你可以使用<strong>aspnet_compiler -h</strong>来查看完整的帮助，例如编译一个IIS默认站点中的ASP.NET子站点可以使用这样的代码：<br />
<strong>aspnet_compiler&nbsp; -v / -p C:\inetpub\wwwroot\site C:\output\site</strong>  </p>
<p>接下来，我们到输出目录的bin子目录里把dll抓到Reflector里面看看吧。你会看到这个dll里面有三个namespace，分别是-（在Reflector中代表没有namespace）、__ASP、ASP。假设你编译的站点有一个Default.aspx，那么在无namespace的类当中就会有一个_Default的类，对应的就是Default.aspx.cs编译出来的类。大家应该还记得《<a href="http://www.cnblogs.com/cathsfz/archive/2006/11/05/550985.html">深入理解 ASP.NET 动态控件 (Part 2 - 编译过程)</a>》里面提到的，直接继承自Page的类是用后台代码编译出来的，_Default类就是这样一个具体例子了。我们打开_Default类来看看，就会发现MultiView1已经是其成员了，为什么呢？MultiView1仅仅在ASPX中声明，没有在C#中声明啊。回头看看《深入理解 ASP.NET 动态控件 (Part 2 - 编译过程)》就能解释了这种现象——Default.aspx.cs是标记为partial的，而在你手动编辑的文件中，这是唯一一个partial，另外一个partial由编译器根据Default.aspx自动生成，编译器解释完Default.aspx后在自动生成的partial中定义了MultiView1，因此两个partial合并编译后，_Default类自然就有了MultiView1这个成员了。  </p>
<p>接下来，我们再看看ASP这个namespace下的default_aspx类，这个是ASPX文件继承自上述_Default类后编译的结果，它完整表述了ASPX文件中整个控件树的逻辑，而不仅仅是一个包含一堆成员控件定义的Page派生类。这个类的执行入口是FrameworkInitialize()方法，它通过调用__BuildControlTree()方法来构建控件树。在这个方法里面，你可以看到<strong>&lt;!DOCTYPE ...&gt;</strong>这样的字符串是被解释为LiteralControl的，LiteralControl在Render()时就会把这段文本原样输出。同时你还可以看到，它调用了另外两个方法，分别用来构建HtmlHead和HtmlForm，这两个方法通过类似的形式继续调用其他方法来构建更深层次的控件。  </p>
<p>通过阅读default_aspx类的代码，你已经能够理解ASPX的控件树是如何转化为C#代码的了——采用的正是Builder模式。了解到这一点，这次动手试验的目的也就达到了。如果你看到文章开头的那个问题时，你已经想到了使用Builder模式，那么此时也就验证了你的想法是完全正确的。  </p>
<p>下一次的文章将是与TemplateControl相关的，我们将继续动手做一些小实验，敬请期待。欢迎订阅我的blog：  </p>
<ul>
    <li><a href="http://chinese.catchen.biz/">Cat in Chinese</a> (feed: <a href="http://feeds.feedburner.com/CatChen/Chinese">http://feeds.feedburner.com/CatChen/Chinese</a>)  </li>
    <li><a href="http://dotnet.catchen.biz/">Cat in dotNET</a> (feed: <a href="http://feeds.feedburner.com/CatChen/dotNET">http://feeds.feedburner.com/CatChen/dotNET</a>)</li>
</ul>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1119465.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41280/" target="_blank">[新闻]我国网民数达2.53亿超美国居世界首位</a>]]></description></item><item><title>在校学生找实习、找工作、了解企业情况等等等等</title><link>http://www.cnblogs.com/cathsfz/archive/2008/03/14/1106442.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Fri, 14 Mar 2008 12:17:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/03/14/1106442.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1106442.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/03/14/1106442.html#Feedback</comments><slash:comments>51</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1106442.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1106442.html</trackback:ping><description><![CDATA[<p>因为时不时就有低年级的同学跑来问我这类问题，所以我干脆写篇文章好了。</p>
<h3>信息获取</h3>
<p>最先想到的，也是最重要的，是你想干什么，而不是你父母想你去干什么，或者哪个赚钱之类的。在计算机系里面，你总能碰到一些对这个行业没什么感觉的人，他们会说当年填报志愿的时候根本没什么喜欢不喜欢可言，于是在父母驱使下或者金钱诱惑下就报了计算机系。显然你不想犯这类错误，因此第一步是弄清楚你想要什么，或者说，有什么是你可以选择不要的。世界上没有十全十美的事情，所以一切都是权衡取舍（trade off），这个思想贯穿着计算机体系设计的方方面面，缺乏这种思想肯定会导致你在这个行业里发展受到限制，所以首先你要想好的就是你将来的职业发展取什么而舍什么。</p>
<p>在你先清晰了解自己之后，才有如何了解企业实际情况的问题。如果说第一个问题严重依赖于你个人悟性的话，那么第二个问题就依赖于你的人脉了，至少是你的外向程度和活跃程度。</p>
<p>一个企业，其自身对外的公关肯定只会说好话，就算没有任何夸张成分，也不会让你看到这个企业内部任何的不足。因此，如果你需要知道一些细节，看看这企业是否如你想象中那么好，你就必须认识在这家企业里面的员工，通过他们好好了解一下。如果你是一个在学校里已经很活跃的学生，整天在BBS上板聊，或者参加各种学生社团的活动，那么你肯定有机会认识到不少比你高一两个年级的同学，看看他们里面有没有一些正好在你想去的企业工作的，联系他们了解一下企业的情况，例如工资和各种福利怎么算啊，工作与学习的氛围如何啊，以及他们是否也认为你适合这个企业。</p>
<p>如果有机会多问几个人的话，最好都问问，并且以人生经历和价值取向与你相近的人的说法为主要参考。这是因为，在同一家企业里面，不同的员工看到它不同的方面，并且都带有自己的主观想法，因此得出的评价可能截然不同。这就好像假如你问我北京是否好住，我肯定说不好住，因为我看重的是商业环境，我觉得北京的服务业经常让我失望，因此就这样说。但肯定也有人很喜欢住北京的，他看重其他一些因素，并且觉得我看重的那些因素可以忽略不计。如果你确实很想去一家企业，就应该多找几个员工了解情况，特别是头脑清晰能看清楚自己所在企业优劣势的人。如果你碰到一个已经被洗脑的员工，那么问什么也没用，反正他就只能帮你洗脑&#8230;&#8230;</p>
<h3>联系途径</h3>
<p>根据往年的经验，现在正是2009年毕业的学生找实习的时候，甚至有2010年毕业的学生也提前开始找实习了。积极的人肯定早已开始四处打听消息，包括各大公司招聘什么实习职位，往年难度如何，转正比例多少，等等。在这里，我就要&#8220;曝光&#8221;我身边的一些朋友了，大家不要怪我&#8220;出卖&#8221;朋友了哦，因为谁都知道成功把有才华的人推荐给自己公司的意义所在。</p>
<p>在这里，我主要说的是BGM（Baidu、Google、Microsoft的意思，不是background music），如果你对其他IT企业有兴趣的话，也可以找我帮忙，只要我认识该企业的人，我会充当一下&#8220;路由&#8221;的角色为你&#8220;尽力服务&#8221;的。</p>
<h4>Baidu</h4>
<p>如果分别把BGM比作人的话，Baidu是一个典型的中国年轻人，一点都不张扬。就如同在中国随手抓一个ASP.NET MVP问他，&#8220;你是不是很熟悉页面生命周期&#8221;，他可能回答道，&#8220;懂一点吧，有什么问题你先说说看。&#8221;虽然从资源（resources）的级别来说，Baidu是很难和Google、Microsoft去比的，但是开放程度（openness）还是是相当高的，你可以做自己喜欢做的项目，可以获取到项目所需的资源。</p>
<p>想去Baidu的可以找我，或者<a href="http://hi.baidu.com/pudding">布丁</a>，先了解一下。当然，如果你来找我的话，最好你也能说服我为什么值得推荐你。我主要做Web前端开发的，而布丁则是做后端开发的，所以如果你想申请这两个方面的职位，可以直接找我们了解Baidu现在所采用的技术或者流程。如果是其他职位，也可以帮你联系其他同事问问。完整的实习职位列表，请看<a href="http://hr.baidu.com/intern.php">这里</a>。</p>
<h4>Google</h4>
<p>Google是一个典型的美国年轻人，你不问他也会很主动地把他的优势展示给你看。在我看来，Google最大的诱惑不在于公司内的&#8220;饮食娱乐&#8221;项目（虽然这些也很吸引），而是作为一般的中国员工也可以随便跑到美国总部去，顺道参加美国举行的一些会议或者讲座。看看<a href="http://blog.wangjunyu.net">Junyu</a>同学就跑到Austin去开<a href="http://sxsw.com">SXSW</a>了。</p>
<p>如果想去Google的话，去找Junyu问问吧。别告诉我找不到他的联系方式，我通常只链接别人的blog，因为该URL就是个人的标识（即使抛开OpenID不谈），拿着这个URL你手上就已经掌握了搜索他联系方式的一切资料。Junyu喜欢把人拐卖进Google里，想了解招聘职位什么的，找他就好了。</p>
<h4>Microsoft</h4>
<p>Microsoft是个稳重的美国中年男人，Google所晒的东西，Microsoft会暗自想着&#8220;我当年又不是没晒过，现在我已经不屑于晒了&#8221;。很成熟的流程，健全的管理体制，都很好地说明了这一点。</p>
<p>貌似我没有很熟的朋友在Microsoft，不算太熟那些又不敢晒出来，所以想找人推荐的话还是联系我，然后我再帮你联系吧。想了解的话，可以找<a href="http://jeffreyzhao.cnblogs.com">Jeffrey</a>或者<a href="http://dflying.cnblogs.com">Dflying</a>这两位老员工加现任MVP，他们现在不再是员工了，可能观点会更加客观一些。</p>
<h3>其他事情</h3>
<p>据我所知，很多人也是准备找实习了，才想到要写简历的。这是一项需要创意的工作，在此我提供<a href="http://catchen.biz/">我的简历</a>和<a href="http://www.wangjunyu.net/">Junyu的简历</a>给大家作为参考。虽然我们的网站下方都写着<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Creative Commons License</a>，不过不建议你直接使用别人设计好的模板。特别是，假如你想申请Web Developer/Designer类别的职位的话，你可不能够错过这个机会好好展示你的设计风格和编码艺术。</p>
<p>最后，祝大家在08年里都能找到自己喜欢的工作学习环境，好好享受生活。</p>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1106442.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41278/" target="_blank">[新闻]瑞星炮轰奇虎用阉割版杀毒软件欺骗用户</a>]]></description></item><item><title>使用 .NET 实现 Ajax 长连接 (Part 2 - Mutex Wait &amp; Signal)</title><link>http://www.cnblogs.com/cathsfz/archive/2008/03/08/1096654.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Sat, 08 Mar 2008 09:21:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/03/08/1096654.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1096654.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/03/08/1096654.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1096654.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1096654.html</trackback:ping><description><![CDATA[<p>在上一次的文章中，我们说到了如何设计一个ASP.NET Web Service来处理长连接请求。很多人对此就提出了问题，如何hold住请求让它30秒不断开了？这其实很简单，只需要Sleep()一下就可以了：</p>
<blockquote><strong>
<p>Thread.Sleep(30 * 1000);</p>
</strong></blockquote>
<p>然而问题是，我们不是要等30秒然后看看是否有事件需要返回，而是在这30秒内随时有事件随时返回。因此，我们需要一套机制来在等待的过程中检查是否有事件发生了。</p>
<h3>Monitor模型</h3>
<p>在.NET里面，大家最熟悉的线程同步模型应该就是Monitor模型了。没听说过？就是C#的那个lock关键字，实际上它编译出来就是一对Monitor.Enter()和Monitor.Exit()。</p>
<p>通过lock命令，我们可以针对一个对象创建一个临界区，代码执行到临界区入口时必须获取到该对象的锁才能执行下去，并且在临界区的出口释放该锁。然而这种模型不太适用于解决我们的问题，因为我们需要等待一个事件，如果使用lock来等待的话，那就是说要先在Web Service外部把对象锁上，然后等事件触发了就解锁，这时候Web Service才顺利进入临界区域。</p>
<p>事实上，要进行这类型的阻塞，还有一个更好的选择，那就是Mutex。</p>
<h3>Mutex模型</h3>
<p>Mutex，也就是mutual exclusive的缩写，&#8220;互斥&#8221;的意思。Mutex是如何运作的？这有点像是银行的排队叫号系统，所有等待服务的人都坐在大厅里等候（wait）被叫，当一个服务窗口空闲时它就会发出一个信号（signal）来通知下一位等候服务的人。总之，所有执行wait指令的线程都在等候，而每一个signal能够让一个线程结束等候继续执行。</p>
<p>在.NET里面，wait和signal这两个操作分别对应Mutex.WaitOne()和Mutex.ReleaseMutex()这两个方法。我们可以让Web Service的线程使用Mutex.WaitOne()进入等候状态，而在事件发生时使用Mutex.ReleaseMutex()来通知Web Service线程。因为必须在Mutex.ReleaseMutex()发生后Mutex.WaitOne()才可能继续执行下去，因此能够执行下去就证明必然有事件发生了并且调用了Mutex.ReleaseMutext()，这时候就可以放心地去读取事件消息了。</p>
<h3>简单示例</h3>
<p>在选定使用Mutex模型后，我们来编写一个简单的示例。首先，我们要在WebService派生类内定义一个Mutex，还有一个代表消息的字符串。</p>
<blockquote><strong>
<p>Mutex mutex = new Mutex();<br />
string message;</p>
</strong></blockquote>
<p>然后，我们定义两个WebMethod。为了把问题简单化，我们选用上一篇文章中开头所说的两个函数签名，也就说只能在一个Web Service内自己发自己收，没有发送目标的概念，也没有超时的概念，还没有可靠性设计。同时，我们将Message类型替换为普通字符串，以便于我们测试。</p>
<p>我们先编写发送消息的函数：</p>
<blockquote><strong>
<p>public void Send(string message) {<br />
&nbsp; this.message = message;<br />
&nbsp; this.mutex.ReleaseMutex();<br />
}<br />
</p>
</strong></blockquote>
<p>在这个发送函数里，首先我们把消息放进了类内全局的变量中，然后让全局的Mutex类释放一个signal。这时候，如果有线程在等待，它可以马上执行下去。如果此时没有线程在等待，那么下一个wait的线程执行到该阻塞的地方就能够不受阻塞继续执行下去。</p>
<p>现在我们来编写接收消息的函数：</p>
<blockquote><strong>
<p>public string Wait() {<br />
&nbsp; this.mutex.WaitOne();<br />
&nbsp; return this.message;<br />
}<br />
</p>
</strong></blockquote>
<p>接收函数一开始就进入wait状态。在得到signal后，需要做的事情就是把全局的消息返回给客户端。</p>
<h3>亲身体验</h3>
<p>最后，我们可以通过ASP.NET Web Service本身支持的Web测试界面来测试一下我们的代码。我们开两个浏览器窗口，一个进入Send()调用，一个进入Wait()调用。然后我们按照如下方法来测试：</p>
<ol>
    <li>首先执行Send("Hello")，然后执行Wait()。这时候你可以马上看到"Hello"。  </li>
    <li>首先执行Wait()，让它等待返回，这时候执行Send("Hello")。随后你可以看到Wait()那段返回"Hello"了。  </li>
    <li>按如下顺序执行：Send("Hello");Wait();Send("World");Wait();  </li>
    <li>按如下顺序执行：Send("Hello");Send("World");Wait();Wait();  </li>
    <li>按如下顺序执行：Wait();Wait();Send("Hello");Send("World");  </li>
    <li>按如下顺序执行：Wait();Send("Hello");Wait();Send("World");</li>
</ol>
<p>你会发现这样一些奇怪的结果：第3个测试返回的是"World"和"World"。第5个测试先返回"Hello"的并不一定是先执行的那个Wait()线程。后者在某些情况下不是什么问题，特别是长连接中一般之后一个Wait()线程在等待中，所以我们可以不管。而前者，则是因为没有消息队列所造成的，我们只有长度为1的消息窗口，所以只能缓存最后一个消息。这个问题我们将在下一篇文章中解决。</p>
<h3>小结</h3>
<p>在本文中，我们看到了不同的线程同步模型的差异。Monitor模型的lock本质上是一个Semaphore，也就是一个不能连续signal的Mutex，一个signal发出去后必须被一个wait接收了才能进行下一次的signal。同时，Semaphore也限制了signal和wait必须在同一个线程内成对执行，而Mutex则没有此限制。虽然.NET是针对Monitor模型优化的，但在我们的需求当中，只能通过Mutex模型来解决。</p>
<p>接着，我们便写了一个小小的消协发送与接收函数，实现了我们想要的阻塞式Web Service。同时我们也看到了没有消息队列造成的问题，因此确定接下来我们要做一个消息队列。如果你想知道消息队列如何编写，欢迎订阅我的blog：</p>
<ul>
    <li><a href="http://chinese.catchen.biz">Cat in Chinese</a> (<a href="http://feeds.feedburner.com/catchen/chinese">feed</a>)  </li>
    <li><a href="http://dotnet.catchen.biz">Cat in dotNET</a> (<a href="http://feeds.feedburner.com/catchen/dotnet">feed</a>) </li>
</ul>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1096654.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41277/" target="_blank">[新闻]阿里巴巴正式成立台湾分公司</a>]]></description></item><item><title>使用 .NET 实现 Ajax 长连接 (Part 1 - Comet Web Service)</title><link>http://www.cnblogs.com/cathsfz/archive/2008/02/26/1082668.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Tue, 26 Feb 2008 09:49:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/02/26/1082668.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1082668.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/02/26/1082668.html#Feedback</comments><slash:comments>33</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1082668.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1082668.html</trackback:ping><description><![CDATA[<p>Ajax的长连接，或者有些人所说的Comet，就是指以XMLHttpRequest的方式连接服务器，连接后服务器并非即时写入相应并返回。服务器会保持连接并等待一个需要通知客户端的事件，该事件发生后马上将数据写入响应，这时候客户端就以相当&#8220;实时&#8221;的方式接收到事件通知。具体的通信模型，请参考这篇文章：《<a href="http://www.ibm.com/developerworks/cn/web/wa-lo-comet/">Comet：基于 HTTP 长连接的&#8220;服务器推&#8221;技术</a>》，里面已经说得非常详细了，我就不再复述了。</p>
<p>我们接着开始讨论如何使用.NET实现这个模型。首先我们能想到的是，我们需要一个Web Service，可以是ASP.NET Web Service，也可以是WCF Web Service，ASP.NET AJAX Library两者都支持。在这里，为了简单起见，就选择大家更熟悉的ASP.NET Web Service举例。然后，我们写下以下两个函数签名：</p>
<blockquote>
<p><strong>public void Send(Message message);</strong><br />
<strong>public Message Wait();</strong></p>
</blockquote>
<p>其中，Send函数用来发送一个Message对象，而Wait函数用来等待一个Message对象。然后，让我们来讨论一些细节问题。</p>
<h3>无事件导致超时</h3>
<p>首先，长期保持连接时不行的。对于服务器和客户端来说，这不是个问题，但我们永远都要记住中间可能存在各式各样配置怪异的网关和代理，它们上面可能有各式各样的超时规则，因此Comet最好设计为定期重连。一般情况下，如果30秒没有任何事件发生，服务器端就应该通知客户端确实没有事件发生，结束掉本次请求，然后重新开始一次新的请求以便继续等待。</p>
<p>那么上述函数签名可否用来返回一个无事件的消息呢？这是显然可以的，我们可以选择返回null表示无事件，或者返回一个EmptyMessage常量，这视乎我们使用class还是struct来定义Message。（甚至，我们还可以做一个名为NoMessageMessage的Message派生类来做这个事情。）</p>
<h3>定义发送目标</h3>
<p>上述函数签名确实能用来收发消息，但是没指名发给谁。可能有人会说，发送给谁可以在Message类里面通过一个属性来定义啊。但是Wait()方法没有说明接受方是谁，服务器端依然不知道哪些消息应该让你接收。</p>
<p>因此，我们引入Channel的概念，Channel使用其名称来标识，相同名称的就必然是同一个Channel。在发送与接受时，通过名称指定要发送到哪个Channel，这样问题就解决了。此时，函数签名修改如下：</p>
<blockquote>
<p><strong>public void Send(string channelName, Message message);</strong><br />
<strong>public Message Wait(string channelName);</strong></p>
</blockquote>
<h3>可靠的消息队列</h3>
<p>想象一个可能发生的情况，服务器端向你发送一个消息，你没有成功接收，但是服务器端认为发送了就成功了，消息从队列删除了，然后这个消息就永久丢失掉了。可能有人会强调TCP多么可靠，服务器端发送的消息如果在TCP的层面发生问题了，肯定会引发Socket级别的Exception，这个Exception冒泡上来，服务器端就能截获，从而得知发送失败，然后先不删除队首消息。可是别忘了，中间是可能存在代理的，如果代理成功把消息收回去了，可是代理发送到客户端这一步失败了，服务器端就不一定会发生异常了。</p>
<p>因此，我们需要制定一种策略，来确保下行消息总能发送到客户端。在这里，我们选择了引入逐个ACK的机制，来确认消息的接收。也就是说，服务器端发送给客户端的消息带有一个序号，在客户端收到消息后就将该序号发回给服务器端，已确认它受到了该消息。这时候，函数签名更改如下：</p>
<blockquote>
<p><strong>public int Send(string channelName, Message message);</strong><br />
<strong>public Message Wait(string channelName, int sequence);</strong></p>
</blockquote>
<p>我们使用Wait()接收到的Message中，应该有一个Sequence的属性，标记它的序号。然后，再我们执行下一次Wait()时就将该序号加1的值通过sequence参数传递回去，让服务器知道我们期望下一条消息的编号是这个。例如我们收到Message，其Sequence属性为836，那么下一次调用Wait()的时候就传给服务器837。服务器端此时应该保留了编号为836的Message在对首，如果客户端继续请求836号消息，证明它上次没收到，这次仍然发送836号消息给它；如果客户端请求837号消息，证明它成功收到836号消息的，这次就发送837号消息给它。</p>
<p>如果都不是，那该怎么办？那意味着，这是一个错误的请求，甚至可能是攻击请求，因为正常情况下不应该出现这样的请求的，服务器端可以考虑抛个无关紧要的Exception（不要告诉攻击者你知道他在攻击了），甚至直接给个400 （bad request）的响应代号。</p>
<p>与Wait()类似的，Send()也可以加入ACK机制，只需要将返回类型从void改为int就可以了，这个值就专门用于传递消息编号，实现方式和Wait()是一样的，不过Send()是由客户端保存待发送消息的队列。</p>
<h3>小结</h3>
<p>到此为止。我们的Web Service就写好了。这就写好了？只有签名没有函数体？是的，复杂的工作留给model去做，Web Service在这里只是相当于一个view，用于将model的接口暴露出来。</p>
<p>在下一次的文章中，我们将开始讨论如何实现服务器端的消息传递机制。如果你对本文章系列感兴趣的话，欢迎订阅我的blog：</p>
<ul>
    <li><a href="http://chinese.catchen.biz">Cat in Chinese</a> (<a href="http://feeds.feedburner.com/catchen/chinese">feed</a>)  </li>
    <li><a href="http://dotnet.catchen.biz">Cat in dotNET</a> (<a href="http://feeds.feedburner.com/catchen/dotnet">feed</a>) </li>
</ul>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1082668.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41276/" target="_blank">[新闻]浅析facebook的信息架构</a>]]></description></item><item><title>Windows 就是一个带 UI 的命令行</title><link>http://www.cnblogs.com/cathsfz/archive/2008/01/10/1034226.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Thu, 10 Jan 2008 13:22:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/01/10/1034226.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1034226.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/01/10/1034226.html#Feedback</comments><slash:comments>122</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1034226.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1034226.html</trackback:ping><description><![CDATA[<p>这是用过Mac之后对Windows的感觉。</p>
<p>用一个对程序员来说比较友善的比喻来说，以面向过程的方式来写一大堆函数，然后再分别塞到几个类里面，这就是Windows了。而Mac是真正的面向对象思想下设计的。</p>
<p>在Windows当中，我们貌似在操作一个&#8220;文档&#8221;、一段&#8220;文本&#8221;、一张&#8220;图片&#8221;，但实际上我们都不是在操作对象本身，而是类似于在操作handle——你不知道对象在哪里，你不能直接传递或操作对象，你只能借助仅有的API对handle进行操作，所有能对handle进行的操作都由API限制了。例如即使你在操作的是一张&#8220;图片&#8221;，你也很清楚那是一个存放为文件的图片，或者暂存在剪贴板的图片，总之你必须清楚handle在哪，否则你就算看到了那张图片也无法操作——图片在网站上，你先另存或者复制到剪贴板吧。</p>
<p>这种体验不就完全是面向过程的映射？每一个操作相当于调用一个或几个API。Windows发展了那么久，在人机交互方面还是脱离不了对DOS的简单封装。在这方面，Windows从前落后于Mac，现在还是这样。Mac虽然不能达到最理想的面向对象操作方式，但至少系统本身提供的体验要比Windows好，同时主流软件也比Windows的主流软件在体验上要好一个等次。</p>
<p>例如<a href="http://skitch.com/">Skitch</a>这个轻量级的图片处理软件，你可以抓起正在编辑的图片扔到桌面上，这就自动另存为一个图片文件了。文件与内存中的图片数据对用户来说已经无缝连接起来了。</p>
<p>再举一个例子，在Windows我们都知道回收站是个很好的比喻，不用的文件当然扔那里面。不过说真的，你多少次把文件扔里面了？你用得更多的是delete按钮，对吧？这是显然的，因为Windows用户习惯最大化窗口，这当然就把回收站遮住了，傻瓜才会选择在窗口里拖动文件的同时回到桌面接着再把文件扔到回收站里。Mac的回收站叫做废纸瘘，它出现在Dock上，Dock类似于Windows的任务栏，永远不会消失，就算自动隐藏也可以在鼠标靠近后自动跳出来，因此你永远可以把你看到的不想要的东西拖到废纸瘘上面去。</p>
<p>这也说明了一个问题，Microsoft这样去仿造Apple发明的交互方式是没用的，因为一点点的差异就可能导致可用性完全不同。Windows Mobile 7泄露的文档中，透露了Windows Mobile 7将可能有一些类似iPhone + Wiimote的功能，例如用手指拨动CD封面从而跳到下一张或上一张CD，甚至晃动手机从而跳到随机抽选的一张CD，这样的交互到底是否好用，真的很难说。</p>
<p>最后，无论你在开发Windows应用还是Web应用，我都建议你去弄个Mac来用一段时间吧，不要给一直以来Windows及Windows主流应用程序的交互设计方式禁锢了你的思路，你应该看一点新鲜点的东西。在以前，我认为Scriptaculous的拖放库完全是多余的，真该好像Atlas转变为ASP.NET AJAX时那样把拖放库丢一边，但在使用Mac之后，我才真正觉得在Web应用中推广拖放操作是非常有意义的。</p>
<p><strong>Update: </strong>这篇文章只是讨论交互，关于Win vs Mac的问
题，可以参考这篇文章：<a href="http://huajun.w18.net/2007/12/mac-os-x.html">我
为什么偏爱苹果电脑和Mac OS X</a>，里面强调了Mac设计的哲学──&#8220;简单&#8221;。
</p>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1034226.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41275/" target="_blank">[新闻]Mozilla将于本周五发布Firefox 3.1第一个预览版</a>]]></description></item><item><title>编写 iPhone Friendly 的 Web 应用程序 (Part 6 - iUI)</title><link>http://www.cnblogs.com/cathsfz/archive/2008/01/07/1029500.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Mon, 07 Jan 2008 13:01:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/01/07/1029500.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1029500.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/01/07/1029500.html#Feedback</comments><slash:comments>15</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1029500.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1029500.html</trackback:ping><description><![CDATA[<p><a href="http://code.google.com/p/iui/">iUI</a>是一个针对iPhone Safari的Web开发框架，由<a href="http://joehewitt.com/">Joe Hewitt</a>开发。这位Joe Hewitt曾经参与过Firefox的开发，包括其中的DOM Inspector以及Firebug，后来到了Facebook，为Facebook开发了iPhone专用版本，对iPhone Web开发社区算是作出了巨大贡献。</p>
<h3>样式</h3>
<p>我们继续说iUI这个框架。这个框架所做的事情，就是提供iPhone Friendly的交互方式与样式。为了简单起见，我们先来说说样式方面，iUI提供的不仅仅是一个CSS文件，基于这个CSS文件你所创建的页面能够符合iPhone的人机界面指引，并且看起来的效果贴近iPhone原生的应用程序，从而降低用户学习门槛，避免你自己设计的Web应用对iPhone操作不友善（例如按钮不够大，手指难以点击）。</p>
<h3>交互</h3>
<p>至于交互方面，iUI提供一个基于page的换页导航机制。这里所说的page不是一个Web页面，而是一个&lt;body /&gt;内的顶级DOM元素，每一个这样的DOM元素都可以作为一个page，同一时间上仅显示一个page。页面上的所有链接，要么导致page转跳，要么导致整个页面转跳。这种转跳有如下几种情况。</p>
<h4>转跳</h4>
<p>如果链接的href指向的是一个锚点，例如<strong>#somePage</strong>，那么iUI就会在页面中寻找<strong>id="somePage"</strong>的page对象，然后进行转跳。</p>
<p>如果链接的href指向的是站内地址，例如<strong>/somePage.html</strong>，那么iUI就会使用AJAX的方法加载<strong>/somePage.html</strong>的内容并追加到<strong>&lt;body /&gt;</strong>内，注意，<strong>/somePage.html</strong>必然是一个文档片段而不可能是完整的XHTML文档，否则把<strong>&lt;html /&gt;</strong>追加到<strong>&lt;body /&gt;</strong>下就是错误的了。追加的内容内可以有多个page，如果其中一个有<strong>selected="true"</strong>的属性，那么接下来将显示该page，否则显示追加内容中的第一个page。</p>
<p>最后一种情况是指向站内地址，但是有<strong>target="_replace"</strong>属性。iUI在看到<strong>target="_replace"</strong>属性后，就会知道该&lt;a /&gt;所在的page内直属元素要被删除，并且替换为目标页面的内容。在这里用CSS来解释一下所谓的直属元素，<strong>body &gt; ul#somePage &gt; li &gt; a[target="_replace"]</strong>，这里<strong>&lt;li /&gt;</strong>就是<strong>&lt;ul id="somePage /&gt;</strong>的直属元素了。这种转跳通常用于曾亮加载，例如iPhone内置的Mail打开邮箱后自动加载50封邮件，点击more之后再加载50封，Web界面上就可以通过这种方式实现——一个<strong>&lt;ul /&gt;</strong>内包含51个<strong>&lt;li /&gt;</strong>，前面50个对应50封邮件，最后一个<strong>&lt;li /&gt;</strong>包含<strong>&lt;a target="_replace" /&gt;</strong>的more链接，目标页面就是下50封邮件的<strong>&lt;li /&gt;</strong>。</p>
<p>在转跳的时候，iUI提供了一种很好看的效果，你能够看到当前page从屏幕左边移出去，新的page从屏幕右边移进来，好像PowerPoint的某种幻灯片切换动画那样。如果添加了<strong>axis="y"</strong>属性，page还能够子底向下滚动。</p>
<h4>历史记录</h4>
<p>AJAX式的页内内容更新不是不好，问题就在于浏览器无法自动保存历史记录，导致前进后退按钮实效。iUI已经解决了这个问题，上述3种转跳中的前两种iUI都会自动创建新的hash以便创建历史记录，hash默认就是<strong>#_pageId</strong>的形式，如果当前显示的page没有id，那么hash就按照增量自动分配id。</p>
<p>在拥有历史记录之后，用户就可以通过浏览器的后退按钮向前翻页了，此时相当于加载前面的page，iUI知道这是一个后退操作，就会提供反向的滚动效果（自左向右或自上向下）。</p>
<p>如果我访问页面的顺序是A &gt; B &gt; C &gt; D &gt; B，那么历史记录会如何呢？历史记录会变成A &gt; C &gt; D &gt; B，也就是说第一次访问B时B从历史记录中删除并重新添加到最前的位置了。</p>
<h3>演示</h3>
<p>说了那么多，我们来看看iUI的实战效果吧！又是Facebook或者Digg的iPhone版？不是，我们来看看自己利用iUI开发一个小应用的效果以及成本如何。就在上个周末，我花了不到20小时做了个名为iBaidu的小东西，自动抓取Baidu的搜索结果与排行榜并以iPhone friendly的方式显示出来。以下是发布到YouTube的演示视频：</p>
<p><embed src="http://www.youtube.com/v/57kRVyP0-_k&amp;rel=1" width="425" height="355" type="application/x-shockwave-flash" wmode="transparent"></embed></p>
<p>服务器端使用的技术是Ruby on Rails以及ASP.NET。为什么需要ASP.NET？这是一个很郁闷的问题，因为Baidu是基于GBK的，而RoR的编码转换能力其若无比，我懒得花时间去寻找适合的转码库，因此直接拿了ASP.NET来做抓去代理，抓取的时候顺便做一下编码转换。如果不是编码问题，那么只需要RoR就能轻松完成任务。</p>
<h3>小结</h3>
<p>在这篇文章中，我们已经看到了如果使用RoR搭配Prototype，不好意思，iUI才对，要设计一个iPhone friendly的Web应用程序是多么地容易，开发过程也相当敏捷。如果你喜欢iPhone开发系列的文章，欢迎订阅：</p>
<ul>
    <li><a href="http://chinese.catchen.biz">Cat in Chinese</a> (<a href="http://feeds.feedburner.com/catchen/chinese">feed</a>)</li>
    <li><a href="http://dotnet.catchen.biz">Cat in dotNET</a> (<a href="http://feeds.feedburner.com/catchen/dotnet">feed</a>)</li>
</ul>

<img src ="http://www.cnblogs.com/cathsfz/aggbug/1029500.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41274/" target="_blank">[新闻]瑞星将向个人用户免费1年</a>]]></description></item><item><title>MVP on dot NET - Episode 1</title><link>http://www.cnblogs.com/cathsfz/archive/2008/01/07/1028568.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Mon, 07 Jan 2008 03:38:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/01/07/1028568.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1028568.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/01/07/1028568.html#Feedback</comments><slash:comments>33</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1028568.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1028568.html</trackback:ping><description><![CDATA[<p>主持：<a href="http://www.beanpeng.com">Bean</a>、<a href="http://jeffreyzhao.cnblogs.com">Jeffrey</a>、<a href="http://dotnet.catchen.biz">Cat</a></p>
<ol>
    <li>根据<a href="http://blogs.pcworld.com/techlog/archives/006130.html">PC World</a>的统计，2007年IE7与FF的增长相当，这意味着从IE6转分别转到IE7与FF的比例为50/50。</li>
    <li>Mac效果般的Lightbox效果 - 来自<a href="http://www.panic.com/candybar/">CandyBar</a>软件首页（留意页面底部的软件截图）</li>
    <li>纯粹用C#编写的<a href="http://osnews.com/story.php/19100/SharpOS-Releases-First-Milestone">SharpOS发布了第一个里程碑版本</a> - 0.0.1</li>
    <li><a href="http://neosmart.net/blog/2008/redesigned-microsoft-website-to-use-silverlight/">NeoSmart Technologies</a>报道，Microsoft将使用Silverlight重新设计其官方网站</li>
    <li>国内的Silverlight网站 - <a hrfe="http://mu.baidu.com/">百度MP3</a></li>
    <li>在Windows Mobile手机上使用Windows Vista的<a href="http://www.cnbeta.com/article.php?sid=46238">Side Show</a>功能！</li>
    <li><a href="http://www.sprymedia.co.uk/article/Design">Design</a> - 一个很cool的纯JavaScript的Web页面设计辅助工具</li>
    <li>使用来自webkit团队的<a href="http://www.codinghorror.com/blog/archives/001023.html">Sunspider</a>测试各种浏览器的JavaScript引擎性能</li>
    <li><a href="http://www.alistapart.com/articles/previewofhtml5">HTML 5 Preview</a> - XHTML 2.0还有发展前途吗？
    </li>
</ol>
<p>直接下载地址：<a href="http://www.podtrac.com/pts/redirect.mp3?http://downloads.cnblogs.com/netcast/mvp-on-dot-net-1-40bit.mp3">http://www.podtrac.com/pts/redirect.mp3?http://downloads.cnblogs.com/netcast/mvp-on-dot-net-1-40bit.mp3</a></p>
<p><strong>Update: </strong>本期已将采样率改为22.050kHz，使用Google Reader订阅的用户应该能够直接使用Web上的播放控件正常播放而不会出现快进的问题。如果大家在播放上还碰到什么问题了，请留言告诉我们，谢谢。</p>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1028568.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41274/" target="_blank">[新闻]瑞星将向个人用户免费1年</a>]]></description><enclosure url="http://www.podtrac.com/pts/redirect.mp3?http://downloads.cnblogs.com/netcast/mvp-on-dot-net-1-40bit.mp3" type="audio/mpeg" /></item><item><title>如何订阅MVP on dot NET（或其它播客） - iTunes版</title><link>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022275.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Tue, 01 Jan 2008 09:39:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022275.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1022275.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022275.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1022275.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1022275.html</trackback:ping><description><![CDATA[<p>如果您还不知道播客是什么，请先阅读《<a href="http:%0A//www.cnblogs.com/cathsfz/archive/2008/01/01/1022034.html">MVP 播客上线</a>》中的播客介绍部分。</p>
<p>首先，请打开iTunes。由于我是在Mac上使用iTunes，所以如果你是PC用户，您所看到的界面细节会和下面的截图略有不同。如果您还没有iTunes，但希望在iPod（包括iPhone）上收听播客，那么请先<a href="http://www.apple.com/itunes/download/">下载iTunes</a>。</p>
<p>然后请点击&#8220;高级&#8221;菜单下的&#8220;订购 Podcast...&#8221;。</p>
<p><img alt="Step 1" src="http://img.skitch.com/20080101-ct47qdxyhcrqhucm71jsm3th8p.jpg" height="335" width="513" /></p>
<p>输入MVP on dot NET的RSS地址。</p>
<p><img alt="Step 2" src="http://img.skitch.com/20080101-c3hcmuxheffcfhp962cafieha7.jpg" height="185" width="563" /></p>
<p>之后您可以在&#8220;Podcast&#8221;视图看到MVP on dot NET已被添加到列表上，并且正在更新。</p>
<p><img alt="Step 3" src="http://img.skitch.com/20080101-fssuyux7b2q6nn9i2kmna6hd4s.jpg" height="585" width="942" /></p>
<p>同时，您也可以在&#8220;下载&#8221;视图看到节目已经在下载中了。请等候下载的完成。</p>
<p><img alt="Step 4" src="http://img.skitch.com/20080101-jx939t68q29626c8bumdd8dxys.jpg" height="271" width="926" /></p>
<p>下载完成后，您可以直接返回&#8220;Podcast&#8221;视图，双击MVP on dot NET以播放节目。</p>
<p>如果您希望把节目同步到iPod（包括iPhone）上，此时请把iPod连接到电脑上，并且进入iPod对应视图，并翻到&#8220;Podcast&#8221;页。请选择同步&#8220;所有 podcast&#8221;，或在&#8220;所选 podcast&#8221;中钩选MVP on dot NET，并点击&#8220;应用&#8221;按钮以便与iTunes与您的iPod重新同步。</p>
<p><img alt="Step 5" src="http://img.skitch.com/20080101-gx62i7wnptui8fwme5r5hqqhw.jpg" height="585" width="942" /></p>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1022275.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41273/" target="_blank">[新闻]中国互联网历史上最伟大的产品TOP10（二）</a>]]></description></item><item><title>MVP on dot NET - Pilot Episode</title><link>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022112.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Tue, 01 Jan 2008 04:33:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022112.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1022112.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022112.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1022112.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1022112.html</trackback:ping><description><![CDATA[<p>主持：<a href="http://www.beanpeng.com">Bean</a>、<a href="http://jeffreyzhao.cnblogs.com">Jeffrey</a>、<a href="http://dotnet.catchen.biz">Cat</a></p>
<ol>
    <li><a href="http://mezzoblue.com/archives/2007/12/19/8_2_x2/">8 + 2 = ☺</a> - <a href="http://blogs.msdn.com/ie/archive/2007/12/19/internet-explorer-8-and-acid2-a-milestone.aspx">IE8通过了Acid2测试</a></li>
    <li><a href="http://thinkgos.com/">gOS</a>发布，日后我们仅仅使用Web也能生存下去吗？客户端过剩的CPU资源用来干什么？</li>
    <li>文档都放上线！我们用<a href="https://share.adobe.com/adc/adc.do">Adobe SHARE</a>还是<a href="http://workspace.office.live.com/">Office Live Workspace</a>？</li>
    <li>Linq to SQL、ADO.NET Entity Framewor，以及关于ORM的更多&#8230;&#8230;</li>
    <li><a href="http://www.asp.net/downloads/3.5-extensions/">ASP.NET MVC Framework</a>发布，与ASP.NET WebForm对比又如何？</li>
    <li>iPhone Web App开发 - 有点点像WPF噢！</li>
</ol>
<p>P.S.podcast订阅的图片教程稍后发布。</p>
<p>直接下载地址：<a href="http://www.podtrac.com/pts/redirect.mp3?http://downloads.cnblogs.com/netcast/mvp-on-dot-net-0-40bit.mp3">http://www.podtrac.com/pts/redirect.mp3?http://downloads.cnblogs.com/netcast/mvp-on-dot-net-0-40bit.mp3</a></p>

<img src ="http://www.cnblogs.com/cathsfz/aggbug/1022112.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41273/" target="_blank">[新闻]中国互联网历史上最伟大的产品TOP10（二）</a>]]></description><enclosure url="http://www.podtrac.com/pts/redirect.mp3?http://downloads.cnblogs.com/netcast/mvp-on-dot-net-0-40bit.mp3" type="audio/mpeg" /></item><item><title>新年新服务： MVP 播客上线</title><link>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022034.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Mon, 31 Dec 2007 19:39:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022034.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1022034.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022034.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1022034.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1022034.html</trackback:ping><description><![CDATA[<p>其实我很早就想做podcast（播客），10月份从三亚回来一直在筹备一个MVP博客，最终在前天完成了第0集（pilot episode）的录制，并将于今天稍晚时候上线。在整个过程中，我需要感谢<a href="http://dudu.cnblogs.com">dudu</a>以及博客园对podcast提供的支持与服务，感谢<a href="http://www.beanpeng.com">Bean</a>与<a href="http://jeffreyzhao.cnblogs.com">Jeffrey</a>对podcast准备工作与录制的投入。</p>
<p>首先，我介绍一下podcast为什么叫做podcast。过往，我们能够订阅feed，从而好像收取email那样收取网上的信息。例如，我订阅了ABC World New，设置了我的电脑每天早上7:00自动开机并打开feed reader下载feed，那么当我准备好早餐后，我就可以一边享受早餐，一边阅读新闻了，这和传统的喝早茶看早报没什么区别。</p>
<p>然而，ABC World New的新文章，附带了一个新闻视频片段，以龟速的下载速度，我可不能等下载完看完再去上班，因此我希望我的feed reader能够识别视频音频片段并且自动下载。RSS 2.0的&lt;enclosure /&gt;标签是第一个出来把问题解决掉的，只要把这一个feed entry相关的文件放到&lt;enclosure /&gt;链接内，feed reader就应该懂得自动去下载。之后，我把电脑自动开机时间改为早上5:00，预留两个小时，什么龟速也能把几分钟的视频片段拉下来吧。然后，我还是边喝着早茶（或者咖啡），边看新闻，不过这次不用读文字了，视频里面有人说给我听。</p>
<p>随后，iPod和iTunes又把这个应用提升到了一个全新的层次。如果你使用iTunes订阅新闻，起床后我只需要按一下同步按钮，视频音频都传到iPod上面去了，然后专心吃我的早餐，出门口时记得把iPod从同步底座上拔下来带走就是了。我在地铁或公交上有足够多的时间，把iPod拿出来看看或者听听头条新闻的时间是绝对是有的，甚至还能听听有声电子书。</p>
<p>由于这个功能在iTunes与iPod上就被命名为podcast，而且iPod在美国相当普及，所以大家就都叫podcast了。不过，Microsoft貌似避忌所有pod字开头的东西，以保持和Apple之间的距离，所以就坚持把同样的东西叫做netcast，这样显得中立一些。不过Zune2里面的功能菜单就写着podcast，看来负责整理Zune2菜单字符串资源的人有被炒鱿鱼的危险了&#8230;&#8230;另外，国内有一些名为播客的东西其实不是播客，土豆一开始就给人如此批评了——不支持RSS订阅，也不允许下载，更别说放到iPod上了，这也想带上播客的头衔？</p>
<p>好吧，对podcast的介绍到此结束，稍后MVP博客的第0集将会发布到<a href="http://netcast.cnblogs.com">netcast.cnblogs.com</a>，并且我还会另外发贴详细说明如何订阅podcast。敬请期待！</p>
<p><strong>Update: </strong>MVP on dot NET已上线，请通过<a href="http://netcast.cnblogs.com">netcast.cnblogs.com</a>访问。</p>
<p><strong>Update again: </strong>教程已发布：<a href="http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022275.html">如何订阅MVP on dot NET（或其它播客） - iTunes版</a></p>

 
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1022034.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41273/" target="_blank">[新闻]中国互联网历史上最伟大的产品TOP10（二）</a>]]></description></item><item><title>我嘅 2007</title><link>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022030.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Mon, 31 Dec 2007 18:45:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022030.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1022030.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2008/01/01/1022030.html#Feedback</comments><slash:comments>50</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1022030.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1022030.html</trackback:ping><description><![CDATA[<p>（以下的是实验性文章，全文使用Cantonese书写而成，附带Mandarin翻译，请将鼠标移至带有下划线的短语上以查看翻译。）</p>
<p><acronym title="为什么">點解</acronym><acronym title="整个">成個</acronym>博客園都<acronym title="在">喺度</acronym><acronym title="说">講</acronym>&#8220;我<acronym title="的">嘅</acronym>2007&#8221;，<acronym title="还要">仲要</acronym>大部分都<acronym title="差不多">差唔多</acronym>&#8230;&#8230;好，<acronym title="那么">咁</acronym>我就寫<acronym title="一些">啲</acronym><acronym title="不同">唔同</acronym><acronym title="一点">啲</acronym><acronym title="的">嘅</acronym><acronym title="东西">嘢</acronym>，例如<acronym title="说">話</acronym>&#8230;&#8230;人脈啦。我要<acronym title="说">話</acronym>，技術<acronym title="不是">唔係</acronym>最重要<acronym title="的">嘅</acronym>，<acronym title="也">亦</acronym>都<acronym title="不是">唔係</acronym>管理，<acronym title="而是">而係</acronym>人脈。</p>
<p>2007年，個人發展上<acronym title="的">嘅</acronym>兩個重要事件，一<acronym title="是">係</acronym><acronym title="拿到">攞咗</acronym>微軟<acronym title="的">嘅</acronym>MVP，二<acronym title="是">係</acronym>賣<acronym title="了">咗</acronym><acronym title="给">畀</acronym><acronym title="Baidu">B家</acronym>，兩樣都<acronym title="是">係</acronym>要靠人脈<acronym title="的">嘅</acronym>（要<acronym title="感謝">多謝</acronym><acronym title="的">嘅</acronym>人自然非常多）。<acronym title="也">亦</acronym>就<acronym title="是">係</acronym><acronym title="说">話</acronym>，第一<acronym title="是">係</acronym>你要認識人際網絡中充當關鍵節點<acronym title="的">嘅</acronym><acronym title="那">嗰</acronym>個人，第二<acronym title="是">係</acronym><acronym title="那">嗰</acronym>個人要<acronym title="看得起">睇得起</acronym>你。簡單<acronym title="来">嚟</acronym><acronym title="说">講</acronym>，如果你有能力，無論係技術<acronym title="还是">定係</acronym>管理，首先你要<acronym title="认识">識得</acronym>渠道（或者叫中間商），其次<acronym title="他">佢</acronym>要覺得你超值，<acronym title="那样">咁</acronym>你<acronym title="才有">先有</acronym>機會賣得出去，而且賣個好價錢。<acronym title="在">喺</acronym><acronym title="没有">冇</acronym>渠道<acronym title="的">嘅</acronym>前提下，大家都明白廠家直接向客戶銷售<acronym title="的">嘅</acronym>成本有幾高，你一個人能夠聯係<acronym title="的">嘅</acronym>買家數量就非常有限<acronym title="了">嘞</acronym>。</p>
<p>如果一開始，我<acronym title="不是">唔係</acronym><acronym title="在">喺</acronym><a href="http://dflying.cnblogs.com">Dflying</a><acronym title="以及">同埋</acronym><a href="http://jeffreyzhao.cnblogs.com">Jeffrey</a><acronym title="的">嘅</acronym>blog上評論，<acronym title="他们">佢哋</acronym><acronym title="也">亦</acronym><acronym title="不会">唔會</acronym><acronym title="来">嚟</acronym><acronym title="看">睇</acronym>我<acronym title="的">個</acronym>blog，<acronym title="也就">亦就</acronym><acronym title="不会">唔會</acronym>有<acronym title="他们">佢哋</acronym>鼓勵我將文章發到首頁，<acronym title="这样子的话">咁嘅話</acronym>，可能<a href="http://dudu.cnblogs.com">dudu</a><acronym title="也就">亦就</acronym><acronym title="不会">唔會</acronym>知道我<acronym title="的">嘅</acronym>存在，<acronym title="这样子">咁</acronym>dudu推薦我去<acronym title="拿">攞</acronym>MVP就<acronym title="不知">唔</acronym>知從何談起<acronym title="了">嘞</acronym>。所以，<acronym title="拿">攞</acronym>MVP呢件事<acronym title="是">係</acronym>一定要<acronym title="感谢">多謝</acronym>Dflying、Jeffrey<acronym title="以及">同埋</acronym>dudu<acronym title="的">嘅</acronym>。當然，<acronym title="还要">仲要</acronym>多謝所有<acronym title="的">嘅</acronym>讀者，特別<acronym title="是">係</acronym>有留言<acronym title="的">嘅</acronym><acronym title="那些">嗰啲</acronym>，因爲有留言自然激發思考。</p>
<p>然而，<acronym title="拿">攞</acronym>MVP並<acronym title="不是">唔係</acronym>終點，<acronym title="只是">只係</acronym>另一個起點<acronym title="而已">嗟</acronym>。之後，有中國<acronym title="的">嘅</acronym>MVP峰會，<a href="http://www.beanpeng.com">Bean</a>介紹我<acronym title="认识">識</acronym><acronym title="了">咗</acronym><acronym title="不少">唔少</acronym>微軟<acronym title="的">嘅</acronym>人<acronym title="以及">同埋</acronym>其他MVP，<acronym title="这样">咁</acronym><acronym title="才有">先有</acronym><acronym title="后来">后嚟</acronym><acronym title="的">嘅</acronym><acronym title="一些">一啲</acronym>合作項目，例如<acronym title="说">話</acronym>netcast啦。所以<acronym title="说">話</acronym>，認人<acronym title="才">先</acronym>有得做，因爲<acronym title="很多">好多</acronym><acronym title="东西">嘢</acronym><acronym title="是">係</acronym><acronym title="不">唔</acronym>熟<acronym title="不">唔</acronym>做<acronym title="的">嘅</acronym>。<acronym title="在这里">係呢度</acronym>，我要<acronym title="感谢">多謝</acronym>Bean、Jeffrey、dudu，特別<acronym title="是">係</acronym>dudu，完全<acronym title="不">唔</acronym>講求回報<acronym title="地">咁</acronym>支持<acronym title="我们">我哋</acronym>做netcast。</p>
<p>另外一件事，就<acronym title="是">係</acronym>關於賣身<acronym title="的了">㗎嘞</acronym>，我<acronym title="的">嘅</acronym>意思<acronym title="是">係</acronym><acronym title="找工作">搵工</acronym>。寫&#8220;我<acronym title="的">嘅</acronym>2007&#8221;<acronym title="的">嘅</acronym>人<acronym title="里面">入邊</acronym>，<acronym title="那么">咁</acronym>多人寫自己今年畢業<acronym title="找工作">搵工</acronym>如何如何，我又<acronym title="怎么">點</acronym>可以<acronym title="不">唔</acronym>寫啊。<acronym title="找实习">搵實習</acronym><acronym title="的">嘅</acronym>事就<acronym title="不">唔</acronym><acronym title="说">講</acronym><acronym title="了">嘞</acronym>，全職<acronym title="申请了">申咗</acronym>好幾間<acronym title="有一定大小的">有噃咁上吓大嘅</acronym>IT公司，包括<acronym title="Baidu, Google, and Microsoft">BGM</acronym>，其中<acronym title="Baidu">B家</acronym>同<acronym title="Google">G家</acronym>都<acronym title="找">搵</acronym>過人做推薦（<acronym title="感谢">多謝</acronym><a href="http://hi.baidu.com/pudding">布丁</a><acronym title="以及">同埋</acronym><a href="http://blog.wangjunyu.net">Junyu</a>）。<acronym title="Baidu">B家</acronym><acronym title="是">係</acronym>最早<acronym title="给">畀</acronym>offer<acronym title="的">嘅</acronym>，所以就賣<acronym title="了">咗</acronym><acronym title="给">畀</acronym><acronym title="Baidu">B家</acronym><acronym title="算了">算嘞</acronym>，<acronym title="Google">G家</acronym><acronym title="和">同</acronym><acronym title="Microsoft">M家</acronym><acronym title="的">嘅</acronym>申請算<acronym title="是">係</acronym>&#8220;無疾而終&#8221;（<acronym title="没有">冇</acronym>拒信，<acronym title="滞留在了不知道哪个">hold咗喺唔知邊個</acronym>環節<acronym title="上">度</acronym>）。<acronym title="但是">但係</acronym>，我想<acronym title="说">講</acronym><acronym title="的">嘅</acronym><acronym title="不是">唔係</acronym><acronym title="怎样">點樣</acronym><acronym title="卖给">賣畀</acronym>大公司<acronym title="咯">囉</acronym>，<acronym title="而是">而係</acronym>推薦有<acronym title="多么">幾</acronym>重要<acronym title="咯">囉</acronym>。</p>
<p>如果<acronym title="没有">冇</acronym>人推薦，你<acronym title="那份">份</acronym>簡歷<acronym title="很">好</acronym>可能石沉大海都<acronym title="没有">冇</acronym>人<acronym title="告诉你知道">話畀你知</acronym>，而且石沉大海<acronym title="的">嘅</acronym>概率<acronym title="还不怎么小">仲唔細添</acronym>。<acronym title="但是">但係</acronym>，有人推薦<acronym title="的话">嘅話</acronym>，你就<acronym title="很">好</acronym>清楚<acronym title="的">個</acronym>流程<acronym title="了">嘞</acronym>，其中每個環節對你評價如何<acronym title="也">亦</acronym>都透明<acronym title="一些">一啲</acronym>，<acronym title="那样">咁</acronym>你就可以不斷調整自己<acronym title="了">嘞</acronym>。推薦人熟悉公司内各個職位<acronym title="的">嘅</acronym>差別<acronym title="的话">嘅話</acronym>，對你選擇職位<acronym title="也有">亦有</acronym>幫助，<acronym title="好像">好似</acronym>高考選專業<acronym title="那样">咁</acronym><acronym title="完全靠猜">蠱蠱吓</acronym>就<acronym title="不好">唔好</acronym>啦。（如果你高考<acronym title="那个时候">嗰時</acronym>已經<acronym title="懂得">識得</acronym><acronym title="找">搵</acronym>師兄問清楚<acronym title="那个">個</acronym>專業<acronym title="是">係</acronym>讀<acronym title="什么">咩</acronym><acronym title="的">嘅</acronym>，<acronym title="那么">咁</acronym>你可以跳過<acronym title="这">呢</acronym>段<acronym title="了">嘞</acronym>。）</p>
<p>當然，最重要<acronym title="的是">嘅係</acronym>推薦你<acronym title="的">嘅</acronym><acronym title="那">嗰</acronym>個人<acronym title="真的是">真係</acronym>認爲你值得擁有<acronym title="这个">呢個</acronym>職位，而<acronym title="不是">唔係</acronym>應付你。<acronym title="他">佢</acronym>有<acronym title="多么">幾</acronym>積極幫你，就反映<acronym title="了">咗</acronym><acronym title="这">呢</acronym>一點，<acronym title="也">亦</acronym>影響<acronym title="着">住</acronym><acronym title="他">佢</acronym><acronym title="那份">份</acronym>推薦<acronym title="的">嘅</acronym>效力。<acronym title="不要">唔好</acronym>以爲<acronym title="他">佢</acronym>幫你<acronym title="在">喺</acronym>ERP或者HR之類<acronym title="的">嘅</acronym>系統填<acronym title="一下">吓</acronym>就<acronym title="搞掂">掂</acronym>，<acronym title="他">佢</acronym>越<acronym title="努力">落力</acronym>幫你<acronym title="做">跟</acronym><acronym title="这">呢</acronym>件事，幫你同你<acronym title="的">嘅</acronym>面試官溝通你<acronym title="的">嘅</acronym>情況，你<acronym title="的">嘅</acronym><acronym title="成功率">成數</acronym>就越大。如果你<acronym title="找到">搵到</acronym><acronym title="一个人">個人</acronym>，<acronym title="只是">只係</acronym>礙于人情而推薦你，根本<acronym title="不">唔</acronym>覺得你將來成爲<acronym title="他">佢</acronym>同事<acronym title="的话">嘅話</acronym>對<acronym title="他">佢</acronym>對<acronym title="和">同</acronym>公司都有好處，<acronym title="那么">咁</acronym>你得到<acronym title="的">嘅</acronym>好處無非<acronym title="就是">就係</acronym>免筆試，對促進你<acronym title="和">同</acronym>公司之間<acronym title="的">嘅</acronym>互相了解<acronym title="一点">一啲</acronym>作用都<acronym title="没有">冇</acronym>。</p>
<p>免筆試&#8230;&#8230;免筆試又有<acronym title="什么">咩</acronym>用呢？其實筆試過後離offer<acronym title="还有">仲有</acronym>十萬八千里<acronym title="那么">咁</acronym>遠。聼講<acronym title="Google">G家</acronym><acronym title="在">喺</acronym>美國本來就<acronym title="没有">冇</acronym>筆試，<acronym title="只是">只係</acronym>中國應屆畢業生實在太多<acronym title="了">嘞</acronym>，<acronym title="那么">咁</acronym>就筆一筆，篩一篩。有時甚至<acronym title="也">亦</acronym>就<acronym title="不">唔</acronym>筆嘞，<acronym title="那样">咁樣</acronym>推薦<acronym title="不">唔</acronym>推薦<acronym title="都是">都係</acronym>一面起步，你希望你<acronym title="的">嘅</acronym>優勢更好<acronym title="地">咁</acronym>傳達<acronym title="给">畀</acronym>面試官<acronym title="知道">知</acronym><acronym title="的话">嘅話</acronym>，<acronym title="除了">除咗</acronym>面試<acronym title="的">嘅</acronym>時候表現要好<acronym title="一些">啲</acronym>，就靠推薦人<acronym title="的">嘅</acronym>溝通<acronym title="了">嘞</acronym>。</p>
<p>最後，通過一個故事結束本文。曾經，Mary<acronym title="总是">總係</acronym><acronym title="很有">好有</acronym>激情<acronym title="地">咁</acronym><acronym title="和别人">同人</acronym><acronym title="说">講</acronym><acronym title="她">佢</acronym><acronym title="的">個</acronym><acronym title="儿子">仔</acronym><acronym title="以及">同埋</acronym><acronym title="她">佢</acronym><acronym title="的">個</acronym><acronym title="儿子">仔</acronym><acronym title="那间">間</acronym>新公司，其中一個聽衆<acronym title="就是">就係</acronym>Unity Way<acronym title="的">嘅</acronym>董事會成員：John Opel。五年之後，John Opel，<acronym title="也就是">亦就係</acronym>IBM<acronym title="的">嘅</acronym>董事長，要為IBM<acronym title="的">嘅</acronym>機器<acronym title="找">搵</acronym>一個操作系統。<acronym title="他">佢</acronym>去<acronym title="了">咗</acronym><acronym title="哪里">邊度</acronym><acronym title="找">搵</acronym>？去<acronym title="了">咗</acronym>Washington<acronym title="的">嘅</acronym>Redmond會見Mary<acronym title="的">個</acronym><acronym title="儿子">仔</acronym>，<acronym title="也就是">即係</acronym>Bill Gates。<acronym title="感谢">多謝</acronym><acronym title="和">同埋</acronym>IBM<acronym title="那">嗰</acronym>單生意，Bill Gates做<acronym title="了">咗</acronym>首富。如果John Opel<acronym title="从来">從嚟</acronym><acronym title="没有">未</acronym><acronym title="听说">聽講</acronym>過<acronym title="他">佢</acronym><acronym title="的">個</acronym><acronym title="名字">名</acronym><acronym title="的话">嘅話</acronym>，IBM絕對<acronym title="不會">唔會</acronym>派人去Redmond<acronym title="看">睇</acronym>一間當時幾乎<acronym title="和">同</acronym>Microsoft一樣默默無聞<acronym title="的">嘅</acronym>公司。</p>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1022030.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41273/" target="_blank">[新闻]中国互联网历史上最伟大的产品TOP10（二）</a>]]></description></item><item><title>编写 iPhone Friendly 的 Web 应用程序 (Part 5 - 交互入门)</title><link>http://www.cnblogs.com/cathsfz/archive/2007/12/29/1019883.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Sat, 29 Dec 2007 05:41:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2007/12/29/1019883.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1019883.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2007/12/29/1019883.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1019883.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1019883.html</trackback:ping><description><![CDATA[<p>我们已经研究过XHTML和CSS了，现在开始看看最后一部分，也就是JavaScript，以及它所提供的交互能力。</p>
<h3>无AJAX交互</h3>
<p>第一种我们要看的交互，是完全不使用JavaScript，这其中一个例子就是GMail。GMail的iPhone版其实就是由普通的<a href="https://m.gmail.com">GMail移动版</a>修改过来的，界面上更贴近桌面版GMail了，然而交互性并没有怎么提高，每一个点击都对应一次刷新，没有任何AJAX可言。</p>
<p>事实上，不用任何AJAX效果并不会让你的iPhone Web App低人一等，如果有人讥笑你的应用没有引入任何AJAX功能，你可以直接跟他说&#8220;GMail也没有&#8221;。因此，如果你在开发的过程中决定不把任何时间投入到AJAX相关技术的研究，这是没问题的，确保你的服务器响应速度，并且交互设计得当，那就行了。</p>
<h3>以服务器端为中心的AJAX</h3>
<p>接下来我们看看另外一些应用，例如之前说到的几个，就拿最简单的AppMarks来说说吧。首先，使用User Agent Switch更改你的Firefox的user-agent属性，伪装为iPhone，然后打开AppMarks，并且打开Firebug。接着点Menu -&gt; Add -&gt; Browse，看到出现AJAX请求了吧？猜猜这个请求是什么类型的，面向内容（传输更新上去的XHTML）、面向脚本（传输进行更新操作的JavaScript）还是面向数据（传输更新相关的JSON）？答案是——面向内容的！</p>
<p>这可是Web App哦，不是一般带有一点点AJAX的网页哦，我们要MVC，我们要&#8220;先进&#8221;的面向数据，为什么要&#8220;落后&#8221;的面向内容呢？至今为止，我们能够看到的大部分iPhone Web Apps，都将MVC保留在服务器端了，客户端唯一需要知道的就是内容更新，不存在任何的客户端MVC模型。暂时我还没看到有面向脚本或者面向数据的，如果你见到有应用这样做了，请告诉我。</p>
<p>我们继续说MVC的事情。现在大多应用的设计方式是这样的：每一个应拥有一个view framework，然后每一次点击所作的操作就是切换view。例如刚才说到的AppMarks，从Menu进入Add是一个view切换，不过因为Add这个view的内容是固定的，因此一早就包含在页面里，不用AJAX请求直接加载就行了。另外一种情况，就是好像加载Browse那样，是需要AJAX把view请求过来才能加载的。除了切换view，我们还需要action，例如提交数据就一定需要action的。说到这里，感觉是不是和RoR或者类似框架扯上关系了？事实上，RoR，或者类似框架，确实很适合用来做iPhone Web Apps。</p>
<h3>以客户端为中心的AJAX</h3>
<p>那么除了RoR，我们还有别的选择吗？我们可以选择使用一些客户端框架来实现类似的效果。这样说吧，类似RoR那样每一个view都是一个模板，但不是rhtml，而是普通的html，没有复杂逻辑，点击连接后不是由RoR引擎调在服务器端用rhtml，而是客户端自己直接拦截了链接点击并用AJAX的方法去请求该html然后更新内容。这样一个框架，可以在Wrox的<a href="http://www.wrox.com/WileyCDA/WroxTitle/productCd-0470251557.html">Professional iPhone and iPod touch Programming : Building Applications for Mobile Safari</a>一书中见到。这本书写着2008年1月出版，但实际上已经出版，并且可以下载源代码。我暂时还没办法买到这本书，但源代码中就包括了这样一个客户端框架。</p>
<p>然而，这种以客户端为中心的做法并没有真正在客户端引入一个MVC，它只是简单地把服务器端的MVC裁减掉了，服务器端只能简单的发送内容或响应提交，因此只适用于比上面的以服务器端为中心的模型更简单的情景。如果你正在编写的应用不涉及大量的提交操作，或者根本就是Web1.0网站，我的意思是，单向传递信息不接受任何用户提交的网站，那么这种轻量级的模型就非常适用了。</p>
<h3>小结</h3>
<p>在这次的文章里，我们介绍了三种常见的iPhone Web Apps交互方案，没有哪一个是绝对更好或者更坏的，按照你当前开发的应用做出选择吧。将来我们写文章深入探讨其中的一些实现细节，或者是交互模式，但前提是我先完成了几个iPhone Web Apps。欢迎订阅本系列文章：</p>
<ul>
    <li><a href="http://chinese.catchen.biz">Cat in Chinese</a> (<a href="http://feeds.feedburner.com/catchen/chinese">feed</a>)  </li>
    <li><a href="http://dotnet.catchen.biz">Cat in dotNET</a> (<a href="http://feeds.feedburner.com/catchen/dotnet">feed</a>)</li>
</ul>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1019883.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41271/" target="_blank">[新闻]盖茨官方否认天价租楼看奥运 纯属地产商炒作</a>]]></description></item><item><title>编写 iPhone Friendly 的 Web 应用程序 (Part 4 - CSS)</title><link>http://www.cnblogs.com/cathsfz/archive/2007/12/27/1016979.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Thu, 27 Dec 2007 06:54:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2007/12/27/1016979.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1016979.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2007/12/27/1016979.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1016979.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1016979.html</trackback:ping><description><![CDATA[<p>说到编写CSS，大家的第一反应肯定是——有没有选择性CSS。有！我们可以设计一个CSS，使得只有iPhone上的Safari会采用它，其他浏览器都会无视它，这样我们就可能可以复用现有的XHTML页面代码，仅仅为它们引入新的CSS就能够适用于iPhone，无须重新编写页面。这个选择性CSS链接语句如下：</p>
<blockquote>
<p><strong>&lt;link media="only screen and (max-device-width: 480px)" href="small-device.css" type= "text/css" rel="stylesheet" /&gt;</strong></p>
</blockquote>
<p>Safari是支持media选择的，only screen声明该CSS仅用于屏幕显示（不用于打印），同时Safari还支持<strong>max-device-width</strong>这样的选项，限定屏幕宽度小于480的设备才采用该样式表，这就把iPhone与桌面浏览器划分开来了。</p>
<p>另一个做法是在服务器端就判断当前浏览器是否是iPhone上的Safari，从而选择返回哪个CSS文件，这可以通过<strong>user-agent</strong>进行判断，iPhone的如下：</p>
<blockquote>
<p><strong>Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543 Safari/419.3</strong></p>
</blockquote>
<p>判断了浏览器之后，就可以开始针对Safari编写CSS了。Safari比较爽的一点是对CSS3的支持，设计PC端网页时总是要兼顾那个&#8220;后进&#8221;的IE，从而避免使用CSS3，或者需要确保IE在无视CSS3规则后仍然正确显示，现在不用为此而头痛啦，只要是Safari支持的就能用，针对一个浏览器设计就是比针对一堆浏览器设计要爽！</p>
<h3>CSS3</h3>
<p>接下来我们就列举一下Safari支持的CSS3属性吧：</p>
<h4>边框</h4>
<ul>
    <li><a href="http://www.css3.info/preview/border-image/">-webkit-border-image</a> - 让边框支持图片（iPhone上支持存在bug）  </li>
    <li><a href="http://www.css3.info/preview/rounded-border/">-webkit-border-radius</a> - 让边框支持远角  </li>
    <li><a href="http://www.css3.info/preview/box-shadow/">-webkit-box-shadow</a> - 让盒区域支持阴影（iPhone上不支持）</li>
</ul>
<h4>背景</h4>
<ul>
    <li><a href="http://www.css3.info/preview/background-origin-and-background-clip/">-webkit-background-origin / -webkit-background-clip</a> - 控制背景的定位与剪裁  </li>
    <li><a href="http://www.css3.info/preview/background-size/">-webkit-background-size</a> - 控制背景的大小  </li>
    <li><a href="http://www.css3.info/preview/multiple-backgrounds/">background</a> - 多背景，如同单背景一样定义一个背景图片，多个图片定义之间用逗号分隔（未经测试）</li>
</ul>
<h4>色彩</h4>
<ul>
    <li><a href="http://www.css3.info/preview/hsl/">HSL</a> - HSL色彩  </li>
    <li><a href="http://www.css3.info/preview/hsla/">HSLA</a> - 带Alpha通道的HSL色彩  </li>
    <li><a href="http://www.css3.info/preview/opacity/">opacity</a> - 透明度  </li>
    <li><a href="http://www.css3.info/preview/rgba/">RGBA</a> - 带Alpha通道的RGB色彩</li>
</ul>
<h4>文本特效</h4>
<ul>
    <li><a href="http://www.css3.info/preview/text-shadow/">text-shadow</a> - 让文本支持阴影  </li>
    <li><a href="http://www.css3.info/preview/text-overflow/">text-overflow</a> - 控制文本溢出时的裁剪与视觉反馈  </li>
    <li><a href="http://www.css3.info/preview/word-wrap/">word-wrap</a> - 控制长单词换行</li>
</ul>
<h4>用户界面</h4>
<ul>
    <li><a href="http://www.css3.info/preview/box-sizing/">-webkit-box-sizing</a> - 可以让盒模型变得基于边框而非内容  </li>
    <li><a href="http://www.css3.info/preview/resize/">resize</a> - 让用户可以更改盒的大小（iPhone上不支持）  </li>
    <li><a href="http://www.css3.info/preview/outline/">outline</a> - 设置盒的外边框</li>
</ul>
<h4>选择器</h4>
<p>Safari支持大部分的CSS3选择器，你可以自己使用桌面端或iPhone上的Safari打开<a href="http://www.css3.info/selectors-test/">CSS Selectors Test</a>进行测试，桌面端与iPhone上的Safari测试结果是一致的。Safari完全通过测试的CSS3选择器包括：</p>
<blockquote>
<p><strong>*</strong>, <strong>E</strong>, <strong>.class</strong>, <strong>#id</strong>, <strong>E F</strong>, <strong>E &gt; F</strong>, <strong>E + F</strong>, <strong>E[attribute]</strong>, <strong>:link</strong>, <strong>:visited</strong>, <strong>:before</strong>, <strong>::before</strong>, <strong>:after</strong>, <strong>::after</strong>, <strong>:first-letter</strong>, <strong>::first-letter</strong>, <strong>:first-line</strong>, <strong>::first-line</strong>, <strong>E - F</strong>, <strong>:root</strong>, <strong>:not()</strong>, <strong>:target</strong>, <strong>:enabled</strong>, <strong>:disabled</strong>, <strong>:checked</strong></p>
</blockquote>
<h4>其它</h4>
<ul>
    <li><a href="http://www.css3.info/preview/media-queries/">media</a> - 根据media选择性加载CSS  </li>
    <li><a href="http://www.css3.info/preview/multi-column-layout/">multi-column</a> - 内容分栏支持（iPhone上不支持）</li>
</ul>
<p>还有一些Safari自己做的CSS扩展没有列举出来。Safari完整的CSS属性支持列表请看这里：<a href="http://developer.apple.com/documentation/AppleApplications/Reference/SafariCSSRef/Articles/StandardCSSProperties.html">Supported CSS Properties</a>。</p>
<h3>表单</h3>
<p>Safari支持对&lt;input /&gt;元素比较高自由度的CSS定义，例如这样的：</p>
<p><img src="http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/Art/customcheckboxes.jpg" alt="" /> <img src="http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/Art/customselect.jpg" alt="" /> </p>
<p>实现所需的CSS属性上面已经列举了，所以不再详细说明，灵活运用就是了。值得注意的是，某些&lt;input /&gt;的默认背景并非纯白色的，而是半透明的，这使得这些元素能够更好地和不同的背景颜色进行颜色混合。为了说明这一点，请先看白色背景下的示例：</p>
<p><img src="http://developer.apple.com/documentation/iPhone/Conceptual/iPhoneHIG/art/defaultcontrols.jpg" alt="" /> </p>
<p>然后再看看蓝色背景下的：</p>
<p><img src="http://developer.apple.com/documentation/iPhone/Conceptual/iPhoneHIG/art/controlsonbluebackground.jpg" alt="" /> </p>
<h3>小结</h3>
<p>CSS相关的话题也说完了，很简单是不是？大部分针对桌面浏览器进行符合Web Standards页面设计的设计师都能轻易掌握这部分内容，然而这只是实现设计的手段，到底如何设计一个界面，在iPhone上才算是拥有高度易用性的，这才是真正的问题。这个问题我们将在以后探讨，至少现在你能够将你自己的设计在iPhone上准确无误的实现出来了，那么我们下一步就进入JavaScript的讨论环节了。</p>
<p>本iPhone Friendly专题的订阅地址如下：</p>
<ul>
    <li><a href="http://chinese.catchen.biz">Cat in Chinese</a> (<a href="http://feeds.feedburner.com/catchen/chinese">feed</a>)  </li>
    <li><a href="http://dotnet.catchen.biz">Cat in dotNET</a> (<a href="http://feeds.feedburner.com/catchen/dotnet">feed</a>) </li>
</ul>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1016979.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41270/" target="_blank">[新闻]2008年7月24日IT博客精选</a>]]></description></item><item><title>编写 iPhone Friendly 的 Web 应用程序 (Part 3 - XHTML)</title><link>http://www.cnblogs.com/cathsfz/archive/2007/12/27/1016772.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Thu, 27 Dec 2007 05:11:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2007/12/27/1016772.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1016772.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2007/12/27/1016772.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1016772.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1016772.html</trackback:ping><description><![CDATA[<p>在接下来的两篇文章中，我们将探讨iPhone上的Safari所支持的XHTML与CSS，之后才进入JavaScript的讨论。作为一款现代化的浏览器，Safari当然是基于标准的，那就让我们看看Safari支持哪些标准吧：</p> <ul> <li>HTML 4.01  <li>XHTML 1.0  <li>CSS 2.1 以及部分 CSS 3  <li>JavaScript (ES3)  <li>DOM (Level 2)  <li>AJAX (XMLHttpRequest) </li></ul> <p>熟悉这些标准并且平常也坚持Web Standards实践的朋友估计要笑出来了——就这些吗？我们天天在用啊，还有必要专门写文章来说明吗？事实上，Safari之前作为一款无PC版的浏览器，一直用户数量就不高，因此对它的研究也就不多，然而Safari其实有不少自己的扩展，因此还是很值得研究的。既然我们是针对iPhone设置，其实就是针对Safari设计，无需考虑兼容其它浏览器，这时候为什么不好好利用这些扩展增强自己的应用程序的可用性呢？</p> <p>好吧，不说废话了，进入Safari对XHTML支持的介绍吧！</p> <h3>链接</h3> <p>iPhone对一下这样一些链接有特殊支持：</p> <h4>邮件</h4> <p>传统的<strong>mailto:</strong>地址iPhone将能自动使用内含的邮件程序处理，直接进入编写邮件的界面。完整的<strong>mailto:</strong>格式请参考<a href="http://www.ietf.org/rfc/rfc2368.txt">RFC 2368</a>。</p> <h4>电话</h4> <p>iPhone上的Safari会自动对看起来像是电话号码的数字串（包括已经加入连字符或括号格式化过的）添加电话链接，点击之后会询问用户是否想要拨打该号码。如果你不希望开启这个自动识别，可以将它关闭：</p> <blockquote> <p><strong>&lt;meta name="format-detection" content="telephone=no" /&gt;</strong></p></blockquote> <p>如果你关闭自动识别后，又希望某些电话号码能够链接到iPhone的拨号功能，那么可以通过这样来声明电话链接：</p> <blockquote> <p><strong>&lt;a href="tel:13800138000"&gt;13800138000&lt;/a&gt;</strong></p></blockquote> <h4>Google Maps</h4> <p>Google Maps的地图链接会自动调用内置的Google Maps客户端软件打开，而非在浏览器内浏览。链接可以是一个地点查询：</p> <blockquote> <p><strong>&lt;a href="</strong><strong>http://maps.google.com/maps?q=cupertino"</strong><strong>&gt;Cupertino&lt;/a&gt;</strong></p></blockquote> <p>也可以是一个路线查询：</p> <blockquote> <p><strong>&lt;a href="</strong><strong>http://maps.google.com/maps?daddr=San+Francisco,+CA&amp;saddr=cupertino"</strong><strong>&gt;Directions&lt;/a&gt;</strong></p></blockquote> <h4>YouTube</h4> <p>如果链接是指向YouTube视频地址的，将会自动调用内置的YouTube客户端打开播放。能够识别的YouTube地址格式为：</p> <blockquote> <p><strong>http://www.youtube.com/watch?v=&lt;video identifier&gt;</strong> </p> <p><strong>http://www.youtube.com/v/&lt;video identifier&gt;</strong></p></blockquote> <p>其中<strong>&lt;video identifier&gt;</strong>替换为视频的id。</p> <h3>图片</h3> <p>由于用户浏览时有可能使用Wi-Fi，也有可能使用EDGE(GPRS)，因此你必须优化你的图片以确保即使是在使用EDGE访问你的网站的用户也能流畅的打开页面。因此你必须优化页面上的图片，尽量减少它们占用的传输带宽。另外Safari本身还对图片有如下的限制：</p> <ul> <li>GIF（包括GIF动画）、PNG与TIFF解压后的体积小于2m。意思是，原图的长度乘以宽度再乘以每一个像素的位数，得出来的大小要小于2m。  <li>JPEG解压后最大的体积是32m。解压体积大于2m的JPG会被进行二次抽样，最终显示给用户的是二次抽样后的结果。这使得Safari能够显示数码相机直接拍摄出来的照片，但显示时实际上是降低了精度的，以提高程序的执行效率。 </li></ul> <p>为了尽量提高效率，例如你要将100*100的图片显示为10*10，就要在服务器端执行压缩操作，而不要直接用10*10的<strong>&lt;img /&gt;</strong>来引用100*100的原始图片。</p> <h3>表单</h3> <h4>text, password, textarea</h4> <p>在设计文本框的时候，必须记住用户点击后会出现软键盘，这时候可视区域就减少了：</p> <p><img alt="" src="http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/Art/layout_forms_appropriate.jpg"></p> <p>另外在文本框中输入时，iPhone提供了自动大写与自动更正两项功能。自动大写的意思是，在输入开始的时候，以及在一个句号并空一个格后，自动会启用shift，输入一个字母后该shift自动消失。自动修正的意思是，iPhone会自动根据词库，包括自带的以及从你过往输入分析而来的，来对你的输入进行自动更正。我们都知道用手指点击那么小一个软键盘很容易误按旁边的键，这时候你可以不用忙于修正，只要iPhone提示的自动修正的词正是你想要的，你就可以按空格然后输入下一个词，iPhone会自动修正前面那个词。</p> <p>要关闭这两项功能，可以通过<strong>autocapitalize</strong>与<strong>autocorrect</strong>这两个选项：</p> <blockquote> <p><strong>&lt;input type="text" autocapitalize="off" autocorrect="off" /&gt;</strong></p></blockquote> <h4>select</h4> <p>必须留意到的是，iPhone上的<strong>&lt;select /&gt;</strong>以不同的方式显示，以便于用户操作：</p> <p><img alt="" src="http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/Art/custom_select_implement.jpg"> </p> <h4>upload</h4> <p>iPhone不支持任何的文件上传下载，因此<strong>&lt;input type="upload" /&gt;</strong>总是会显示出来，并且是……disabled的！</p> <h3>多媒体内容</h3> <p>iPhone上支持显示的多媒体内容，除了图片还包括QuickTime音频视频以及PDF。</p> <p>如果需要创建视频，可以使用QuickTime Pro。如果你正在使用一台MacBook或者iMac，并且已经将QuickTime升级为QuickTime Pro，可以马上就试一试！你需要做的就是打开QuickTime Pro，然后开始录像，（接着请对着镜头傻笑3秒，或者做点别的），最后选择"Export for Web"。其中iPhone格式与iPhone (cellular)格式分别适用于Wi-Fi与EDGE环境，iPhone在播放时会自动根据当前的环境选择适合的流媒体文件进行下载与播放，另外poster是指影片播放之前在页面上显示的那一帧静态图片。导出后文件夹里ReadMe.html说明了如何将这些文件添加到XHTML中。</p> <p>（事实上，导出结果中QuickTime控件引用的那个mov文件不包含任何视频数据，它只是一个引用，类似我们编程时所说的引用，用于指向真正的视频文件。不过这个引用指向的是多个视频文件，客户端根据当前的状态自动选择正确的视频文件来播放。）</p> <h3>其他琐事</h3> <p>虽然说是琐事，但也必须注意到，这样才能让你的页面更好地受到Safari的支持。这包括：</p> <ul> <li>声明正确的doctype  <li>避免使用frameset  <li>每一个独立的资源文件，HTML、CSS、JavaScript、以及非流媒体的其他多媒体文件，限制在10m之内  <li>顶级入口的JavaScript执行时间限制为5秒，超时将自动终止。  <li>JavaScript分配内存上限为10m。  <li>同一时间最多在Safari内打开8个子窗口（同时浏览的页面）。 </li></ul> <h3>小结</h3> <p>XHTML部分到这里就讲完了，可以看出iPhone对XHTML的支持与桌面端的Safari是类似的，只是加入了更多扩展功能而已。下一期将开始讲CSS，欢迎订阅：</p> <ul> <li><a href="http://chinese.catchen.biz">Cat in Chinese</a> (<a href="http://feeds.feedburner.com/catchen/chinese">feed</a>)  <li><a href="http://dotnet.catchen.biz">Cat in dotNET</a> (<a href="http://feeds.feedburner.com/catchen/dotnet">feed</a>) </li></ul><img src ="http://www.cnblogs.com/cathsfz/aggbug/1016772.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41270/" target="_blank">[新闻]2008年7月24日IT博客精选</a>]]></description></item><item><title>编写 iPhone Friendly 的 Web 应用程序 (Part 2 - Viewport)</title><link>http://www.cnblogs.com/cathsfz/archive/2007/12/26/1015867.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Wed, 26 Dec 2007 09:48:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2007/12/26/1015867.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1015867.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2007/12/26/1015867.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1015867.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1015867.html</trackback:ping><description><![CDATA[<p>在了解到iPhone的一些常见布局法后，我们就可以开始着手编写一个真正能在iPhone上跑的页面了。小声说一句，之前我说要布局讨论完了，要进入交互逻辑开发，后来细心一想发现不行，有些东西不讲的话将会对布局带来问题，绕过去的话并不怎么优雅，因此继续讲布局。</p>
<p>首先要说的就是viewport，也就是可视区域。对于桌面浏览器，我们都很清楚viewport是什么，就是出去了所有工具栏、状态栏、滚动条等等之后用于看网页的区域，这是真正有效的区域。（无论你屏幕多大，如果你装足够多的toolbar，你的viewport最终也会消失掉。）在桌面浏览器中，viewport的大小是与浏览器窗口大小直接相关的，窗口大了viewport自然就大，同时随着viewport的改变，页面布局可能也跟着变。例如<strong>width: 100%</strong>的页面宽度就总是和viewport宽度一致。</p>
<p><img src="http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/Art/viewportondesktop.jpg" alt="" /> </p>
<p>然而iPhone的Safari不是这样理解viewport的，它基于viewport呈现页面，然后用户缩放页面后viewport保持不变，仅仅是页面内容按比例缩放了。举个例子，在不设置viewport的情况下，默认viewport为宽度980（单位是像素），这时候页面的呈现出来的布局和在桌面短viewport宽度为980时呈现的结果一致，然而因为iPhone屏幕宽度为320，因此按比例缩小了。因此，一张宽度为320的图片，在默认viewport下会这样显示：</p>
<p><img src="http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/Art/vp980notspecified.jpg" alt="" /> </p>
<p>可以看到，图片按比例缩小了，这对于传统Web页面直接在iPhone上面显示来说是很好的事情，因为如果传统Web页面在980宽度的桌面浏览器viewport中显示正常的话，iPhone上显示也绝对正常。然而这对于Web应用程序来说则不是好事，因为我们需要按照980宽度来设计将来会以320宽度显示的页面，一个应该显示为320*80的元素，必须设计为980*245，这多麻烦！</p>
<p>因此我们需要改变viewport，让它变成这样：</p>
<p><img src="http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/Art/vp320width.jpg" alt="" /> </p>
<p>实际上应该怎么做呢？我们有几个选择，因此先让我们看看到底我们能够设置哪些属性吧。我们可以操作的属性有4个：</p>
<ul>
    <li><strong>width</strong> - viewport的宽度  </li>
    <li><strong>height</strong> - viewport的高度  </li>
    <li><strong>initial-scale</strong> - 初始的缩放比例  </li>
    <li><strong>minimum-scale</strong> - 允许用户缩放到的最小比例  </li>
    <li><strong>maximum-scale</strong> - 允许用户缩放到的最大比例  </li>
    <li><strong>user-scalable</strong> - 用户是否可以手动缩放</li>
</ul>
<p>这6个属性，我们可以设置其中的一个或者多个，iPhone会根据你设置的属性自动推算其他属性值，而非直接采用默认值。这点很重要，在完全不设置的时候有默认viewport，在你设置一个属性后其它值是自动推算出来的，不再是默认的。</p>
<p>如果你把<strong>initial-scale=1</strong>，那么<strong>width</strong>和<strong>height</strong>在竖屏时自动为320*356（不是320*480因为地址栏等都占据空间），横屏时自动为480*208。</p>
<p><img src="http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/Art/textat980withinitialscale1_0.jpg" alt="" /> </p>
<p>类似地，如果你仅仅设置了<strong>width</strong>，就会自动推算出<strong>initial</strong>-<strong>scale</strong>以及<strong>height</strong>。例如你设置了<strong>width=320</strong>，竖屏时<strong>initial-scale</strong>就是1，横屏时则变成1.5了。</p>
<p><img src="http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/Art/textat980withwidth320.jpg" alt="" /> </p>
<p>那么到底这些设置如何让Safari知道？其实很简单，就一个meta，形如：</p>
<blockquote><strong>&lt;meta id="viewport" name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/&gt;</strong></blockquote>
<p>在设置了<strong>initial-scale=1</strong>之后，我们终于可以以1:1的比例进行页面设计了。下一步我们就可以正式进入页面布局的细节设计了，如果你想继续关注iPhone开发话题的话，欢迎订阅：</p>
<ul>
    <li><a href="http://chinese.catchen.biz">Cat in Chinese</a> (<a href="http://feeds.feedburner.com/catchen/chinese">feed</a>)  </li>
    <li><a href="http://dotnet.catchen.biz">Cat in dotNET</a> (<a href="http://feeds.feedburner.com/catchen/dotnet">feed</a>) </li>
</ul>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1015867.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41269/" target="_blank">[新闻]TOM在线与Joost正式组建合资公司</a>]]></description></item><item><title>编写 iPhone Friendly 的 Web 应用程序 (Part 1 - 布局入门)</title><link>http://www.cnblogs.com/cathsfz/archive/2007/12/25/1014698.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Tue, 25 Dec 2007 13:47:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2007/12/25/1014698.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1014698.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2007/12/25/1014698.html#Feedback</comments><slash:comments>18</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1014698.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1014698.html</trackback:ping><description><![CDATA[<p>用过iPhone的朋友应该知道，iPhone上面的一些应用程序是能够随机器转动自动适应的，也就是说竖着拿的时候就竖着显示，横着拿的话就横着显示，iPhone中至关重要的Safari浏览器当然也支持这一点了，因此我们考虑设计iPhone friendly的应用程序时，首先要考虑兼容这种情况，不能把页面定死在一个宽度上。且慢，我们不是说设计自己的应用程序吗？这和内置的Safari有何关系？iPhone被设计为不允许安装任何第三方应用程序（破解不在讨论范围之内），一切第三方应用程序必须以Web的形式来跑，小到一个国际象棋的游戏也如此，因此我们现在说的应用程序就是指Web，但是与传统意义上以提供信息为核心的Web又不同，我们所说的是以提供交互操作为主的应用。</p>
<p>好吧，在我们正是进入布局的讨论之前，先来赏析一下已有的iPhone应用：</p>
<h3><a href="http://iphone.facebook.com">Facebook iPhone Edition</a></h3>
<p>Facebook的iPhone版。如果你已经习惯了在iPhone上使用过Facebook，第一次在PC上浏览这个页面会被它的&#8220;肥大&#8221;吓坏的。从这个页面我们能够得知，让页面自动适应iPhone屏幕的方法就是尽量使用百分比来定义宽度，特别是全页宽度一律用100%，如果是导航栏里面4个项目并排的就每个25%。</p>
<h3><a href="http://appmarks.com">AppMarks</a></h3>
<p>AppMarks可以说是一个应用程序的书签，当然也有人把它作为Safari的首页，那就相当于桌面了，因为你收藏的应用程序就在这个页面直接显示，以大图标的方式。AppMarks以前是可以直接在PC上浏览的，现在已经自动将非iPhone的请求重定向到介绍页了，不过这里有一个<a href="http://appmarks.com/main/?q=node/10">AppMarks Demo</a>能在PC上看看。我们能够看得到图片是4个一行地排列的，共12个，然而横屏会怎样了？当然是变成6个一行，仍然能够在一屏内显示完，并且不会有不满行的图标。其实这是一个很tricky的做法，12是4和6的公倍数，因此虽然竖屏和横屏的显示方式不一样，但你不会觉得有什么缺陷。</p>
<h3><a href="http://m.newsgator.com/iphone.aspx">Newsgator Mobile iPhone Edition</a></h3>
<p>终于有一个ASP.NET写的iPhone应用了，其实和上面的Facebook看起来差不多，同样采用了宽度为100%的做法，同时页面上的元素要么向左对齐要么向右对齐。这听起来很废话，其实意思是，中间尽管留空，不要想把整个宽度为100%的块区都利用起来，说明性文字可以放左边，操作及视觉反馈放右边，这样无论屏幕怎么旋转都好看。如果中间塞满了内容，只会让Safari进行比例缩放操作，把页面整个缩小，这其实是不利于操作的。</p>
<h3><a href="https://mail.google.com/mail">GMail</a></h3>
<p>这不是普通的GMail吗？怎样才能看到iPhone版？这就需要通过修改user-agent属性欺骗它了。iPhone上的Safari所用的user-agent如下所示：</p>
<blockquote>
<p><strong>Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3</strong></p>
</blockquote>
<p>使用Firefox的<a href="https://addons.mozilla.org/firefox/addon/59">User Agent Switcher</a>修改一下user-agent就行了，然后你就能看到iPhone上看到的GMail了。仍然和上面的网站一样，可点击区域是一大个宽度为100%的块区。</p>
<h3>小结</h3>
<p>实际上，设计iPhone friendly的界面，在CSS的层面上来说一点也不难，甚至可以说是非常简单，因为基本上就是宽度为100%的块区，少数时候要用到按百分比划分的块区，但实际上我们也应该避免这种情况。为什么呢？别忘记了，iPhone的用户是没有鼠标的，他们必须通过手指来操作页面上的一切，因此可点击区域必须尽量大。</p>
<p>既然他们看不到鼠标指针，你也就不用考虑可点击区域必须是链接或者<strong>cursor: pointer</strong>，因为用户无法通过鼠标指针的改变来判断一个区域是否能点击。然而这同时也就引入了另一个问题，如何让用户了解一个区域能否点击呢？这时候你必须给出明确的视觉暗示，例如看起来是链接的文本，蓝色的文本有无下划线通常都挺诱惑人去点，这方面Facebook是一个例子。另一种做法是让界面看起来是菜单式的，好像AppsMarker和Newsgator那样，菜单右侧的符号让人挺熟悉不是吗？只要我点击这个菜单项，就会展开下一级菜单。最后一种做法就是基于用户已经熟悉的独创暗示来提示用户，习惯使用GMail的用户一看到邮件标题那个大大的蓝色区域，就知道点击是打开邮件，这是不需要任何指引的，最坏的情况下，用户不知道点击什么还是会点击邮件标题，之后他也就会用了。</p>
<p>到此为止，就已经把设计iPhone friendly应用界面的一些布局因素解释清楚了，我们下一步就要进入交互的环节，让我们的应用程序真正执行起来，并且是在客户端JavaScript环境中执行起来。如果你想继续关注本话题的话，欢迎订阅：</p>
<ul>
    <li><a href="http://chinese.catchen.biz">Cat in Chinese</a> (<a href="http://feeds.feedburner.com/catchen/chinese">feed</a>)  </li>
    <li><a href="http://dotnet.catchen.biz">Cat in dotNET</a> (<a href="http://feeds.feedburner.com/catchen/dotnet">feed</a>) </li>
</ul>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1014698.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41268/" target="_blank">[新闻]财富:谷歌副总裁称其新闻搜索值1亿美元</a>]]></description></item><item><title>使用 fluid layout 时记得设置 min-width</title><link>http://www.cnblogs.com/cathsfz/archive/2007/12/21/1009244.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Fri, 21 Dec 2007 07:35:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2007/12/21/1009244.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/1009244.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2007/12/21/1009244.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/1009244.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/1009244.html</trackback:ping><description><![CDATA[<p>希望<a href="http://www.awflasher.com/blog/">aw</a>不介意我拿他的blog来做例子，因为第一次想到这个问题是我在手机上看aw的blog时碰到的。我的手机屏幕小，然而Opera Mini运行在完整视图时会以贴近Opera PC的形式处理CSS，因此fluid layout的多个列不会自顶向下顺序显示，而会保持原来并排的布局，同时因为fluid layout没有强制width，因此Opera Mini就会使用手机浏览器的宽度来显示整个页面，可想而知原本一个列会被压缩到多么的窄。</p>
<p>因此，使用fluid layout时，要加上min-width属性，加在哪个具体元素上看具体情况而言，但是凡是你不希望被缩得太窄的列，你都应该加上min-width属性。这时候，Opera Mini会发现无法压缩页面宽度，就只能显示横向滚动了，不过这看起来至少会好一些。</p>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/1009244.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41267/" target="_blank">[新闻]Ubuntu创始人呼吁开发Linux桌面软件对抗苹果</a>]]></description></item><item><title>转会咯，从广州转北京咯！</title><link>http://www.cnblogs.com/cathsfz/archive/2007/11/27/974707.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Tue, 27 Nov 2007 13:42:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2007/11/27/974707.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/974707.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2007/11/27/974707.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/974707.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/974707.html</trackback:ping><description><![CDATA[<p>我说的是从广州.NET俱乐部转到北京.NET俱乐部，哈哈。今天一早的飞机抵达北京，明天入职开始在百度为期三个月的实习。非常幸运的是，11月刚刚参加完广州俱乐部的活动，到了北京后就马上碰上了12月的北京俱乐部的<a href="http://www.cnblogs.com/jerryge/articles/971229.html">Visual Studio2008 &amp; Windows Server2008 交流会</a>。如果你是北京俱乐部的成员，或者好像我这样&#8220;碰巧&#8221;有机会参加这次活动，那么到时候见咯。</p>
<img src ="http://www.cnblogs.com/cathsfz/aggbug/974707.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41266/" target="_blank">[新闻]央视国际联手微软打造数字奥运媒体平台</a>]]></description></item><item><title>从 Adobe SHARE 说到 Silverlight 的 XPS 支持</title><link>http://www.cnblogs.com/cathsfz/archive/2007/11/21/966635.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Wed, 21 Nov 2007 01:34:00 GMT</pubDate><guid>http://www.cnblogs.com/cathsfz/archive/2007/11/21/966635.html</guid><wfw:comment>http://www.cnblogs.com/cathsfz/comments/966635.html</wfw:comment><comments>http://www.cnblogs.com/cathsfz/archive/2007/11/21/966635.html#Feedback</comments><slash:comments>16</slash:comments><wfw:commentRss>http://www.cnblogs.com/cathsfz/comments/commentRss/966635.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/cathsfz/services/trackbacks/966635.html</trackback:ping><description><![CDATA[<p>在很久很久以前，我们仅仅知道Flash能够做一些JavaScript做不到或者做不好的交互，特别是复杂度高的交互，除此之外也没有什么理由使用Flash了。后来Flash加上了视频支持，却一直不受重视。然而突然有一天YouTube就出现了，人们才发现这项支持的真正价值，并且纷纷效仿。再后来，Flash还加入了对PDF文档的支持，这项技术最近已经被Adobe成功利用于开发Web2.0站点了，那就是<a href="https://share.adobe.com/">Adobe SHARE</a>。</p> <p>在Silverlight发布的时候，大多数Flash拥有的功能Silverlight都做到了（嵌入字体除外），当然也包括上述的视频与文档支持。只不过，视频支持变成了WMV，因此也就直接支持DRM了，而文档支持则变成了XPS。这个XPS支持能做什么？我们还是先来看看Adobe SHARE的<a href="https://share.adobe.com/adc/document.do?docid=4bfc540c-931b-11dc-8cec-b5f2558a9c5a">示例文档</a>吧，这个文档其实就是一个PDF，然而你无需安装任何客户端的PDF阅读软件，也不需要为浏览器加装任何PDF插件，就能够直接在浏览器中以Flash的形式阅读。</p> <p>考虑一下，以往Sharepoint里面的文档要在浏览器中直接以只读方式打开阅读，可以转换为HTML版本再显示，Sharepoint内置了这一功能，然而这转换肯定会存在一定的失真。现在可以考虑转换为XPS了，然后使用Silverlight作为阅读器就可以了，和HTML版本一样不需要客户端安装有Office，然而用户体验却比HTML版