<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>简单生活 —— Kevin Yang的博客 &#187; Silverlight</title> <atom:link href="http://www.imkevinyang.com/categories/techarticles/silverlight/feed" rel="self" type="application/rss+xml" /><link>http://www.imkevinyang.com</link> <description>It&#039;s all about sharing</description> <lastBuildDate>Thu, 29 Jul 2010 17:50:43 +0000</lastBuildDate> <generator>http://wordpress.org/?v=2.9.1</generator> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <item><title>Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</title><link>http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html</link> <comments>http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html#comments</comments> <pubDate>Mon, 03 May 2010 16:37:42 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[RIA]]></category> <category><![CDATA[SEO]]></category> <category><![CDATA[Silverlight SEO]]></category> <category><![CDATA[Sitemap]]></category> <category><![CDATA[优化]]></category> <category><![CDATA[搜索引擎]]></category> <category><![CDATA[深层链接]]></category> <category><![CDATA[网站地图]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html</guid> <description><![CDATA[继续我们的系列文章，接着来看一下Silverlight和SEO。互联网上大部分流量都是搜索驱动的。搜索引擎通常是很多用户在公共互联网上的第一站，企业环境上的情况也在朝这个趋势发展。搜索也是很多广告获得收益的关键因素。所以无须多讲，SEO非常重要。但对于Silverlight程序来说，很多有意思的内容都是动态生成的，怎么做SEO呢？接下来我会给大家展示一个只需耗费最小工作的应用模式来实现Silverlight应用程序的SEO优化。]]></description> <content:encoded><![CDATA[<div class="statement"><p>作者：Brad Abrams</p><p>译者：Kevin Yang</p><p>英文链接：<a title="Silverlight 4 + RIA Services - Ready for Business: Search Engine Optimization (SEO)" href="http://blogs.msdn.com/brada/archive/2010/03/17/silverlight-4-ria-services-ready-for-business-search-engine-optimization-seo.aspx" target="_blank">Silverlight 4 + RIA Services - Ready for Business: Search Engine Optimization (SEO)</a></p></div><p>继续我们的系列文章，接着来看一下Silverlight和SEO。互联网上大部分流量都是搜索驱动的。搜索引擎通常是很多用户在公共互联网上的第一站，企业环境上的情况也在朝这个趋势发展。搜索也是很多广告获得收益的关键因素。所以无须多讲，SEO非常重要。但对于Silverlight程序来说，很多有意思的内容都是动态生成的，怎么做SEO呢？接下来我会给大家展示一个只需耗费最小工作的应用模式来实现Silverlight应用程序的SEO优化。</p><p>要实现Silverlight应用程序的SEO优化，需要按照以下三个有趣而又简单的步骤来实施：</p><ul><li>步骤1：做好重要的页面的深层链接</li><li>步骤2：使用网站地图(Sitemap)让搜索引擎知道你网站的所有深层链接</li><li>步骤3：对于重要内容，提供一个备选版本</li></ul><p>下面我会用例子来讲解以上这三个步骤的具体含义。我会继续沿用我在PDC209上的“美食浏览器”的演示。你可能需要看一下我之前的演示(<a href="http://blogs.msdn.com/brada/archive/2009/11/19/pdc09-talk-building-amazing-business-applications-with-silverlight-4-ria-services-and-visual-studio-2010.aspx">PDC09 Talk: Building Amazing Business Applications with Silverlight 4, RIA Services and Visual Studio 2010</a>)，这样可以在正式开始下面的讲解之前，能够熟悉一些背景。</p><p><a href="http://brad_abrams.members.winisp.net/Projects/Mix10/MyApp.SEO.zip">下载完整的示例</a>。</p><h2>步骤1: 做好重要的页面的深层链接</h2><p>对于你网站上的任何内容，如果你想让搜索引擎能够爬取到，那么必须给这份内容起一个独特的Url。例如如果我想在Bing（或者Google，或者其他搜索引擎）上搜索“乡村炸牛排（Country Fried Steak）”，能看到我网站上这个列举了很多乡村炸牛排图片的页面，那么我需要为这个页面提供一个Url，从而引导你来到这个页面。http://foo.com/foodieExplorer.aspx这个Url还不够好，我需要提供一个类似于http://foo.com/foodieExplorer.aspx?food=CountryFriedsteak这样的Url。注意，使用这种格式的Url还有很多其他的好处，例如用户可以在Twitter上传播，通过电子邮件或者即时通讯软件去讨论这些内容。</p><p>幸运的是，Silverlight的导航特性使到实现内容的深层链接变得非常简单。我们来看看具体是怎么做的。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0016.png"><img style="display: inline; border-width: 0px;" title="clip_image001[6]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0016_thumb.png" border="0" alt="clip_image001[6]" width="275" height="212" /></a></p><p>我们首先需要做的就是提供一个Url来唯一标识一个特定的餐馆，或者一个特定的餐馆加特定的美食。出于SEO或者用户友好的角度考虑，我们希望Url的格式类似于http://www.hanselman.com/abrams/restaurant/25/plate/4，这表示餐馆编号=25，美食编号=4。要实现这个，我们需要在Web工程的global.aspx文件中定义导航路径（Routes）。</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Global : HttpApplication
{
    <span class="kwrd">void</span> Application_Start(<span class="kwrd">object</span> sender, EventArgs e)
    {
        RegisterRoutes(RouteTable.Routes);
    }

    <span class="kwrd">void</span> RegisterRoutes(RouteCollection routes)
    {
        routes.MapPageRoute(
            <span class="str">"deepLinkRouteFull"</span>,
            <span class="str">"restaurant/{restaurantId}/plate/{plateId}"</span>,
            <span class="str">"~/default.aspx"</span>,
            <span class="kwrd">false</span>,
            <span class="kwrd">new</span> RouteValueDictionary { { <span class="str">"restaurant"</span>, <span class="str">"-1"</span> },
            { <span class="str">"plate"</span>, <span class="str">"-1"</span> } });

        routes.MapPageRoute(
            <span class="str">"deepLinkRoute"</span>,
            <span class="str">"restaurant/{restaurantId}"</span>,
            <span class="str">"~/default.aspx"</span>,
            <span class="kwrd">false</span>,
            <span class="kwrd">new</span> RouteValueDictionary { { <span class="str">"restaurant"</span>, <span class="str">"-1"</span> } });</pre><p>在上面代码中，我们定义了深层链接的Url模板，支持Url中添加餐馆编号（restaurantId）和美食编号（plateId）的参数。我们定义的导航路径的顺序是从最复杂到不那么复杂。如果这两个编号在Url中都缺失的话，那么将使用上面设置的默认值。</p><p>现在，我们来看看Silverlight客户端怎么解析这个Url的。在Plates.xaml.cs文件中：</p><pre class="csharpcode"><span class="rem">// Executes when the user navigates to this page.</span>
<span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)
{
    <span class="kwrd">int</span> plateID = -1;
    <span class="kwrd">int</span> restaurantId  =-1;
    var s = HtmlPage.Document.DocumentUri.ToString().Split(<span class="kwrd">new</span> <span class="kwrd">char</span>[] {<span class="str">'/'</span>,<span class="str">'#'</span>});
    <span class="kwrd">int</span> i = Find(s, <span class="str">"plate"</span>);
    <span class="kwrd">if</span> (i != -1)
    {
         plateID = Convert.ToInt32(s[i + 1]);
         plateDomainDataSource.FilterDescriptors.Add(
             <span class="kwrd">new</span> FilterDescriptor(<span class="str">"ID"</span>,
                 FilterOperator.IsEqualTo, plateID));
    }
    i = Find(s, <span class="str">"restaurant"</span>);
    <span class="kwrd">if</span> (i != -1) restaurantId = Convert.ToInt32(s[i + 1]);
    <span class="kwrd">else</span> restaurantId = Convert.ToInt32(NavigationContext.QueryString[<span class="str">"restaurantId"</span>]);
    plateDomainDataSource.QueryParameters.Add(
        <span class="kwrd">new</span> Parameter()
        {
           ParameterName = <span class="str">"resId"</span>,
           Value = restaurantId
        }
    );
}</pre><p>基本上，上面代码所做的事情就是获取完整的Url，然后将其结构化，再提取出其中的餐馆编号和美食编号。在18-23行中，我们将餐馆编号作为参数传给查询方法，但是在11-14行中，我们并没有这么干，而是应用了一个过滤器，这就相当于最终发给服务器的LINQ查询就多了一个“where”子句。这样，我们就无需修改服务端的代码了。</p><p>我们还需要做一点小工作，那就是保证客户端最终导航到美食（Plates）的页面。这在Silverlight的导航框架中是通过锚点“#/Plates”来实现的。但由于锚点只是一个客户端特性，而搜索引擎并不能很好的处理锚点，因此我们需要在客户端动态添加锚点。我发现用一点点Javascript脚本就可以很好的完成这个工作。我在服务端的Default.aspx页面上加入了这段脚本：</p><pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">void</span> Page_Init(<span class="kwrd">object</span> sender, EventArgs e)
{
    <span class="kwrd">string</span> resId = Page.RouteData.Values[<span class="str">"restaurant"</span>] <span class="kwrd">as</span> <span class="kwrd">string</span>;
    <span class="kwrd">if</span> (resId != <span class="kwrd">null</span>) { Response.Write(<span class="str">"&lt;script type=text/javascript&gt;window.location.hash='#/Plates';&lt;/script"</span>+<span class="str">"&gt;"</span>); }
}</pre><p>还有一个小事情需要注意的，由于我们启用了路径导航的功能，现在就可以通过不同的Url来访问default.aspx页面了，因此如果使用相对路径去引用Silverlight.js以及MyApp.xap包的时候就会出现问题。例如我们会看到浏览器去请求http://www.hanselman.com/abrams/restaurant/25/plate/4/Silverlight.js，而不是http://www.hanselman.com/abrams/silverlight.js，这会导致下面错误：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0018.png"><img style="display: inline; border-width: 0px;" title="clip_image001[8]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0018_thumb.png" border="0" alt="clip_image001[8]" width="244" height="169" /></a></p><blockquote><p>行: 56</p><p>错误: Unhandled Error in Silverlight Application</p><p>异常代码: 2104</p><p>类别: InitializeError</p><p>消息: 无法下载Silverlight程序，请检查Web服务器的设置</p></blockquote><p>要解决这个问题，我们需要修改脚本的src属性：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">script </span><span class="attr">src</span><span class="kwrd">='&lt;%= this.ResolveUrl("~/Silverlight.js") %&gt;'</span></pre><p>还有Silverlight插件参数：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">param</span> <span class="attr">name</span><span class="kwrd">="source"</span> <span class="attr">value</span><span class="kwrd">="&lt;%= this.ResolveUrl("</span>~/<span class="attr">ClientBin</span>/<span class="attr">MyApp</span>.<span class="attr">xap</span><span class="kwrd">") %&gt;"</span><span class="kwrd">/&gt;</span></pre><p>现在我们再通过http://localhost:30045/restaurant/48/plate/119#/Plates这个包含美食编号的Url来访问，就能直接来到相应的美食页面了：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00110.png"><img style="display: inline; border-width: 0px;" title="clip_image001[10]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00110_thumb.png" border="0" alt="clip_image001[10]" width="408" height="322" /></a></p><h2>步骤2：使用网站地图让搜索引擎知道你网站的所有深层链接</h2><p>现在我们有了一个已经做好深层链接的应用程序了，每一个有趣的内容都被赋予了一个唯一的Url。但搜索引擎怎么知道这些Url呢？我们当然希望别人在社交网络上多谈论（谈论的时候通常会留下链接），然后搜索引擎能够发现其中的一部分Url，但我们更希望能够把这事做完整了。我们想给搜索引擎提供一个应用程序内部所有深层链接的Url列表。这可以使用网站地图（Sitemap）来实现。</p><p>网站地图的格式是所有主流搜索引擎都认可的。你可以在<a href="http://sitemap.org">http://sitemap.org</a>网站找到相关的信息。</p><p>为了更好的了解这其中的原理，我们来看看亚马逊，<a href="http://amazon.com">http://amazon.com</a>，这个以数据驱动的网站是如何被搜索引擎索引的。当搜索引擎第一次来到这个网站，它会去读取网站根目录下的robots.txt文件。在这个例子中，robots.txt文件的绝对地址是<a href="http://www.amazon.com/robots.txt">http://www.amazon.com/robots.txt</a>。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00112.png"><img style="display: inline; border-width: 0px;" title="clip_image001[12]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00112_thumb.png" border="0" alt="clip_image001[12]" width="222" height="341" /></a></p><p>在这个例子中，我们可以看到，文件上半部分列举了一些目录，这些目录是不允许搜索引擎爬取的，文件下半部分列举的sitemap清单，是希望搜索引擎去爬取这些网站内容。</p><p>注意，严格来说，你不是必须使用Robots文件来声明你的网站地图（译者注：原文写的是“你不是必须使用网站地图”）。你可以使用主流搜索引擎提供的网站管理员工具直接登记网站地图地址。</p><p>如果我们导航到上面其中一个网址，我们将看到一个网站地图文件，如下面所示：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00114.png"><img style="display: inline; border-width: 0px;" title="clip_image001[14]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00114_thumb.png" border="0" alt="clip_image001[14]" width="244" height="190" /></a></p><p>在这个例子中，因为亚马逊网站很庞大，这些链接被放到多个网站地图中去了（上面这个文件被称为网站地图索引文件）。当我们钻进子网站地图文件中，就能看到实际产品的链接了。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00116.png"><img style="display: inline; border-width: 0px;" title="clip_image001[16]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00116_thumb.png" border="0" alt="clip_image001[16]" width="396" height="293" /></a></p><p>格式就如你看到的：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">urlset</span> <span class="attr">xmlns</span><span class="kwrd">="http://www.google.com/schemas/sitemap/0.84"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">url</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">loc</span><span class="kwrd">&gt;</span>http://www.amazon.com/GAITHER-COMMITTEE-EISENHOWER-COLD-WAR/dp/081425005X<span class="kwrd">&lt;/</span><span class="html">loc</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">url</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">url</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">loc</span><span class="kwrd">&gt;</span>http://www.amazon.com/CONTROLLING-VICE-REGULATING-PROSTITUTION-CRIMINAL/dp/0814250076<span class="kwrd">&lt;/</span><span class="html">loc</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">url</span><span class="kwrd">&gt;</span></pre><p>有意思的是，当亚马逊产品目录中添加或者移除商品的时候，这里的链接也会经常发生变更。</p><p>我们接着来看看如何为我们的网站建立一个网站地图。在Web工程中，打开VS的添加条目对话框，往我们工程添加一个“Search sitemap”  。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image002.png"><img style="display: inline; border-width: 0px;" title="clip_image002" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image002_thumb.png" border="0" alt="clip_image002" width="366" height="247" /></a></p><p>确认你机器上已经安装了<a href="http://silverlight.net/riaservices">RIA Services Toolkit</a> ，否则是没有这个条目模板的。</p><p>添加成功之后，我们会得到一个robots.txt文件：</p><blockquote><p># This file provides hints and instructions to search engine crawlers.</p><p># For more information, see <a href="http://www.robotstxt.org/">http://www.robotstxt.org/</a>.</p><p># Allow all</p><p>User-agent: *</p><p># Prevent crawlers from indexing static resources (images, XAPs, etc)</p><p>Disallow: /ClientBin/</p><p># Register your sitemap(s) here.</p><p>Sitemap: /Sitemap.aspx</p></blockquote><p>还有一个sitemap.aspx的文件。</p><p>更多信息，请参考：<a href="http://www.bing.com/community/blogs/webmaster/archive/2009/08/15/uncovering-web-based-treasure-with-sitemaps-sem-101.aspx">Uncovering web-based treasure with Sitemaps</a>。</p><p>但这个sitemap.aspx文件还是空的，要建立实际可用的网站地图，我们需要基于PlateViewDomainService创建另外的视图。在这个例子，这个视图的消费者是一个Asp.Net页面。这里我们要用到asp:DomainDataSource。在设计器拖放一个Repeater控件到表单中，如下所示：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image003.png"><img style="display: inline; border-width: 0px;" title="clip_image003" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image003_thumb.png" border="0" alt="clip_image003" width="244" height="157" /></a></p><p>在Repeater控件上右键配置数据源：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image004.png"><img style="display: inline; border-width: 0px;" title="clip_image004" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image004_thumb.png" border="0" alt="clip_image004" width="436" height="117" /></a></p><p>选择一个数据源</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image005.png"><img style="display: inline; border-width: 0px;" title="clip_image005" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image005_thumb.png" border="0" alt="clip_image005" width="369" height="294" /></a></p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image006.png"><img style="display: inline; border-width: 0px;" title="clip_image006" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image006_thumb.png" border="0" alt="clip_image006" width="244" height="192" /></a></p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image007.png"><img style="display: inline; border-width: 0px;" title="clip_image007" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image007_thumb.png" border="0" alt="clip_image007" width="244" height="192" /></a></p><p>最后，我们的网站地图文件中就会得到两个链接集合。</p><pre class="csharpcode"> <span class="kwrd">&lt;</span><span class="html">asp:DomainDataSource</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">ID</span><span class="kwrd">="RestaurauntSitemapDataSource"</span>
 <span class="attr">DomainServiceTypeName</span><span class="kwrd">="MyApp.Web.DishViewDomainService"</span>
 <span class="attr">QueryName</span><span class="kwrd">="GetRestaurants"</span> <span class="kwrd">/&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">asp:Repeater</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">id</span><span class="kwrd">="repeater"</span> <span class="attr">DataSourceID</span><span class="kwrd">="RestaurauntSitemapDataSource"</span> <span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">HeaderTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">urlset</span> <span class="attr">xmlns</span><span class="kwrd">="http://www.sitemaps.org/schemas/sitemap/0.9"</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">HeaderTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">url</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">loc</span><span class="kwrd">&gt;</span><span class="asp">&lt;%</span>= Request.Url.AbsoluteUri.ToLower().Replace(<span class="str">"sitemap.aspx"</span>,<span class="kwrd">string</span>.Empty) + <span class="str">"restaurant/"</span><span class="asp">%&gt;</span><span class="asp">&lt;%</span># HttpUtility.UrlEncode(Eval(<span class="str">"ID"</span>).ToString()) <span class="asp">%&gt;</span><span class="kwrd">&lt;/</span><span class="html">loc</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">url</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">asp:Repeater</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">asp:DomainDataSource</span> <span class="attr">ID</span><span class="kwrd">="PlatesSitemapDataSource"</span> <span class="attr">runat</span><span class="kwrd">="server"</span>
 <span class="attr">DomainServiceTypeName</span><span class="kwrd">="MyApp.Web.DishViewDomainService"</span>
 <span class="attr">QueryName</span><span class="kwrd">="GetPlates"</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">asp:DomainDataSource</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">asp:Repeater</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">id</span><span class="kwrd">="repeater2"</span> <span class="attr">DataSourceID</span><span class="kwrd">="PlatesSitemapDataSource"</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">url</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">loc</span><span class="kwrd">&gt;</span><span class="asp">&lt;%</span>= Request.Url.AbsoluteUri.ToLower().Replace(<span class="str">"sitemap.aspx"</span>,<span class="kwrd">string</span>.Empty) + <span class="str">"restaurant/"</span><span class="asp">%&gt;</span><span class="asp">&lt;%</span># HttpUtility.UrlEncode(Eval(<span class="str">"RestaurantID"</span>).ToString()) + <span class="str">"/plate/"</span> + HttpUtility.UrlEncode(Eval(<span class="str">"ID"</span>).ToString()) <span class="asp">%&gt;</span><span class="kwrd">&lt;/</span><span class="html">loc</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">url</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">FooterTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">urlset</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">FooterTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">asp:Repeater</span><span class="kwrd">&gt;</span></pre><p>在第3行和第20行，我们是直接调用在DomainService中定义的GetRestaurant 和GetPlates方法。</p><p>现在，对于一个具有相当规模数据量的网站来说，这个页面将会耗费很长的时间去执行。它需要扫描数据库中的每一行。这当然可以保证数据永远最新的，但是我们希望平衡一下服务器的负载。一个简单的做法就是通过设置一个小时的输出缓存。具体操作参考<a href="http://msdn.microsoft.com/en-us/library/aa478965.aspx">ASP.NET Caching: Techniques and Best Practices</a>。</p><pre class="csharpcode"><span class="asp">&lt;%@ OutputCache Duration="3600" VaryByParam="None" %&gt;</span></pre><p>另外一个处理这种大数据集的策略是将数据分割到多个网站地图中去，就像我们上面看到的亚马逊网站的例子。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image008.png"><img style="display: inline; border-width: 0px;" title="clip_image008" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image008_thumb.png" border="0" alt="clip_image008" width="311" height="372" /></a></p><p>随便取其中的一个Url，导航到此网址，OK，现在我们得到正确的页面了。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image009.png"><img style="display: inline; border-width: 0px;" title="clip_image009" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image009_thumb.png" border="0" alt="clip_image009" width="444" height="261" /></a></p><h2>步骤3：对于重要内容，提供一个备选版本</h2><p>太棒了，现在我们有了深层链接，我们也能让搜索引擎发现所有这些链接，不过，当搜索引擎来到这个页面的时候，它会看到什么？多数搜索引擎只会解析HTML，所以通过菜单"页面&gt;查看源代码"，我们就能够看到搜索引擎眼中我们页面的面目了:</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00118.png"><img style="display: inline; border-width: 0px;" title="clip_image001[18]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00118_thumb.png" border="0" alt="clip_image001[18]" width="358" height="207" /></a></p><p>或者我们在禁用Silverlight插件（工具 &gt; 管理加载项）后去访问此页面，我们会看到：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00120.png"><img style="display: inline; border-width: 0px;" title="clip_image001[20]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00120_thumb.png" border="0" alt="clip_image001[20]" width="275" height="158" /></a></p><p>我们会看到一个巨大的白屏！</p><p>Silverlight生成的动态内容根本没有显示。事实上，要显示这些动态内容，必须得执行Silverlight代码。但我敢肯定，搜索引擎在任何时候都不会在他们的数据中心上去执行我们的Silverlight（或者Flash或者Ajax）代码的。所以我们需要的是一些备选的内容。</p><p>幸运的是，要做到这一点非常简单。首先让所有备选的内容展示出来。需要特别注意的是，这些内容并不单单是给搜索引擎看。制作只给搜索引擎看的内容是“糊弄搜索引擎”，或者是垃圾网页。这些内容通常用来迷惑搜索引擎，掩盖网站的真实内容（<a href="http://www.bing.com/community/blogs/webmaster/archive/2010/02/11/the-pernicious-perfidy-of-page-level-web-spam-sem-101.aspx">the pernicious perfidy of page-level web spam</a>) 。而这里的备选内容是给那些没有安装Silverlight插件的用户看的。它可能不拥有所有Silverlight的特性，但却提供了一个降级的用户体验。当搜索引擎蜘蛛没有安装Silverlight插件的时候也是如此，这可以保证它们能够索引到一些有意义而且准确的信息。</p><p>把下面这段HTML代码添加到default.aspx页面中。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">id</span><span class="kwrd">="AlternativeContent"</span> <span class="attr">style</span><span class="kwrd">="display: none;"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">h2</span><span class="kwrd">&gt;</span>Hi, this is my alternative content<span class="kwrd">&lt;/</span><span class="html">h2</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre><p>注意，这里写的是display:none，意味着我们并不期望浏览器去渲染这段内容...除非Silverlight插件不可用。为了实现这个效果，把下面这小段JS代码添加到页面中：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">="text/javascript"</span><span class="kwrd">&gt;</span>
<span class="kwrd">if</span> (!isSilverlightInstalled()) {
<span class="kwrd">var</span> obj = document.getElementById(<span class="str">'AlternativeContent'</span>);
obj.style.display = <span class="str">""</span>;
}
<span class="kwrd">&lt;/</span><span class="html">script</span><span class="kwrd">&gt;</span></pre><p>注意，这个很方便的isSilverlightInsalled函数是从Petr的<a href="http://blogs.msdn.com/piotrp/archive/2008/05/07/determining-if-silverlight-is-installed-using-javascript.aspx">old-but-good post on the subject</a>文章中找到的。我只是把这个函数添加到我的Silverlight.js文件而已。</p><pre class="csharpcode"><span class="kwrd">function</span> isSilverlightInstalled() {
    <span class="kwrd">var</span> isSilverlightInstalled = <span class="kwrd">false</span>;
    <span class="kwrd">try</span> {
        <span class="rem">//check on IE</span>
        <span class="kwrd">try</span> {
            <span class="kwrd">var</span> slControl = <span class="kwrd">new</span> ActiveXObject(<span class="str">'AgControl.AgControl'</span>);
            isSilverlightInstalled = <span class="kwrd">true</span>;
        }
        <span class="kwrd">catch</span> (e) {
            <span class="rem">//either not installed or not IE. Check Firefox</span>
            <span class="kwrd">if</span> (navigator.plugins[<span class="str">"Silverlight Plug-In"</span>]) {
                isSilverlightInstalled = <span class="kwrd">true</span>;
            }
        }
    }
    <span class="kwrd">catch</span> (e) {
        <span class="rem">//we don't want to leak exceptions. However, you may </span>
        <span class="rem">//to add exception tracking code here</span>
    }
    <span class="kwrd">return</span> isSilverlightInstalled;
}</pre><p>当我们使用一个没有启用Silverlight插件的浏览器中去浏览此页面的时候，我们就会看到备选的内容：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0025.png"><img style="display: inline; border-width: 0px;" title="clip_image002[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0025_thumb.png" border="0" alt="clip_image002[5]" width="244" height="134" /></a></p><p>但是如果安装了Silverlight，我们则会看到漂亮的Silverlight应用程序内容：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0035.png"><img style="display: inline; border-width: 0px;" title="clip_image003[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0035_thumb.png" border="0" alt="clip_image003[5]" width="244" height="184" /></a></p><p>这很不错，但我们怎么让页面显示正确的内容呢？我们想要展示和Silverlight应用程序完全一致的数据，而且又不想写太多代码。我们也实在不想去维护太多页面。所以让我们在页面的AlternativeContent这个DIV里头加入一些基本的代码。这个ListView是用来显示餐馆详细信息的。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">asp:ListView</span> <span class="attr">ID</span><span class="kwrd">="RestaurnatDetails"</span> <span class="attr">runat</span><span class="kwrd">="server"</span>
                <span class="attr">EnableViewState</span><span class="kwrd">="false"</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">LayoutTemplate</span><span class="kwrd">&gt;</span>
       <span class="kwrd">&lt;</span><span class="html">asp:PlaceHolder</span> <span class="attr">ID</span><span class="kwrd">="ItemPlaceHolder"</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">/&gt;</span>
   <span class="kwrd">&lt;/</span><span class="html">LayoutTemplate</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
       <span class="kwrd">&lt;</span><span class="html">asp:DynamicEntity</span> <span class="attr">ID</span><span class="kwrd">="RestaurnatEntity"</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">/&gt;</span>
   <span class="kwrd">&lt;/</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">asp:ListView</span><span class="kwrd">&gt;</span></pre><p>现在我们需要把它和我们的数据源绑定...我发现在VS的设计视图里头很容易就能够做到这一点。注意，要在设计器中编辑这个DIV，你需要将DIV改成可见模式。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0045.png"><img style="display: inline; border-width: 0px;" title="clip_image004[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0045_thumb.png" border="0" alt="clip_image004[5]" width="244" height="130" /></a></p><p>然后我们来配置一下数据源：</p><p><a href="http://blogs.msdn.com/blogfiles/brada/WindowsLiveWriter/Silverlight4RIAServicesReadyforBusinessS_C533/image70.png"><img style="display: inline; border-width: 0px;" title="clip_image005[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0055.png" border="0" alt="clip_image005[5]" width="270" height="212" /></a></p><p>下一步，我们需要基于我们之前定义的导航路径来绑定查询参数。</p><p><a href="http://blogs.msdn.com/blogfiles/brada/WindowsLiveWriter/Silverlight4RIAServicesReadyforBusinessS_C533/image_74.png"><img style="display: inline; border-width: 0px;" title="clip_image006[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0065.png" border="0" alt="clip_image006[5]" width="275" height="192" /></a></p><p>然后，我们对美食的ListView控件也重复同样的操作...</p><p>现在我们得到的代码非常简单:</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">asp:ListView</span> <span class="attr">ID</span><span class="kwrd">="RestaurnatDetails"</span> <span class="attr">runat</span><span class="kwrd">="server"</span>
         <span class="attr">EnableViewState</span><span class="kwrd">="false"</span> <span class="attr">DataSourceID</span><span class="kwrd">="restaurantsDomainDataSource"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">LayoutTemplate</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">asp:PlaceHolder</span> <span class="attr">ID</span><span class="kwrd">="ItemPlaceHolder"</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">LayoutTemplate</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
     <span class="kwrd">&lt;</span><span class="html">asp:DynamicEntity</span> <span class="attr">ID</span><span class="kwrd">="RestaurnatEntity"</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">asp:ListView</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">asp:DomainDataSource</span> <span class="attr">ID</span><span class="kwrd">="restaurantsDomainDataSource"</span> <span class="attr">runat</span><span class="kwrd">="server"</span>
               <span class="attr">DomainServiceTypeName</span><span class="kwrd">="MyApp.Web.DishViewDomainService"</span>
               <span class="attr">QueryName</span><span class="kwrd">="GetRestaurant"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">QueryParameters</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">asp:RouteParameter</span> <span class="attr">name</span><span class="kwrd">="id"</span> <span class="attr">RouteKey</span><span class="kwrd">="restaurantId"</span>
                   <span class="attr">DefaultValue</span> <span class="kwrd">="-1"</span> <span class="attr">Type</span> = <span class="kwrd">"Int32"</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">QueryParameters</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">asp:DomainDataSource</span><span class="kwrd">&gt;</span></pre><p>下一步，我们需要让这些控件基于数据动态生成UI。</p><pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">void</span> Page_Init(<span class="kwrd">object</span> sender, EventArgs e)
{
 RestaurnatDetails.EnableDynamicData(<span class="kwrd">typeof</span>(MyApp.Web.Restaurant));
 PlateDetails.EnableDynamicData(<span class="kwrd">typeof</span>(MyApp.Web.Plate));
 <span class="kwrd">string</span> resId = Page.RouteData.Values[<span class="str">"restaurant"</span>] <span class="kwrd">as</span> <span class="kwrd">string</span>;
 <span class="kwrd">if</span> (resId != <span class="kwrd">null</span>) { Response.Write(<span class="str">"&lt;script type=text/javascript&gt;window.location.hash='#/Plates';&lt;/script"</span>+<span class="str">"&gt;"</span>); }
}</pre><p>注意到，我们在第4-5行处为这两个ListView控件启用了动态数据。</p><p>最后一步，我们需要添加DynamicData需要用到的模板集。你可以从任何DynamicData的工程中获得相应的文件。将其拷贝到Web工程根目录下。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0075.png"><img style="display: inline; border-width: 0px;" title="clip_image007[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0075_thumb.png" border="0" alt="clip_image007[5]" width="165" height="212" /></a></p><p>你可以通过编辑这些模板来控制数据的显示。</p><p>在EntityTemplates目录中，我们需要为每个实体创建一个实体模板（在这个例子中，有美食和餐馆这两个实体）。这会决定他们是如何显示的。</p><pre class="csharpcode"><span class="asp">&lt;%@ Control Language="C#" CodeBehind="Restaurant.ascx.cs" Inherits="MyApp.Web.RestaurantEntityTemplate" %&gt;</span>

<span class="kwrd">&lt;</span><span class="html">asp:DynamicControl</span>  <span class="attr">ID</span><span class="kwrd">="DynamicControl8"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="ImagePath"</span> <span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;</span><span class="html">ul</span> <span class="attr">class</span><span class="kwrd">="restaurant"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">ul</span> <span class="attr">class</span><span class="kwrd">="restaurantDetails"</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">h2</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="NameControl"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="Name"</span> <span class="kwrd">/&gt;</span> <span class="kwrd">&lt;/</span><span class="html">h2</span><span class="kwrd">&gt;</span> <span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl1"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="ContactName"</span> <span class="kwrd">/&gt;</span> (<span class="kwrd">&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl2"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="ContactTitle"</span> <span class="kwrd">/&gt;</span>)<span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl3"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="Address"</span> <span class="kwrd">/&gt;</span>  <span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl4"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="City"</span> <span class="kwrd">/&gt;</span>, <span class="kwrd">&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl5"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="Region"</span> <span class="kwrd">/&gt;</span>  <span class="kwrd">&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl6"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="PostalCode"</span> <span class="kwrd">/&gt;</span>  <span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl7"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="Phone"</span> <span class="kwrd">/&gt;</span>  <span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:HyperLink</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">ID</span><span class="kwrd">="link"</span>  <span class="attr">NavigateUrl</span><span class="kwrd">="&lt;%#GetDetailsUrl() %&gt;"</span> <span class="attr">Text</span><span class="kwrd">="details.."</span><span class="kwrd">&gt;&lt;/</span><span class="html">asp:HyperLink</span><span class="kwrd">&gt;&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;/</span><span class="html">ul</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">ul</span><span class="kwrd">&gt;</span></pre><p>这里我们只是做了些简单的格式化操作，然后把我们需要在备选内容中显示的字段挑选出来。对美食实体也重复同样的操作…</p><p>现在我们已经可以准备运行了。</p><p>访问根目录，在没有添加任何Url参数的情况下，我们会看到一个餐馆列表，当然，全都是HTML代码。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0085.png"><img style="display: inline; border-width: 0px;" title="clip_image008[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0085_thumb.png" border="0" alt="clip_image008[5]" width="275" height="191" /></a></p><p>接着我们可以添加一个导航来定位某个特定餐馆的所有美食。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0095.png"><img style="display: inline; border-width: 0px;" title="clip_image009[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0095_thumb.png" border="0" alt="clip_image009[5]" width="249" height="212" /></a></p><p>但是，让我们在真正的浏览器中浏览此页面，确保我们看到的和搜索引擎看到的是一样的。</p><p>Lynx还活着！Lynx是我92年在北卡罗来纳州州立大学Leazar实验室的DEC2100机器上用过的第一个浏览器...现在还可以正常工作！</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image010.png"><img style="display: inline; border-width: 0px;" title="clip_image010" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image010_thumb.png" border="0" alt="clip_image010" width="275" height="184" /></a></p><p>还有细节信息：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image011.png"><img style="display: inline; border-width: 0px;" title="clip_image011" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image011_thumb.png" border="0" alt="clip_image011" width="275" height="184" /></a></p><p>这款经典的文本浏览器让我们看到了纯文本模式下页面的样子，这恰恰是搜索引擎蜘蛛所看到的。</p><p>现在，来看真正的测试。</p><p>我们使用Bing去搜索“我的美食浏览器——和Joe学烹饪”，显然，这个页面确实在那。</p><p><a href="http://blogs.msdn.com/blogfiles/brada/WindowsLiveWriter/Silverlight4RIAServicesReadyforBusinessS_C533/image_56.png"><img style="display: inline; border-width: 0px;" title="clip_image012" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image012.png" border="0" alt="clip_image012" width="275" height="185" /></a></p><p>点击这个链接？</p><p>浏览器导航到的页面正是我们期望的页面。</p><p><a href="http://blogs.msdn.com/blogfiles/brada/WindowsLiveWriter/Silverlight4RIAServicesReadyforBusinessS_C533/image_58.png"><img style="display: inline; border-width: 0px;" title="clip_image013" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image013.png" border="0" alt="clip_image013" width="275" height="191" /></a></p><p>当然，这在另外一个<a href="http://www.google.com/#hl=en&amp;source=hp&amp;q=my+foodie+Explorer+Cooking+Class+with+Joe..&amp;btnG=Google+Search&amp;aq=f&amp;aqi=&amp;aql=&amp;oq=my+foodie+Explorer+Cooking+Class+with+Joe..&amp;fp=f55f94328208dcc1" target="_blank">搜索引擎</a>来说也是一样的... 如果你刚好是另外这个搜索引擎的用户:-)</p><h2>总结</h2><p>在上面这个例子中，我们学习了如何创建一个SEO优化过的、以数据驱动的Silverlight应用程序的基本操作。总共分为三个步骤：</p><ul><li>步骤1：做好重要的页面的深层链接</li><li>步骤2：使用网站地图(Sitemap)让搜索引擎知道你网站的所有深层链接</li><li>步骤3：对于重要内容，提供一个备选版本</li></ul><p>希望你们喜欢~</p><p>更多信息，请参考:  <a href="http://www.bing.com/community/blogs/webmaster/archive/2010/03/05/illuminating-the-path-to-seo-for-silverlight.aspx">点亮Silverlight的SEO之路</a>。</p>标签：<a href="http://www.imkevinyang.com/tags/ria" title="RIA" rel="tag">RIA</a>, <a href="http://www.imkevinyang.com/tags/seo" title="SEO" rel="tag">SEO</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight-seo" title="Silverlight SEO" rel="tag">Silverlight SEO</a>, <a href="http://www.imkevinyang.com/tags/sitemap" title="Sitemap" rel="tag">Sitemap</a>, <a href="http://www.imkevinyang.com/tags/%e4%bc%98%e5%8c%96" title="优化" rel="tag">优化</a>, <a href="http://www.imkevinyang.com/tags/%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e" title="搜索引擎" rel="tag">搜索引擎</a>, <a href="http://www.imkevinyang.com/tags/%e6%b7%b1%e5%b1%82%e9%93%be%e6%8e%a5" title="深层链接" rel="tag">深层链接</a>, <a href="http://www.imkevinyang.com/tags/%e7%bd%91%e7%ab%99%e5%9c%b0%e5%9b%be" title="网站地图" rel="tag">网站地图</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/05/2009%e5%b9%b4%e7%ac%ac%e4%b8%80%e5%ad%a3%e5%ba%a6%e4%b8%ad%e5%9b%bd%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e5%b8%82%e5%9c%ba%e8%90%a5%e6%94%b6%e4%bb%bd%e9%a2%9d.html" title="2009年第一季度中国搜索引擎市场营收份额 (2009/05/06)">2009年第一季度中国搜索引擎市场营收份额</a> (2009/05/06)</li><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/03/google%e5%b7%a5%e7%a8%8b%e5%b8%88matt-cutts%e8%b0%88seo.html" title="Google工程师Matt Cutts谈SEO (2009/03/23)">Google工程师Matt Cutts谈SEO</a> (2009/03/23)</li><li><a href="http://www.imkevinyang.com/2009/05/robotstxt%e6%96%87%e4%bb%b6.html" title="Robots.txt文件 (2009/05/06)">Robots.txt文件</a> (2009/05/06)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Silverlight的依赖属性与附加属性</title><link>http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html</link> <comments>http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html#comments</comments> <pubDate>Sun, 28 Mar 2010 13:42:59 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[AttachedProperty]]></category> <category><![CDATA[CLR属性]]></category> <category><![CDATA[DependancyProperty]]></category> <category><![CDATA[依赖属性]]></category> <category><![CDATA[值变更]]></category> <category><![CDATA[寻值]]></category> <category><![CDATA[附加属性]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html</guid> <description><![CDATA[<p>好久没写Silverlight了，依赖属性（Dependency Property）和附加属性（Attached Property）这两个算是很基础的知识都不是很记得了。写一写，当做一下笔记吧。</p><h2>CLR属性 与 依赖属性</h2><p>CLR属性我们非常熟悉了，在DotNet编程中随处可见。最简单最常见的属性访问器就是直接操纵类的私有成员，如下：</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Person
{
    <span class="kwrd">private</span> String _name;
    <span class="kwrd">public</span> <span class="kwrd">string</span> Name
    {
        get { <span class="kwrd">r&#8230;</span></pre>]]></description> <content:encoded><![CDATA[<p>好久没写Silverlight了，依赖属性（Dependency Property）和附加属性（Attached Property）这两个算是很基础的知识都不是很记得了。写一写，当做一下笔记吧。</p><h2>CLR属性 与 依赖属性</h2><p>CLR属性我们非常熟悉了，在DotNet编程中随处可见。最简单最常见的属性访问器就是直接操纵类的私有成员，如下：</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Person
{
    <span class="kwrd">private</span> String _name;
    <span class="kwrd">public</span> <span class="kwrd">string</span> Name
    {
        get { <span class="kwrd">return</span> _name; }
        set { _name = <span class="kwrd">value</span>; }
    }
}</pre><p>C#3.0对这种常见的写法提供了“自动属性”这一特性，方便了偶等这些懒惰的码农。</p><pre class="csharpcode">

<span class="kwrd">public</span> <span class="kwrd">class</span> Person
{
    <span class="kwrd">public</span> <span class="kwrd">string</span> Name { get; set; }
}
</pre><p>这两种写法是等价的，都是<strong><font color="#008000">需要设立一个实例级的私有变量作为属性访问器的持久存储</font></strong>。这对于我们非UI应用来说没什么。因为第一，我们一般不会创建太多类实例；第二，一个类的属性通常不会很多，加几个私有变量不会增加系统负担。但是这两个理由对于UI应用程序来说恰恰不成立。</p><p>在很多UI应用中，我们经常会创建很多类实例，成千上万个实例在UI系统中是很普遍的事情。同时，UI类通常会包含大量的属性供设计人员使用，例如背景颜色，前景颜色，字体，边距等等，这些属性在绝大多数情况下会保持默认值，如果为每个实例都建立这么多的私有变量来存储UI属性的值，势必会造成极大的浪费，对系统负担的开销也是不小。</p><p>鉴于以上提到的问题，设计一个高效的属性存储系统对于UI应用程序的开发是非常重要的。因此Silverlight引入了“依赖属性（DependencyProperty）”。</p><h3>采用键值对替代成员变量作为属性内部存储</h3><p>传统CLR属性，一个属性对应一个私有变量，UI元素的属性那么多，创建过多的私有变量不是一件简单的事情，况且大多数属性只会用到默认值。因此Silverlight在每个类实例中使用一个字典型的成员变量来存放那些用户显式设置的属性（称为Local Value本地值），没有设置的属性就不存。那属性的默认值存放在哪？既然各个实例的默认值都一样（不然也不叫默认值了），那么直接存放到静态成员变量（<span style="background-color: yellow">依赖属性的静态成员变量，而不是注册依赖属性的类的成员变量</span>）上就行了。这也就大大提高了存储的效率。</p><p>在实现上，Silverlight中所有的UI元素都继承自DependencyObject，这个类封装了对依赖属性的存储以及访问等操作。</p><h3>注册依赖属性</h3><p>既然依赖属性采用键值对这样的哈希结构进行存储，那么要获取不同属性的值，我们就必须使用不同的哈希键，否则就会读取到其他属性的值了。因此，当我们在向Silverlight属性系统注册依赖属性的时候，Silverlight会返回一个唯一的属性标识对象，类型为DependencyProperty。我们以后就通过这个唯一标识对象去访问依赖属性的值。</p><p>由于这个唯一标识符是所有类实例都公用并且不会被修改的，因此我们通常将其保存到一个static readonly的成员变量中。</p><p>DependencyProperty类提供了两个方法，一个是Register方法，用于注册依赖属性；另外一个是RegisterAttached，用于注册附加属性，这个后面再讲。</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> DependencyProperty Register(
    <span class="kwrd">string</span> name,
    Type propertyType,
    Type ownerType,
    PropertyMetadata typeMetadata
)</pre></p><p>Register方法的签名由几部分组成，Name参数指明了依赖属性使用的名称，这个名字很重要，<strong><font color="#008000">在定义控件Style和Template的时候，Setter的Property属性填入的值就是注册依赖属性时使用的名称</font></strong>；propertyType指明了依赖属性实际的类型，ownerType指明了是哪个类注册了此依赖属性，最后typeMetadata存放了一些依赖属性的元信息，包括依赖属性使用的默认值，还有属性值发生变更时的通知函数。</p><h3><strong><font color="#2c68a3" size="3">属性的存取</font></strong></h3><p>和CLR属性不同，依赖属性不是直接对私有变量的操纵，而是通过GetValue和SetValue的方法来操作属性值的。</p><p>&#160;</p><p>下面的代码演示了为Ball控件设置一个Center的依赖属性，并且在程序中读取和修改此属性的过程：</p><pre class="csharpcode">

<span class="kwrd">public</span> <span class="kwrd">class</span> Ball : Control
{
    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> DependencyProperty CenterProperty =
        DependencyProperty.Register(<span class="str">&quot;Center&quot;</span>, <span class="kwrd">typeof</span>(Point), <span class="kwrd">typeof</span>(Ball), <span class="kwrd">null</span>);
}

<span class="kwrd">public</span> <span class="kwrd">class</span> BallApp
{
    <span class="kwrd">public</span> <span class="kwrd">void</span> RollBall(Ball ball)
    {
        Point curCenter = (Point)ball.GetValue(Ball.CenterProperty);
        curCenter.X++;

        // 注意对值类型对象操作完毕之后一定要调用SetValue修改才能生效
        ball.SetValue(Ball.CenterProperty, curCenter);
    }
}
</pre><p>由于上述对依赖属性的操作经常需要涉及到类型的转换，比较麻烦，而传统CLR属性用起来和直接操纵普通变量一样方便，因此通常在设计依赖属性的时候，都会使用CLR属性将其包装起来，我们称之为增强型的CLR属性。</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Ball : Control
{
    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> DependencyProperty CenterProperty =
        DependencyProperty.Register(<span class="str">&quot;Center&quot;</span>, <span class="kwrd">typeof</span>(Point), <span class="kwrd">typeof</span>(Ball), <span class="kwrd">null</span>);

    <span class="kwrd">public</span> Point Center
    {
        get { <span class="kwrd">return</span> (Point)GetValue(CenterProperty); }
        set { SetValue(CenterProperty, <span class="kwrd">value</span>); }
    }
}</pre><p>按照约定，依赖属性的名称通常是相应CLR属性名称后面加上个“Property”字符串。</p><p>事实上，使用CLR包装依赖属性并不只是为了方便（<a title="http://msdn.microsoft.com/en-us/library/cc221408%28VS.95%29.aspx#back_dependency_properties" href="http://msdn.microsoft.com/en-us/library/cc221408%28VS.95%29.aspx#back_dependency_properties">http://msdn.microsoft.com/en-us/library/cc221408%28VS.95%29.aspx#back_dependency_properties</a>），很多依赖于CLR属性作为基础的工具或者子系统并不能直接访问依赖属性，而只能通过CLR属性去间接访问依赖属性。例如上面的例子中，假设我们并没有设置一个Center的CLR属性，那么以下的Xaml将会编译失败，因为Xaml解析器无法知道Ball类有一个Center的依赖属性（在Style中设置Center属性值就可以编译成功，因为Style是动态查找属性的）。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Ball</span> <span class="attr">Center</span><span class="kwrd">=&quot;2&quot;</span> <span class="kwrd">/&gt;</span></pre><h2>依赖属性的寻值逻辑和值变更通知</h2><p>上面提到的只是依赖属性相比CLR属性在存储效率的不同，实际上，依赖属性还有其他实用的特性。</p><h3>寻值逻辑</h3><p>CLR属性在获取值的时候是直接读取成员变量值返回的，而依赖属性在使用的时候是通过GetValue函数的调用来获取属性的值。实际上，GetValue内部做的事情可不止是简单的读取字典里头存放的值。他还有寻值逻辑。如下图所示：</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="依赖属性GetValue寻值逻辑" border="0" alt="依赖属性GetValue寻值逻辑" src="http://www.imkevinyang.com/wp-content/uploads/2010/03/image2.png" width="373" height="224" /></p><p>当你调用GetValue去读取一个依赖属性的值的时候，Silverlight的属性系统会首先从动画系统中查找当前是否有作用在此依赖属性上的动画，如果有，则返回此动画值。从这里也可以看出，依赖属性是Silverlight实现动画机制的基础。<span style="background-color: yellow">注意，如果动画已经停止了，并且没有设置FillBehavior=HoldEnd的话，那么Silverlight就不会返回此动画值。</span></p><p><span style="background-color: yellow"></span></p><p>如果读不到动画值，那么Silverlight就会尝试读取本地值。本地值有几种类型，一种是用户通过代码或者Xaml直接设定的值。一种是通过资源绑定得到的值，最后一种是通过数据绑定得到的值。这些都被视为本地值。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">StackPanel</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">StackPanel.Resources</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">System:String</span> <span class="attr">x:Key</span><span class="kwrd">=&quot;TextBlockResource&quot;</span><span class="kwrd">&gt;</span>资源数据绑定文本<span class="kwrd">&lt;/</span><span class="html">System:String</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">StackPanel.Resources</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">=&quot;{Binding Source={StaticResource TextBlockResource}}&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;DataBindingElement&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;{Binding ElementName}&quot;</span> <span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre><p>如果还是读取不到，那么就继续尝试读取控件模板和样式中设置的值。</p><p>如果所有这些值都读取失败，那么Silverlight属性系统就会返回该依赖属性的默认值。当我们注册依赖属性的时候，可以传入一个PropertyMetaData对象，这个对象包含了此依赖属性的默认值和值变更通知回调函数。如果注册的时候没有传入默认值，则对于引用类型的依赖属性，返回null，对于字符串，返回String.Empty，对于值类型，则返回一个以默认值初始化的实例。</p><p><span style="background-color: yellow">这里需要对集合类型特别注意，由于通过PropertyMetaData传入的默认值是所有类实例共享的，因此，一定要在类构造函数中显式传入集合的实例</span>。</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> GameRoom : Control
{
    <span class="kwrd">public</span> List&lt;Ball&gt; Balls
    {
        get { <span class="kwrd">return</span> (List&lt;Ball&gt;)GetValue(BallsProperty); }
        set { SetValue(BallsProperty, <span class="kwrd">value</span>); }
    }

    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> DependencyProperty BallsProperty =
        DependencyProperty.Register(<span class="str">&quot;Balls&quot;</span>, <span class="kwrd">typeof</span>(List&lt;Ball&gt;), <span class="kwrd">typeof</span>(GameRoom), <span class="kwrd">null</span>);

    <span class="kwrd">public</span> GameRoom()
    {
        Balls = <span class="kwrd">new</span> List&lt;Ball&gt;();
    }
}</pre><p>可能正是因为Silverlight的依赖属性在获取值的时候需要从多个地方去读取值，而不是像CLR属性一样，直接从成员变量中读取值，所以才被称之为“依赖”属性吧。</p><h3>值变更通知</h3><p>属性值的变更通知我们并不陌生。我们在DotNet中实现的时候，一般是让类实现INotifyPropertyChanged接口。在UI系统中，值变更通知是经常需要用到的。数据源一旦变更，所有相应的UI元素的值都要相应的做出调整。Silverlight的依赖属性对此有内置的支持。只要你在绑定时使用依赖属性，那么当依赖属性值发生变更的时候，所有绑定的地方的值都会同步更新。而且，依赖属性也提供了一个值变更通知函数（在注册依赖属性时通过PropertyMetaData传入），你可以自定义一个函数来控制值变更时需要执行的操作。</p><pre class="csharpcode">

<span class="kwrd"></span>&#160;

<span class="kwrd">public</span> <span class="kwrd">class</span> Ball : Control
{
    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> DependencyProperty CenterProperty =
        DependencyProperty.Register(<span class="str">&quot;Center&quot;</span>, <span class="kwrd">typeof</span>(Point), <span class="kwrd">typeof</span>(Ball), <span class="kwrd">new</span> PropertyMetadata(OnCenterChanged));

    <span class="kwrd">public</span> Point Center
    {
        get { <span class="kwrd">return</span> (Point)GetValue(CenterProperty); }
        set { SetValue(CenterProperty, <span class="kwrd">value</span>); }
    }

    <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> OnCenterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Ball ball = d <span class="kwrd">as</span> Ball;
        <span class="rem">// 获取新的球心</span>
        Point newCenter = (Point)e.NewValue;
        <span class="rem">// ...</span>
    }
}
</pre><h2>Silverlight的附加属性（Attached Property）——全局的依赖属性</h2><p>刚才提到的依赖属性和CLR属性一样都是服务于某一个类的。只不过将属性改造得存储上更有效率，使用上更加强大。在Silverlight中还有一种特殊的依赖属性，这种依赖属性并不只是服务于某个特定的类，而是服务于全局，这就是附加属性。从名字上也可以看出来，附加属性是在某个类里面注册，然后可以被其他类所使用。</p><p>什么情况下需要使用附加属性呢？举Canvas类的ZIndex属性作为例子。</p><p>容器类在叠加子控件的时候，需要考虑哪个控件放置在最上面，那个放在下面。</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/03/image3.png" width="202" height="203" /></p><p>那么容器类怎么知道子控件的叠放顺序呢？最不动脑子的设计就是为所有的控件都添加一个ZIndex的属性，属性的值代表叠放的顺序。但这样的后果就是，如果我这个控件不参与布局，那多这个属性就会显得很浪费。所以比较理想的设计是，需要用到这个属性的时候就有这个属性，不需要的时候就没有这个属性的负担。附加属性的出现就是为了解决这样的问题。一旦控件需要某个属性的时候，我们可以把这个属性附加到这个控件类上。</p><p>注册附加属性和依赖属性差不多，只不过函数名为RegisterAttached。这个就不多说了。</p><h2>什么时候应该用到依赖属性</h2><p>既然依赖属性那么高效，而且那么强大，那么我们是不是应该保持使用依赖属性的习惯呢？事实上，任何好处都是有代价的。Silverlight的依赖属性在访问效率上并不如直接访问成员变量那么高效。因此，对于那些比较简单而访问频率又非常高的属性，建议还是使用传统的CLR属性去实现。</p><p>&#160;</p><p>暂时想到这么多了，以后有新的认识再补充补充。</p><p style="text-align: right">——<a title="Silverlight的依赖属性与附加属性" href="http://www.imkevinyang.com/2010/03/Silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/tags/attachedproperty" title="AttachedProperty" rel="tag">AttachedProperty</a>, <a href="http://www.imkevinyang.com/tags/clr%e5%b1%9e%e6%80%a7" title="CLR属性" rel="tag">CLR属性</a>, <a href="http://www.imkevinyang.com/tags/dependancyproperty" title="DependancyProperty" rel="tag">DependancyProperty</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7" title="依赖属性" rel="tag">依赖属性</a>, <a href="http://www.imkevinyang.com/tags/%e5%80%bc%e5%8f%98%e6%9b%b4" title="值变更" rel="tag">值变更</a>, <a href="http://www.imkevinyang.com/tags/%e5%af%bb%e5%80%bc" title="寻值" rel="tag">寻值</a>, <a href="http://www.imkevinyang.com/tags/%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7" title="附加属性" rel="tag">附加属性</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html" title="图片等资源的引用路径问题 (2009/03/19)">图片等资源的引用路径问题</a> (2009/03/19)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%9c%a8xaml%e4%b8%ad%e8%be%93%e5%85%a5%e5%b0%96%e6%8b%ac%e5%8f%b7%e6%96%87%e6%9c%ac.html" title="在Xaml中输入尖括号文本 (2009/02/28)">在Xaml中输入尖括号文本</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%b0%86silverlight%e6%90%ac%e5%88%b0%e6%a1%8c%e9%9d%a2.html" title="将Silverlight搬到桌面 (2009/02/28)">将Silverlight搬到桌面</a> (2009/02/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html/feed</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Silverlight启用Assembly Caching之后铁通用户无法访问</title><link>http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html</link> <comments>http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html#comments</comments> <pubDate>Sat, 13 Feb 2010 05:24:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[Assembly Caching]]></category> <category><![CDATA[HTTP]]></category> <category><![CDATA[HTTP Watch]]></category> <category><![CDATA[跨域]]></category> <category><![CDATA[重定向]]></category> <category><![CDATA[铁通]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html</guid> <description><![CDATA[<p>去年年底的时候，有客户向我们公司反映，他在自己公司内网（铁通ADSL）无法访问我们的Silverlight应用程序，而在他家里（网通ADSL）就可以正常访问。我们其他的客户并没有反映过类似的问题。</p><h2>问题分析排查</h2><p>由于他用的是笔记本，在家里和在公司访问时的系统环境是一样的，这样也就排除了系统环境的原因。那只能怀疑是网络环境的问题了。后来在现场使用HTTP Watch调试发现，当Silverlight在下载其中几个缓存程序集的zip包（我们的Si&#8230;</p>]]></description> <content:encoded><![CDATA[<p>去年年底的时候，有客户向我们公司反映，他在自己公司内网（铁通ADSL）无法访问我们的Silverlight应用程序，而在他家里（网通ADSL）就可以正常访问。我们其他的客户并没有反映过类似的问题。</p><h2>问题分析排查</h2><p>由于他用的是笔记本，在家里和在公司访问时的系统环境是一样的，这样也就排除了系统环境的原因。那只能怀疑是网络环境的问题了。后来在现场使用HTTP Watch调试发现，当Silverlight在下载其中几个缓存程序集的zip包（我们的Silverlight应用程序启用了Assembly Caching）时，HTTP请求被302永久重定向到一个奇怪的IP上。</p><p><img style="display: inline; border-width: 0px;" title="Silverlight启用Assembly Caching之后铁通用户无法访问" src="http://www.imkevinyang.com/wp-content/uploads/2010/02/image.png" border="0" alt="Silverlight启用Assembly Caching之后铁通用户无法访问" width="564" height="148" /></p><p>这样，由于zip包和Xap包地址的主机域不同，构成跨域，Silverlight会要求zip包所在的网站提供clientaccesspolicy.xml或者crossdomain.xml文件。而那个奇怪的IP所在网站下根本就没有这两个文件，所以请求失败。进而导致整个程序挂掉。</p><h2>Assembly Caching程序集缓存</h2><p>Assembly Caching（又称Application Library Caching）是Silverlight 3的新特性。以前Silverlight都是将所有用到的dll放到一个xap包之中，这样整个xap包会很大，下载相对比较慢。启用Assembly Caching之后，Silverlight工程用到的dll就可以在编译的时候自动打包到各自的zip包中，然后Silverlight在加载Xap包之后会自动下载这些zip包并解压出里头的dll，然后加载到应用程序域中。这样一来可以大大提高程序集下载的并行度，同时也可以使到不同Silverlight程序之间可以利用浏览器缓存而无需重复下载。</p><p>Silverlight在加载Xap包之后会去读取xap包中的appmanifest.xaml文件，然后下载该文件中指定的程序集文件。如果程序集文件Url和当前Xap包Url构造跨域（参考Silverlight SDK文档），则Silverlight会向该程序集所在网站的根目录请求跨域策略文件。</p><h2>为什么会被重定向</h2><p>这个问题困扰了我们很久。当时我们的第一反应是怀疑网关设置了什么规则。当用户访问特定Url的时候，触发了这个规则，导致HTTP请求被挟持。但是和客户公司网管沟通之后，对方明确表示并没有设置过类似的规则。</p><p>直到最近，客户和电信通（率属铁通）的人沟通之后，那边的技术人员说这是由于铁通的缓存加速服务器造成。据说是铁通为了让用户下载更快，就将某些HTTP请求进行重定向。后来电信通的技术人员告诉客户他们已经没问题了，但是他们并没有告知详细的问题所在，到底是由于我们的HTTP请求碰巧符合特定规则，还是怎么回事。也不知道他们是怎么解决的，是只将客户公司的IP列入禁止缓存列表，还是将我们Silverlight应用程序使用的域名加入禁止缓存列表，我们都无从知道。对于我们来说，这并没有真正解决问题。如果将来其他客户也通过铁通访问我们的产品，那么可能还是会出现类似的问题。由于我家里也是铁通的网络，所以我决定自己研究一下到底是怎么回事。</p><p>由于铁通那边没有任何可用的技术信息，Google也没有找到有价值的信息，唯一猜测的就是HTTP请求可能符合特定规则然后就被无辜重定向了。因此我只能采用最原始的人肉测试了。尝试不断的调整出问题的Url然后看是否被重定向了来发现规律。修改zip包所在目录，修改zip包文件名，修改zip包后缀，修改IIS的MIME类型，测试不同域名，等等。在历经100多次尝试之后，终于发现了<strong><span style="color: #008000;">当文件大小超过40K左右，并且后缀名是zip或者rar等常见的下载文件后缀，就会被铁通重定向。而且有时候第一、二次不会被重定向，刷新多几次的时候就才会被重定向</span></strong>。后面一点让我走了不少弯路，多少次我以为找到规律了，最后验证结论的时候还是错了。</p><p>o(︶︿︶)o</p><h2>怎么解决</h2><p>知道具体问题所在之后，我们几个技术人员就开始讨论如何解决这个问题。由于Silverlight对于缓存程序集打包之后的文件后缀没有要求，不管什么后缀，都会以zip文件流的格式去解析。因此可以修改打包文件的后缀来“逃过”铁通的魔掌。</p><p>修改文件后缀也有两种方法。</p><p>一种是在部署的时候，通过自动化脚本，修改所有zip文件后缀，然后修改xap包中appmanifest.xaml里头程序集的Url。这种方式的好处是一劳永逸，通用性强，以后部署的时候只需要执行一次脚本即可，其他应用程序可以共用。缺点是脚本编写比较复杂，并且部署的时候需要多加一步。</p><p>另外一种方法是将用到的Silverlight系统程序集放到工程底下，然后修改同名的xml配置文件，使其打包的文件使用其他后缀名。好处是这样编译完之后就可以直接部署了，无需执行什么操作，也不需要写脚本。坏处就是首先需要修改所有现有的工程，而且以后如果要开发新的Silverlight应用，也要记得这么做。</p><p>不管怎么样，这两种方法都不简单。后来我就想，既然客户可以和电信通联系，为什么我不可以直接和铁通联系呢。我就上网搜了一下北京铁通客户中心，找到申诉通道，填写完整的申述理由。然后第二天又打他们的客服电话去骚扰他们。结果过了两天，申述结果就下来了，“问题已解决”。对方客服还本着能自己动手决不麻烦别人的精神，帮我填写了用户满意度一栏：“非常满意”。</p><h2>更深层的东西</h2><p>其实最终解决问题的办法非常简单，就是投诉。我不满意你的服务，我就有权利投诉你。可是为什么一开始没有意识到这种解决办法呢？</p><p>我觉得这是和我们接触的社会环境有很大关系。我们潜意识里头已经习惯了各种中国式的流氓。运营商喜欢往你访问的网站中插播广告，访问我自己的博客偶尔还有弹窗广告；上Google搜索技术资料，一不小心点了blogspot的链接就导致Google被重置了，然后就10分钟不可用。没有明文规定告诉你什么是被禁止的，我们只能人肉测试。我们除了接受、适应并绕过这种事实之外还能做什么？也许我们还可以发出几声“中国式的抗议”吧。</p><p>言多必封，不多说了。</p><p style="text-align: right;">——<a title="Silverlight启用Assembly Caching之后铁通用户无法访问" href="http://www.imkevinyang.com/2010/02/Silverlight%e5%90%af%e7%94%a8Assembly%20Caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/tags/assembly-caching" title="Assembly Caching" rel="tag">Assembly Caching</a>, <a href="http://www.imkevinyang.com/tags/http" title="HTTP" rel="tag">HTTP</a>, <a href="http://www.imkevinyang.com/tags/http-watch" title="HTTP Watch" rel="tag">HTTP Watch</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/%e8%b7%a8%e5%9f%9f" title="跨域" rel="tag">跨域</a>, <a href="http://www.imkevinyang.com/tags/%e9%87%8d%e5%ae%9a%e5%90%91" title="重定向" rel="tag">重定向</a>, <a href="http://www.imkevinyang.com/tags/%e9%93%81%e9%80%9a" title="铁通" rel="tag">铁通</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2010/05/64%e4%bd%8d%e7%b3%bb%e7%bb%9f%e4%b8%8biis7-isapi%e5%a4%84%e7%90%86%e5%99%a8%e5%8a%a0%e8%bd%bd%e5%a4%b1%e8%b4%a5.html" title="64位系统下IIS7 ISAPI处理器加载失败 (2010/05/05)">64位系统下IIS7 ISAPI处理器加载失败</a> (2010/05/05)</li><li><a href="http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html" title="Asp.Net页面的编码问题 (2009/11/27)">Asp.Net页面的编码问题</a> (2009/11/27)</li><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2009/11/%e3%80%90%e6%8e%a8%e8%8d%90%e3%80%91%e4%b8%a4%e6%ac%behttp%e6%b5%81%e9%87%8f%e5%88%86%e6%9e%90%e5%b7%a5%e5%85%b7%e7%9a%84%e6%af%94%e8%be%83.html" title="【推荐】两款HTTP流量分析工具的比较 (2009/11/08)">【推荐】两款HTTP流量分析工具的比较</a> (2009/11/08)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>解决Xaml中包含中文导致无法编译的问题</title><link>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3xaml%e4%b8%ad%e5%8c%85%e5%90%ab%e4%b8%ad%e6%96%87%e5%af%bc%e8%87%b4%e6%97%a0%e6%b3%95%e7%bc%96%e8%af%91%e7%9a%84%e9%97%ae%e9%a2%98.html</link> <comments>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3xaml%e4%b8%ad%e5%8c%85%e5%90%ab%e4%b8%ad%e6%96%87%e5%af%bc%e8%87%b4%e6%97%a0%e6%b3%95%e7%bc%96%e8%af%91%e7%9a%84%e9%97%ae%e9%a2%98.html#comments</comments> <pubDate>Tue, 29 Sep 2009 04:41:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[Xaml]]></category> <category><![CDATA[Xml]]></category> <category><![CDATA[中文]]></category> <category><![CDATA[字符集]]></category> <category><![CDATA[编译错误]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/10/%e8%a7%a3%e5%86%b3xaml%e4%b8%ad%e5%8c%85%e5%90%ab%e4%b8%ad%e6%96%87%e5%af%bc%e8%87%b4%e6%97%a0%e6%b3%95%e7%bc%96%e8%af%91%e7%9a%84%e9%97%ae%e9%a2%98.html</guid> <description><![CDATA[<p>最近同事在编译工程的时候发现一个奇怪的Xml验证错误，提示信息是The &#34;ValidateXaml&#34; task failed unexpectedly。检查了半天发现是Generic.xaml文件中的中文字符导致的。只要在文件中写了中文，那么就会出现这个编译错误。即使注释了也是一样的错误。</p><p>这就奇怪了，按理说Xaml中是可以直接写中文的。想了一下，这个情况和我之前遇到的脚本字符集的问题类似（参考：<a title="文档字符集导致的脚本错误" href="http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html" target="_blank">文档字符集导致的脚本错误</a>）。我&#8230;</p>]]></description> <content:encoded><![CDATA[<p>最近同事在编译工程的时候发现一个奇怪的Xml验证错误，提示信息是The &quot;ValidateXaml&quot; task failed unexpectedly。检查了半天发现是Generic.xaml文件中的中文字符导致的。只要在文件中写了中文，那么就会出现这个编译错误。即使注释了也是一样的错误。</p><p>这就奇怪了，按理说Xaml中是可以直接写中文的。想了一下，这个情况和我之前遇到的脚本字符集的问题类似（参考：<a title="文档字符集导致的脚本错误" href="http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html" target="_blank">文档字符集导致的脚本错误</a>）。我查看了一下这个Generic.xaml文件的字符集，发现是GB2312，改成UTF-8之后，成功编译，问题解决。</p><p>问题的原因就在于，文件本身使用的字符集和它声明的字符集不一致，这样导致解析这个Xaml文件的xml解析器在对字节流（假设该字节流是使用gb2312进行编码的）进行解码（假设xml解析器使用UTF-8字符集对字节流进行解码的）的时候会出现一些意想不到的字符，从而使到Xml解析出错，从而抛出上述的异常。例如一个本应该解析成闭合符&gt;的，结果被解析成其他字符。</p><p>知道这个原因之后我们要做的就是，保证文件存储的编码格式和它声明的编码格式一致即可。</p><p>如果允许，我们可以直接将文件存储格式改成UTF-8即可。否则，我们需要修改Xaml的字符集声明。由于Xaml也是xml，因此我们可以在文件中加上xml声明头，如下：</p><pre class="csharpcode"><span class="kwrd">&lt;?</span><span class="html">xml</span> <span class="attr">version</span><span class="kwrd">=&quot;1.0&quot;</span> <span class="attr">encoding</span><span class="kwrd">=&quot;gb2312&quot;</span> ?<span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">ResourceDictionary</span>
    <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span>
    <span class="attr">xmlns:x</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span><span class="kwrd">&gt;</span>
    <span class="rem">&lt;!--测试--&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">ResourceDictionary</span><span class="kwrd">&gt;</span></pre><p>不过建议还是使用标准的UTF-8格式来表示Xml，这样兼容性更好一些。</p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/xaml" title="Xaml" rel="tag">Xaml</a>, <a href="http://www.imkevinyang.com/tags/xml" title="Xml" rel="tag">Xml</a>, <a href="http://www.imkevinyang.com/tags/%e4%b8%ad%e6%96%87" title="中文" rel="tag">中文</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e7%ac%a6%e9%9b%86" title="字符集" rel="tag">字符集</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%96%e8%af%91%e9%94%99%e8%af%af" title="编译错误" rel="tag">编译错误</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html" title="Asp.Net页面的编码问题 (2009/11/27)">Asp.Net页面的编码问题</a> (2009/11/27)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%9c%a8xaml%e4%b8%ad%e8%be%93%e5%85%a5%e5%b0%96%e6%8b%ac%e5%8f%b7%e6%96%87%e6%9c%ac.html" title="在Xaml中输入尖括号文本 (2009/02/28)">在Xaml中输入尖括号文本</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%ad%97%e7%ac%a6%e7%bc%96%e8%a7%a3%e7%a0%81%e7%9a%84%e6%95%85%e4%ba%8b%ef%bc%88ascii%ef%bc%8cansi%ef%bc%8cunicode%ef%bc%8cutf-8%e5%8c%ba%e5%88%ab%ef%bc%89.html" title="字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别） (2009/02/28)">字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/11/%e5%ad%97%e7%ac%a6%ef%bc%8c%e5%ad%97%e8%8a%82%e5%92%8c%e7%bc%96%e7%a0%81.html" title="字符，字节和编码 (2009/11/27)">字符，字节和编码</a> (2009/11/27)</li><li><a href="http://www.imkevinyang.com/2010/05/%e5%bd%93google-analytics%e3%80%81firefox%e5%92%8ciis%e8%b5%b0%e5%88%b0%e4%ba%86%e4%b8%80%e8%b5%b7.html" title="当Google Analytics、Firefox和IIS走到了一起&#8230; (2010/05/29)">当Google Analytics、Firefox和IIS走到了一起&#8230;</a> (2010/05/29)</li><li><a href="http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html" title="文档字符集导致的脚本错误 (2009/08/19)">文档字符集导致的脚本错误</a> (2009/08/19)</li><li><a href="http://www.imkevinyang.com/2009/08/%e8%af%a6%e8%a7%a3javascript%e4%b8%ad%e7%9a%84url%e7%bc%96%e8%a7%a3%e7%a0%81.html" title="详解Javascript中的Url编码/解码 (2009/08/19)">详解Javascript中的Url编码/解码</a> (2009/08/19)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3xaml%e4%b8%ad%e5%8c%85%e5%90%ab%e4%b8%ad%e6%96%87%e5%af%bc%e8%87%b4%e6%97%a0%e6%b3%95%e7%bc%96%e8%af%91%e7%9a%84%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Blend小贴士&#8212;&#8212;改变鼠标滚轮的默认行为</title><link>http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html</link> <comments>http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html#comments</comments> <pubDate>Fri, 18 Sep 2009 04:47:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[Blend]]></category> <category><![CDATA[Tips]]></category> <category><![CDATA[小贴士]]></category> <category><![CDATA[缩放]]></category> <category><![CDATA[鼠标滚轮]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/10/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html</guid> <description><![CDATA[<p>使用Blend的一个最大的别扭之处就在于它默认情况下滚轮的作用是放大缩小，而不是我们熟悉的滚动屏幕。还好这个默认行为是可以修改的。在菜单Tool=&#62;Options=&#62;Artboard中找到Mouse Wheel一节，将其改成Ctrl+滚动即可。以后滚轮就是滚动屏幕的作用，Ctrl+滚轮才是缩放。</p><p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Blend 3 Zoom by Mouse Wheel" border="0" alt="Blend 3 Zoom by Mouse Wheel" src="http://www.imkevinyang.com/wp-content/uploads/2009/10/image_thumb4.png" width="226" height="55" /></p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/tags/blend" title="Blend" rel="tag">Blend</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/tips" title="Tips" rel="tag">Tips</a>, <a href="http://www.imkevinyang.com/tags/%e5%b0%8f%e8%b4%b4%e5%a3%ab" title="小贴士" rel="tag">小贴士</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%a9%e6%94%be" title="缩放" rel="tag">缩放</a>, <a href="http://www.imkevinyang.com/tags/%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae" title="鼠标滚轮" rel="tag">鼠标滚轮</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的&#8230;</h4>]]></description> <content:encoded><![CDATA[<p>使用Blend的一个最大的别扭之处就在于它默认情况下滚轮的作用是放大缩小，而不是我们熟悉的滚动屏幕。还好这个默认行为是可以修改的。在菜单Tool=&gt;Options=&gt;Artboard中找到Mouse Wheel一节，将其改成Ctrl+滚动即可。以后滚轮就是滚动屏幕的作用，Ctrl+滚轮才是缩放。</p><p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Blend 3 Zoom by Mouse Wheel" border="0" alt="Blend 3 Zoom by Mouse Wheel" src="http://www.imkevinyang.com/wp-content/uploads/2009/10/image_thumb4.png" width="226" height="55" /></p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/tags/blend" title="Blend" rel="tag">Blend</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/tips" title="Tips" rel="tag">Tips</a>, <a href="http://www.imkevinyang.com/tags/%e5%b0%8f%e8%b4%b4%e5%a3%ab" title="小贴士" rel="tag">小贴士</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%a9%e6%94%be" title="缩放" rel="tag">缩放</a>, <a href="http://www.imkevinyang.com/tags/%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae" title="鼠标滚轮" rel="tag">鼠标滚轮</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html" title="Sql Tips——Update语句也使用表别名(Table Alias) (2010/07/02)">Sql Tips——Update语句也使用表别名(Table Alias)</a> (2010/07/02)</li><li><a href="http://www.imkevinyang.com/2009/09/visual-studio%e5%b0%8f%e8%b4%b4%e5%a3%ab%e5%8a%a0%e4%ba%86try-catch%e4%b9%9f%e8%83%bd%e8%87%aa%e5%8a%a8%e5%ae%9a%e4%bd%8d%e5%88%b0%e5%bc%82%e5%b8%b8%e4%bb%a3%e7%a0%81.html" title="Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码 (2009/09/18)">Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html" title="图片等资源的引用路径问题 (2009/03/19)">图片等资源的引用路径问题</a> (2009/03/19)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>解决Silverlight引用中文字体的问题</title><link>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e5%bc%95%e7%94%a8%e4%b8%ad%e6%96%87%e5%ad%97%e4%bd%93%e7%9a%84%e9%97%ae%e9%a2%98.html</link> <comments>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e5%bc%95%e7%94%a8%e4%b8%ad%e6%96%87%e5%ad%97%e4%bd%93%e7%9a%84%e9%97%ae%e9%a2%98.html#comments</comments> <pubDate>Mon, 07 Sep 2009 16:34:19 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[中文字体]]></category> <category><![CDATA[字体]]></category> <category><![CDATA[字体打包]]></category> <category><![CDATA[引用]]></category> <category><![CDATA[本地字体]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e5%bc%95%e7%94%a8%e4%b8%ad%e6%96%87%e5%ad%97%e4%bd%93%e7%9a%84%e9%97%ae%e9%a2%98.html</guid> <description><![CDATA[<h2>问题描述</h2><p>在Silverlight程序中，对文字设置了中文字体之后不起任何作用。</p><h2>问题分析</h2><p>Silverlight内置了十几种常见拉丁字体，如Arial，Comic Sans MS，Courier New，Lucida Sans Unicode等。默认使用的字体是Portable User Interface。这是一种复合字体，Silverlight会根据文字的语言选择最佳的字体。但是，这种字体通常在显示中文的时候非常难看。下图是默认的显示效果：</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb6.png" width="404" height="51" /></p><p>所以，我们&#8230;</p>]]></description> <content:encoded><![CDATA[</p><h2>问题描述</h2><p>在Silverlight程序中，对文字设置了中文字体之后不起任何作用。</p><h2>问题分析</h2><p>Silverlight内置了十几种常见拉丁字体，如Arial，Comic Sans MS，Courier New，Lucida Sans Unicode等。默认使用的字体是Portable User Interface。这是一种复合字体，Silverlight会根据文字的语言选择最佳的字体。但是，这种字体通常在显示中文的时候非常难看。下图是默认的显示效果：</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb6.png" width="404" height="51" /></p><p>所以，我们需要在程序中手动指定文字的字体。</p><h3>三种字体引用方式</h3><p>如果使用的字体是Silverlight内置支持的，那么无需做任何配置，直接指定FontFamily即可。内置的字体有Arial，Arial Black，Comic Sans MS，Courier New，Lucida Sans Unicode，Times New Roman，Georgia，Trebuchet MS，Verdana和Webdings。使用这些字体不依赖于客户端操作系统。</p><p>同时Silverlight也支持引用本地系统一部分字体（注意，不是全部本地字体都支持）。如Segoe UI，Symbol，Tahoma，宋体，等等。使用这些字体需要注意，其他客户端系统中可能不存在这些字体，如英文操作系统一般没有宋体。那么如果你使用了宋体那就会有问题。</p><p>如果你需要让Silverlight应用程序在不同系统下都有一致的字体，或者你想用某些字体，但是这些字体不支持本地引用（如隶书），那么Silverlight允许你将字体文件打包到应用程序中，可以放在Xap包中，也可以放在ClientBin目录下，然后在代码中动态下载并引用这些字体文件。这样牺牲的代价就是Xap包会变得较大。</p><p>为了更好显示中文，我需要为上面的文字显式指定使用“宋体”。代码如下：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span> <span class="attr">Background</span><span class="kwrd">=&quot;White&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">=&quot;Hello，测试中英文混合显示效果&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;26&quot;</span> <span class="attr">FontFamily</span><span class="kwrd">=&quot;宋体&quot;</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">Grid</span><span class="kwrd">&gt;</span></pre><p>Ctrl+F5运行，却发现字体没有发生明显的变化。说明字体的设置不起作用。我又测试了一下将宋体打包到应用程序中。为了简单，我使用Blend3帮我自动完成这个操作。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Blend 3中字体打包" border="0" alt="Blend 3中字体打包" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb7.png" width="246" height="140" /></p><p>选中一种字体之后，勾选字体面板下面的Embed复选框即可将指定字体打包到Silverlight工程中去。这个时候工程中自动生成了Fonts文件夹，里面放置了宋体这个字体文件。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Visual Studio 打包字体" border="0" alt="Visual Studio 打包字体" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb8.png" width="165" height="112" /></p><p>同时，Xaml也发生了变化，由引用系统的宋体改成引用Fonts.zip包中的宋体了。如下：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span> <span class="attr">Background</span><span class="kwrd">=&quot;White&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">=&quot;Hello，测试中英文混合显示效果&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;26&quot;</span> <span class="attr">FontFamily</span><span class="kwrd">=&quot;Fonts/Fonts.zip#宋体&quot;</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">Grid</span><span class="kwrd">&gt;</span></pre><p>运行结果发现字体依旧。</p><p>后来查阅Silverlight官方文档的时候，看到字体列表一节时，突然想到，<strong><font color="#008000">是不是因为字体名不规范？不能直接使用“宋体”，而应该使用Simsun</font></strong>。赶紧测试了一下，发现果然是这个问题。只需将上面两个示例代码中的宋体改成Simsun即可正确显示出宋体的效果来。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb9.png" width="388" height="33" /></p><p>后来又测试了一下其它中文字体，如微软雅黑，如果直接这样写中文的话是显示不出来的，一定要写“Microsoft YaHei”。可恶的Blend，帮我自动生成的代码居然有这种莫名其妙的错。不知道这算是Silverlight和Blend的Bug还是设计使然。</p><h2>总结</h2><p>在Silverlight中，如果要引用字体，一定不能直接写上中文，否则不起任何作用。如果你是在英文操作系统下的话，你可以打开字体文件（C:\windows\fonts文件夹下，Silverlight支持ttf,odttf和otf这几种后缀的字体文件），其中的字体名称一栏就是FontFamily所使用的名称。只是在中文操作系统下，支持中文的字体在这里会显示为中文名，而不是英文名。</p><p><img style="border-bottom: 0px; border-left: 0px; margin: 0px; display: inline; border-top: 0px; border-right: 0px" title="FontFamily" border="0" alt="FontFamily" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb10.png" width="316" height="132" /></p><p>常见中文字体名和英文字体名的对应关系如下：</p><table border="1" cellspacing="0" cellpadding="0" height="400"><thead><tr><td colspan="2" align="center">常见中文字体与FontFamily映射表</td></tr></thead><tbody><tr><td valign="top" width="171">宋体（英文不等宽）</td><td valign="top" width="429">Simsun</td></tr><tr><td valign="top" width="171">宋体（英文等宽）</td><td valign="top" width="429">NSimsun</td></tr><tr><td valign="top" width="171">楷体</td><td valign="top" width="429">KaiTi</td></tr><tr><td valign="top" width="171">黑体</td><td valign="top" width="429">SimHei</td></tr><tr><td valign="top" width="171">仿宋</td><td valign="top" width="429">FangSong</td></tr><tr><td valign="top" width="171">微软正黑体</td><td valign="top" width="429">Microsoft JhengHei</td></tr><tr><td valign="top" width="171">细明体</td><td valign="top" width="429">MingLiu</td></tr><tr><td valign="top" width="171">微软雅黑</td><td valign="top" width="429">Microsoft YaHei</td></tr><tr><td valign="top" width="171">隶书</td><td valign="top" width="429">LiSu（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">华文彩云</td><td valign="top" width="429">STCaiyun（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">华文琥珀</td><td valign="top" width="429">STHupo（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">华文隶书</td><td valign="top" width="429">STLiti（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">华文新魏</td><td valign="top" width="429">STXinwei（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">华文行楷</td><td valign="top" width="429">STXingkai（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">幼圆</td><td valign="top" width="429">YouYuan（只能打包，不支持本地系统引用）</td></tr></tbody></table><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/%e4%b8%ad%e6%96%87%e5%ad%97%e4%bd%93" title="中文字体" rel="tag">中文字体</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e4%bd%93" title="字体" rel="tag">字体</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e4%bd%93%e6%89%93%e5%8c%85" title="字体打包" rel="tag">字体打包</a>, <a href="http://www.imkevinyang.com/tags/%e5%bc%95%e7%94%a8" title="引用" rel="tag">引用</a>, <a href="http://www.imkevinyang.com/tags/%e6%9c%ac%e5%9c%b0%e5%ad%97%e4%bd%93" title="本地字体" rel="tag">本地字体</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html" title="图片等资源的引用路径问题 (2009/03/19)">图片等资源的引用路径问题</a> (2009/03/19)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%9c%a8xaml%e4%b8%ad%e8%be%93%e5%85%a5%e5%b0%96%e6%8b%ac%e5%8f%b7%e6%96%87%e6%9c%ac.html" title="在Xaml中输入尖括号文本 (2009/02/28)">在Xaml中输入尖括号文本</a> (2009/02/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e5%bc%95%e7%94%a8%e4%b8%ad%e6%96%87%e5%ad%97%e4%bd%93%e7%9a%84%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>解决Silverlight无法调试的问题</title><link>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e6%97%a0%e6%b3%95%e8%b0%83%e8%af%95%e7%9a%84%e9%97%ae%e9%a2%98.html</link> <comments>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e6%97%a0%e6%b3%95%e8%b0%83%e8%af%95%e7%9a%84%e9%97%ae%e9%a2%98.html#comments</comments> <pubDate>Tue, 01 Sep 2009 06:26:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[疑难杂症]]></category> <category><![CDATA[Silverlight无法调试]]></category> <category><![CDATA[Visual Studio]]></category> <category><![CDATA[调试]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/08/%e8%a7%a3%e5%86%b3silverlight%e8%b0%83%e8%af%95%e7%8a%b6%e6%80%81%e4%b8%8b%e6%97%a0%e6%b3%95%e8%b7%9f%e8%bf%9b%e6%96%ad%e7%82%b9%e7%9a%84%e9%97%ae%e9%a2%98.html</guid> <description><![CDATA[<h2>问题描述</h2><p>在Silverlight开发过程中，经常时不时的会碰到Silverlight无法调试的问题。我就遇到下面几种情况：</p><p>1. Web Application+Silverlight，F5进入调试状态之后无法跟进Silverlight程序中下的断点</p><p>2. 项目中有两个Silverlight工程，其中一个Silverlight程序中有一个鼠标点击事件会将当前页面导航到另外一个Silverlight程序的承载页面。第一个Silverlight程序断&#8230;</p>]]></description> <content:encoded><![CDATA[<h2>问题描述</h2><p>在Silverlight开发过程中，经常时不时的会碰到Silverlight无法调试的问题。我就遇到下面几种情况：</p><p>1. Web Application+Silverlight，F5进入调试状态之后无法跟进Silverlight程序中下的断点</p><p>2. 项目中有两个Silverlight工程，其中一个Silverlight程序中有一个鼠标点击事件会将当前页面导航到另外一个Silverlight程序的承载页面。第一个Silverlight程序断点正常，但是第二个Silverlight程序中的断点不能自动停下来</p><p>3. 无论是在TestPage模式下调试还是在Web工程上调试，只要打开了Silverlight调试开关，那么启动的时候会提示“<strong><font color="#008000">Unable to start debugging. Cannot locate Microsoft Internet Explorer</font></strong>”。如果你是直接Ctrl+F5运行，有时候也会出现一样的问题。</p><h2>单个Silverlight工程无法调试</h2><p>对于第一个问题，请检查如下设置是否正确：</p><p>1. <strong><font color="#008000">确认启用了Silverlight调试</font></strong>。双击Asp.Net工程中的属性文件夹打开属性设置页，找到Web一栏，在此页卡的最下面有几个调试选项，如下图所示：</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/08/image_thumb5.png" width="166" height="116" /> <img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/08/image_thumb6.png" width="511" height="42" /></p><p>确认最后一项“Silverlight”之前的勾是勾上的。</p><p>2. <strong><font color="#008000">确保浏览器访问的Xap包是最新的</font></strong>。检查IE是否已经清除了缓存，或者ClientBin中的Xap因为某些原因没能更新（如因配置管理导致无法覆盖）</p><p>3. <strong><font color="#008000">检查Asp.Net工程是否绑定了Silverlight应用</font></strong>。可以通过asp.net工程的属性面板中的Silverlight Application页卡查看是否绑定成功。如下：</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Silverlight Applications Settings" border="0" alt="Silverlight Applications Settings" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb.png" width="331" height="204" /></p><p>4. <strong><font color="#008000">检查Silverlight工程的StartupObject是否设置正确</font></strong>。有时候我们对工程的命名空间进行重命名，会导致Silverlight应用程序的入口对象失效，从而导致无法启动等情况。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Silverlight Application Startup Object" border="0" alt="Silverlight Application Startup Object" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb1.png" width="453" height="131" /></p><h2>IE8下无法同时调试多个Silverlight工程？！</h2><p>IE8和以往的IE不大一样，它的多标签是采用多进程的方式来实现的。整个窗口是一个框架进程，每个Tab标签页是一个独立的子进程（实际上，IE8会根据内存动态控制Tab进程的数目，因此多个标签页可能会共存于同一个进程之中）。当你尝试在多个标签页中打开不同的Silverlight应用程序时，例如从SilverlightApplication1中打开新页面到SilverlightApplication2页面，这个时候你会发现，SilverlightApplication2应用程序无法调试。</p><p>这是因为，<strong><font color="#008000">Visual Studio除了启动窗口进程之外，不会自动帮我们Attach其他的包含Silverlight应用程序的进程，如果我们需要在多个标签页（或者多个窗口）中同时调试不同的Silverlight应用程序，那么我们必须自己手动Attach这些进程</font></strong>。</p><p>举个简单的例子，我有两个Silverlight工程，其中SilverlightApplication1中包含链接指向SilverlightApplication2页面，点击链接会在新标签页中打开SilverlightApplication2的承载页面。</p><p>为了Attach相应的进程，首先我们需要找到SilverlightApplication2承载页面对应的进程。打开ProcessExplorer，我们可以看到三个进程。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb2.png" width="232" height="59" /></p><p>其中的ID为4528的是父进程，也就是框架进程，用于管理不同的标签进程之间的通信等事务。5160和5248分别对应着两个标签页进程。至于哪个对应哪个我们在这里无法根据进程号确定。</p><p>我们再打开Visual Studio中的Attach窗口（菜单=&gt;Debug=&gt;Attach to process…）</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb3.png" width="510" height="185" /></p><p>这里列出了所有系统可用的进程清单，我们可以看到三个IE进程，其中一个是灰色的，这表示了这个进程已经被Attach到Visual Studio的调试器上了。排除了框架进程4258外，就剩下5248这个进程了，这个进程就是我们要找的SilverlightApplication2对应的承载页面的进程了。选中之后Attach到调试器上，我们发现，SilverlightApplication2中的断点还是显示为空心红圈，依然无法调试。</p><p>这是因为我们指定的进程代码类型不正确。我们注意到，上图中最上面有一个Attach to，后面显示的是Automatic，这个代表着Visual Studio的调试器会自动帮我们选择进程的调试类型，例如是托管代码调试，还是脚本调试，等等。我们选中5248这个进程，发现Visual Studio给我们选择的方式是脚本调试。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb4.png" width="504" height="144" /></p><p>在Visual Studio中，脚本调试和Silverlight调试是不能共存的，这也就是为什么有时候你按下F5的时候，Visual Studio会提示你，调试Silverlight程序会暂时关闭脚本调试的功能。因此在脚本调试下，我们无法跟进Silverlight应用程序的断点。</p><p>这里额外说一点，IE8高级选项中的禁用脚本调试设置对Visual Studio一点影响都没有，因为Visual Studio 2008在调试器启动的时候会自动启用脚本调试（可以通过注册表禁用此特性），除非在Web Application属性中打开了Silverlight调试。</p><p>回到刚才的问题，由于Visual Studio帮我们自动选择的调试类型有误，导致我们无法调试SilverlightApplication2，因此我们需要手动指定Attach类型。点击Attach to后侧的select按钮。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb5.png" width="308" height="211" /></p><p>在弹出的选择代码类型窗口中勾选上Silverlight。确定之后再次Attach，我们发现，这一次，断点真的起作用了。</p><p>当然，如果这种方式比较麻烦的话，我们也可以通过改变IE8的Tab进程创建方式来让不同标签页共存于一个进程中。在注册表HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main下面有一个TabProcGrowth键值（DWORD类型），当其设置为0时， IE框架和Tab工作在一个进程里面，Tab采用线程的方式创建，同时IE的保护模式（Protect Mode）会关闭。TabProcGrowth=1时IE框架和Tab工作在不同的进程里面。TabProcGrowth&gt;1时，此值将决定IE8最多创建的Tab进程数目。如果TabProcGrowth 不存在，则会根据可用的物理内存数量决定Tab进程的数量。</p><h2>调试时无法打开IE窗口的问题</h2><p>这个问题是我最近才遇到的，我也不知道为什么突然之间，我的Silverlight工程按下F5的时候无法调试，弹出下面这个对话框：Unable to start debugging. Cannot locate Microsoft Internet Explorer.</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb15.png" width="248" height="141" /></p><p>如果直接运行，那么能够打开，但是打开之后Visual Studio还是会弹出一样的错误。</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb16.png" width="257" height="134" /></p><p>这个问题折腾了我半天，我尝试了重启电脑，重装Silverlight Tools，新建干净的测试工程，修改系统和Visual Studio的默认浏览器（注意，系统和Visual Studio的默认浏览器是独立设置的）均以失败告终。Google了很久，Silverlight官方论坛上倒是有不少帖子和这个相关的，但我细细看了之后发现没有一个回帖能够解决我的问题的。有个发帖的家伙问题是解决了，但是不把怎么解决的说一下就跑了，强烈bs一下这种人！</p><p>话说回来，我最后是怎么解决这个问题的呢，是用了Process Monitor这个小工具（微软Sysinternal荣誉出品！）。之前有一次asp.net网站的GlobalError里头出现了一个“文件不存在”的HTTPException，查了半天没查出来，后来使用这个工具监视了一下WebDevServ.exe进程之后发现该进程尝试去访问某个不存在的文件。</p><blockquote><p>Process Monitor，可以监控当前系统中所有进程的活动，包括对文件系统的操作，读写注册表，网络访问以及线程活动等等，非常实用的调试维护工具。</p></blockquote><p>我打开这个工具，选择监视进程为devenv.exe。在Visual Studio中F5开始调试，立即弹出出错对话框，OK，把PM暂停一下，否则条目太多了。</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb17.png" width="298" height="98" /></p><p>但是事件条目还是太多了，所以我把Result为SUCCESS的条目过滤掉，因为我们只关注那些失败的条目。</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb18.png" width="271" height="171" /></p><p>然后对日志条目进行细致的排查，终于发现了问题根源：</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb19.png" width="546" height="45" /></p><p>原来Visual Studio在调试或者运行的时候会去读取注册表中的HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\iexplore.exe项，然后读取不到，因而才报那个错误。难怪提示Cannot locate Microsoft internet explorer呢。</p><p>我打开regedit注册表编辑器，找到这个路径，然后把缺失的项加上去，重新回到Visual Studio中F5，终于可以了，内牛满面~</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb20.png" width="330" height="156" /></p><p>希望我的解决方法能够给你一些启发，以后遇到类似莫名其妙的问题，可以想到使用PM这个工具去排查问题。</p><p><font color="#ff0000">update</font>: 更新了新的症状（F5调试的时候弹出cannot locate microsoft internet explorer的对话框）的解决办法。</p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight%e6%97%a0%e6%b3%95%e8%b0%83%e8%af%95" title="Silverlight无法调试" rel="tag">Silverlight无法调试</a>, <a href="http://www.imkevinyang.com/tags/visual-studio" title="Visual Studio" rel="tag">Visual Studio</a>, <a href="http://www.imkevinyang.com/categories/techarticles/knottyproblems" title="疑难杂症" rel="tag">疑难杂症</a>, <a href="http://www.imkevinyang.com/tags/%e8%b0%83%e8%af%95" title="调试" rel="tag">调试</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/08/firebug%e5%9c%a8edithtml%e6%97%b6%e4%b8%a2%e5%a4%b1%e4%ba%8b%e4%bb%b6%e5%a4%84%e7%90%86%e5%87%bd%e6%95%b0-2.html" title="Firebug在EditHtml时丢失事件处理函数 (2009/08/19)">Firebug在EditHtml时丢失事件处理函数</a> (2009/08/19)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2009/09/visual-assist%e4%bb%a3%e7%a0%81%e6%8f%90%e7%a4%ba%e4%bd%bf%e7%94%a8%e7%9a%84%e5%ad%97%e7%ac%a6%e4%b8%b2%e6%a8%a1%e7%b3%8a%e5%8c%b9%e9%85%8d%e7%ae%97%e6%b3%95.html" title="Visual Assist代码提示使用的字符串模糊匹配算法 (2009/09/28)">Visual Assist代码提示使用的字符串模糊匹配算法</a> (2009/09/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e6%97%a0%e6%b3%95%e8%b0%83%e8%af%95%e7%9a%84%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>枚举导致的WCF Web Service接口返回异常</title><link>http://www.imkevinyang.com/2009/08/%e6%9e%9a%e4%b8%be%e5%af%bc%e8%87%b4%e7%9a%84wcf-web-service%e6%8e%a5%e5%8f%a3%e8%bf%94%e5%9b%9e%e5%bc%82%e5%b8%b8.html</link> <comments>http://www.imkevinyang.com/2009/08/%e6%9e%9a%e4%b8%be%e5%af%bc%e8%87%b4%e7%9a%84wcf-web-service%e6%8e%a5%e5%8f%a3%e8%bf%94%e5%9b%9e%e5%bc%82%e5%b8%b8.html#comments</comments> <pubDate>Sun, 23 Aug 2009 13:44:58 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[WCF]]></category> <category><![CDATA[Web Service]]></category> <category><![CDATA[异常]]></category> <category><![CDATA[枚举]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/08/%e6%9e%9a%e4%b8%be%e5%af%bc%e8%87%b4%e7%9a%84wcf-web-service%e6%8e%a5%e5%8f%a3%e8%bf%94%e5%9b%9e%e5%bc%82%e5%b8%b8.html</guid> <description><![CDATA[<p>枚举在DotNet中是一个比较特别的类型，因为你可以将任意整数赋值给一个枚举类，而不会导致编译或者运行时异常。不知道为什么要这样设计，感觉在这样的设计下，枚举类就变成弱类型了，丧失了类型安全检测了。曾经就有一次在Silverlight项目中遇到了和枚举类这个设计相关的奇怪问题，调试了半天才解决。</p><p>当时的症状是这样的，客户端Silverlight程序（当时是Silverlight 2.0 RTM）在调用Web Service返回的时候抛出了一个C&#8230;</p>]]></description> <content:encoded><![CDATA[<p>枚举在DotNet中是一个比较特别的类型，因为你可以将任意整数赋值给一个枚举类，而不会导致编译或者运行时异常。不知道为什么要这样设计，感觉在这样的设计下，枚举类就变成弱类型了，丧失了类型安全检测了。曾经就有一次在Silverlight项目中遇到了和枚举类这个设计相关的奇怪问题，调试了半天才解决。</p><p>当时的症状是这样的，客户端Silverlight程序（当时是Silverlight 2.0 RTM）在调用Web Service返回的时候抛出了一个CommunicationException，这个错误没能提供任何信息，Silverlight把所有的Web Service的异常都替换成这个没有调试意义的异常。我尝试在Web Service端跟了一下，发现程序正常的走到最后一个大括号，没有抛出任何异常。但是返回的时候却还是抛出了这个CommunicationException异常。</p><p>Google了一下，实在找不到相关的文章。只能自己分析了。在对涉及到的类做了详尽的检查之后，还是没有检查出什么设计问题来。该标注的属性都标注了。绞尽脑汁，后来终于想起了一丝线索，就是某个类里面定义了一个枚举成员，这个枚举类我之前修改过。我回想起当时的修改，我是把一个成员给删掉了，但是这会有什么关系呢？？我重新跟了一下，重点跟踪和该枚举成员相关的代码，终于发现了在一个数据库查询的时候，返回的枚举成员就是之前删掉的那个成员。由于枚举的设计是允许未定义成员的存在，因此这里不会报错，代码会继续执行直到返回。但是Silverlight客户端Web Service代理在反射此类型的时候则会出错（因为没有对应的枚举成员存在）。遗憾的是，Silverlight对Web Service返回的结果异常的报错机制不能帮我们很好的发现这个问题。我后来测试发现，如果在调用Web Service的时候传入一个非法的成员值，Silverlight是会抛出一个反射类型出错的异常，而且会帮你定位到出错的那个枚举成员上。</p><p>后来项目开发中还遇到和这个类似的问题，就是在实例化一个类实例的时候，由于类中使用C#3.0的自动属性特性去定义的枚举成员，成员的初始值是0，而枚举类中并没有0的成员，所以会遇到和上面一样的问题。</p><p>实际上，微软给的最佳开发实践中指出了，枚举类的一个设计原则就是，一定要定义一个0值的成员，这样可以避免枚举初始化值无效的问题。</p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/wcf" title="WCF" rel="tag">WCF</a>, <a href="http://www.imkevinyang.com/tags/web-service" title="Web Service" rel="tag">Web Service</a>, <a href="http://www.imkevinyang.com/tags/%e5%bc%82%e5%b8%b8" title="异常" rel="tag">异常</a>, <a href="http://www.imkevinyang.com/tags/%e6%9e%9a%e4%b8%be" title="枚举" rel="tag">枚举</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/05/javascript%e4%b8%ad%e8%8e%b7%e5%8f%96%e5%87%ba%e9%94%99%e4%bb%a3%e7%a0%81%e6%89%80%e5%9c%a8%e6%96%87%e4%bb%b6%e5%8f%8a%e8%a1%8c%e6%95%b0.html" title="Javascript中获取出错代码所在文件及行数 (2009/05/18)">Javascript中获取出错代码所在文件及行数</a> (2009/05/18)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2009/09/visual-studio%e5%b0%8f%e8%b4%b4%e5%a3%ab%e5%8a%a0%e4%ba%86try-catch%e4%b9%9f%e8%83%bd%e8%87%aa%e5%8a%a8%e5%ae%9a%e4%bd%8d%e5%88%b0%e5%bc%82%e5%b8%b8%e4%bb%a3%e7%a0%81.html" title="Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码 (2009/09/18)">Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码</a> (2009/09/18)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/08/%e6%9e%9a%e4%b8%be%e5%af%bc%e8%87%b4%e7%9a%84wcf-web-service%e6%8e%a5%e5%8f%a3%e8%bf%94%e5%9b%9e%e5%bc%82%e5%b8%b8.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>跨域下请求Silverlight Xap包引起的问题</title><link>http://www.imkevinyang.com/2009/07/%e8%b7%a8%e5%9f%9f%e4%b8%8b%e8%af%b7%e6%b1%82silverlight-xap%e5%8c%85%e5%bc%95%e8%b5%b7%e7%9a%84%e9%97%ae%e9%a2%98.html</link> <comments>http://www.imkevinyang.com/2009/07/%e8%b7%a8%e5%9f%9f%e4%b8%8b%e8%af%b7%e6%b1%82silverlight-xap%e5%8c%85%e5%bc%95%e8%b5%b7%e7%9a%84%e9%97%ae%e9%a2%98.html#comments</comments> <pubDate>Sun, 12 Jul 2009 11:15:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[HTML]]></category> <category><![CDATA[HTML Bridge]]></category> <category><![CDATA[Xap]]></category> <category><![CDATA[安全]]></category> <category><![CDATA[疑难问题]]></category> <category><![CDATA[脚本访问]]></category> <category><![CDATA[跨域]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/07/%e8%b7%a8%e5%9f%9f%e4%b8%8b%e8%af%b7%e6%b1%82silverlight-xap%e5%8c%85%e5%bc%95%e8%b5%b7%e7%9a%84%e9%97%ae%e9%a2%98.html</guid> <description><![CDATA[<h2>问题</h2><p>最近将一个Silverlight应用从一个域挪到另外一个域下之后，出了一些莫名其妙的问题。<strong><font color="#008000">在加载完Silverlight之后，整个Silverlight UI一闪就消失了</font></strong>。左下角没有异常信息，异常报错的窗口——系统会捕获到所有异常，将其使用Alert方法展示给用户——也没有弹出来。</p><p>后来使用HTTP Watch观察了一下，发现在调用web service的时候服务端返回了错误（服务端会将异常封装成一个自定义的数据结构返回给客户端）。奇怪的是&#8230;</p>]]></description> <content:encoded><![CDATA[</p><h2>问题</h2><p>最近将一个Silverlight应用从一个域挪到另外一个域下之后，出了一些莫名其妙的问题。<strong><font color="#008000">在加载完Silverlight之后，整个Silverlight UI一闪就消失了</font></strong>。左下角没有异常信息，异常报错的窗口——系统会捕获到所有异常，将其使用Alert方法展示给用户——也没有弹出来。</p><p>后来使用HTTP Watch观察了一下，发现在调用web service的时候服务端返回了错误（服务端会将异常封装成一个自定义的数据结构返回给客户端）。奇怪的是，既然返回了错误，按理应该会弹出窗口显示错误信息才是，但是却什么信息也没弹出来，整个UI界面一闪就消失了。</p><p>查了很久之后终于找到相关的资料，原来Silverlight和宿主（承载Silverlight应用的网页）Dom元素和脚本的交互在跨域下也有一些限制。</p><h2>Silverlight HTML桥的安全设置</h2><p>在Silverlight2中，有三个参数控制着Silverlight和HTML的交互行为。</p><ul><li><strong>enableHtmlAccess ——</strong> Silverlight插件属性，禁止恶意的基于 Silverlight 的跨域应用程序访问主页面的 JavaScript 和 DOM 代码。</li><li><strong>ExternalCallersFromCrossDomain</strong> —— 部署清单属性，禁止恶意的跨域宿主访问由基于 Silverlight 的应用程序公开的可编写脚本的属性、方法或事件。</li><li><strong>AllowHtmlPopupwindow</strong> —— Silverlight插件属性，控制基于 Silverlight 的跨域应用程序打开的弹出窗口。在此属性设置为 false 时（在从包含页或承载 iframe 以外的其他域加载 Silverlight 控件时的默认值），开发人员无法调用 [HtmlPage.PopupWindow]。</li></ul><h2><strong>enableHtmlAccess</strong></h2><p>这个属性是在Silverlight插件中配置的。它使到Xap包中的托管代码可以访问宿主页面中的DOM元素以及Javascript代码。<strong><font color="#008000">此插件一旦初始化之后就是只读的。在同域情况下，此属性默认值为true，而在跨域情况下（宿主和Xap包不在同个域下）默认值为false</font></strong>。这也就是为什么我们一般情况下不需要设置此参数的缘故。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">id</span><span class="kwrd">=&quot;silverlightControlHost&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">object</span> <span class="attr">data</span><span class="kwrd">=&quot;data:application/x-silverlight,&quot;</span> <span class="attr">type</span><span class="kwrd">=&quot;application/x-silverlight-2&quot;</span> <span class="attr">width</span><span class="kwrd">=&quot;300&quot;</span> <span class="attr">height</span><span class="kwrd">=&quot;100&quot;</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">param</span> <span class="attr">name</span><span class="kwrd">=&quot;source&quot;</span> <span class="attr">value</span><span class="kwrd">=&quot;http://www.domain1.com/silverlightapp.xap&quot;</span><span class="kwrd">/&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">param</span> <span class="attr">name</span><span class="kwrd">=&quot;enableHtmlAccess&quot;</span> <span class="attr">value</span><span class="kwrd">=&quot;true&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">object</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre><p>将此属性设置为true之后才可以访问以下对象：</p><ul><li><a href="http://msdn.microsoft.com/zh-cn/library/system.windows.browser.htmlpage.document(VS.95).aspx">HtmlPage.Document</a></li><li><a href="http://msdn.microsoft.com/zh-cn/library/system.windows.browser.htmlpage.window(VS.95).aspx">HtmlPage.Window</a></li><li><a href="http://msdn.microsoft.com/zh-cn/library/system.windows.browser.htmlpage.plugin(VS.95).aspx">HtmlPage.Plugin</a></li><li><a href="http://msdn.microsoft.com/zh-cn/library/system.windows.browser.htmlpage.browserinformation(VS.95).aspx">HtmlPage.BrowserInformation</a></li></ul><p>这也就解释了文章开头提到的问题。</p><p>因为在出问题的Silverlight应用中，会捕获所有的异常，并将异常描述信息通过HtmlWindow.Alert方法展示给用户。而Alert的实现应该也是通过调用Javascript的alert函数来完成的，因此在跨域情况下，如果直接调用跨域宿主的Javascript代码是会抛出异常的。不过对于此异常Silverlight的处理行为还是很糟糕的。</p><ul>如果出于某种目的需要禁用此属性，防止Silverlight意外篡改宿主Dom元素，或者限制Silverlight可访问的Dom元素，那么可以采用以下步骤实现：</ul><ul>1. 通过<a href="http://msdn.microsoft.com/zh-cn/library/system.windows.browser.scriptabletypeattribute(VS.95).aspx">ScriptableTypeAttribute</a>或者<a href="http://msdn.microsoft.com/zh-cn/library/system.windows.browser.scriptablememberattribute(VS.95).aspx">ScriptableMemberAttribute</a>属性声明一个可以被Javascript访问的Silverlight对象</ul><ul>2. 通过<a href="http://msdn.microsoft.com/zh-cn/library/system.windows.browser.htmlpage.registerscriptableobject(VS.95).aspx">RegisterScriptableObject</a>显式注册此对象以供Javascript访问</ul><ul>3. Javascript调用此对象接口，将所需要的Dom元素传给Silverlight托管代码</ul><ul>需要注意的是，这种方式是由Javascript发起的操作，需要配置ExternalCallersFromCrossDomain属性为true。</ul><h2>ExternalCallersFromCrossDomain</h2><p><font color="#000000"></font></p><p>ExternalCallersFromCrossDomain属性是在部署清单appmanifest.xaml中配置的。它是用来限制跨域情况下脚本对Silverlight托管代码的访问的，<strong><font color="#008000">在同域情况下此属性无效</font></strong>。配置示例如下：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Deployment</span> <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/client/2007&quot;</span>
    <span class="attr">xmlns:x</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span>
    <span class="attr">EntryPointAssembly</span><span class="kwrd">=&quot;MyAppAssembly&quot;</span>
    <span class="attr">EntryPointType</span><span class="kwrd">=&quot;MyNamespace.MyApplication&quot;</span>
    <span class="attr">ExternalCallersFromCrossDomain</span><span class="kwrd">=&quot;ScriptableOnly&quot;</span>
<span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">Deployment.Parts</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">AssemblyPart</span> <span class="attr">Source</span>=&quot;<span class="attr">MyAppAssembly</span>.<span class="attr">dll</span>” <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">AssemblyPart</span> <span class="attr">Source</span><span class="kwrd">=&quot;MyUserControl.dll&quot;</span> <span class="kwrd">/&gt;</span>
  <span class="kwrd">&lt;/</span><span class="html">Deployment.Parts</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">Deployment</span><span class="kwrd">&gt;</span></pre><p>此属性有两个取值，ScriptableOnly和NoAccess（beta2的FullAccess取值在正式版的时候已经废弃了）。当设置为ScriptableOnly时，Javascript可以访问Silverlight托管代码显式注册的脚本入口，而不能查询或设置其他对象的属性。另外，它也不接受事件通知。如果设置为NoAccess，那么Javascript无法访问托管代码里的任何对象接口。</p><p>&#160;</p><p>关于这两个属性的详细信息，参见<a href="http://msdn.microsoft.com/zh-cn/library/cc645023(VS.95).aspx" target="_blank">SilverlightHTML 桥中的安全设置</a>。</p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/tags/html" title="HTML" rel="tag">HTML</a>, <a href="http://www.imkevinyang.com/tags/html-bridge" title="HTML Bridge" rel="tag">HTML Bridge</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/xap" title="Xap" rel="tag">Xap</a>, <a href="http://www.imkevinyang.com/tags/%e5%ae%89%e5%85%a8" title="安全" rel="tag">安全</a>, <a href="http://www.imkevinyang.com/tags/%e7%96%91%e9%9a%be%e9%97%ae%e9%a2%98" title="疑难问题" rel="tag">疑难问题</a>, <a href="http://www.imkevinyang.com/tags/%e8%84%9a%e6%9c%ac%e8%ae%bf%e9%97%ae" title="脚本访问" rel="tag">脚本访问</a>, <a href="http://www.imkevinyang.com/tags/%e8%b7%a8%e5%9f%9f" title="跨域" rel="tag">跨域</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/11/button%e6%a0%87%e7%ad%be%e9%bc%a0%e6%a0%87%e7%82%b9%e5%87%bb%e4%ba%8b%e4%bb%b6%e7%9a%84%e8%a7%a6%e5%8f%91%e6%ba%90%e9%97%ae%e9%a2%98.html" title="Button标签鼠标点击事件的触发源问题 (2009/11/27)">Button标签鼠标点击事件的触发源问题</a> (2009/11/27)</li><li><a href="http://www.imkevinyang.com/2009/04/pre%e6%a0%87%e7%ad%be%e5%86%85%e6%96%87%e5%ad%97%e8%87%aa%e5%8a%a8%e6%8d%a2%e8%a1%8c%ef%bc%88%e5%85%bc%e5%ae%b9%e5%a4%9a%e6%95%b0%e4%b8%bb%e6%b5%81%e6%b5%8f%e8%a7%88%e5%99%a8%ef%bc%89.html" title="Pre标签内文字自动换行（兼容多数主流浏览器） (2009/04/09)">Pre标签内文字自动换行（兼容多数主流浏览器）</a> (2009/04/09)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2009/10/wordpress%e8%af%84%e8%ae%ba%e4%b8%ad%e4%bf%9d%e7%95%99html%e4%bb%a3%e7%a0%81.html" title="Wordpress评论中保留Html代码 (2009/10/31)">Wordpress评论中保留Html代码</a> (2009/10/31)</li><li><a href="http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html" title="图片等资源的引用路径问题 (2009/03/19)">图片等资源的引用路径问题</a> (2009/03/19)</li><li><a href="http://www.imkevinyang.com/2009/07/%e8%8e%ab%e5%90%8d%e5%85%b6%e5%a6%99%e7%9a%84silverlight%e8%b5%84%e6%ba%90%e6%96%87%e4%bb%b6%e5%bc%95%e7%94%a8%e9%97%ae%e9%a2%98.html" title="莫名其妙的Silverlight资源文件引用问题 (2009/07/06)">莫名其妙的Silverlight资源文件引用问题</a> (2009/07/06)</li><li><a href="http://www.imkevinyang.com/2009/03/%e8%b0%88%e8%b0%88silverlight%e7%9a%84%e4%b8%80%e4%b8%aa%e8%b7%a8%e5%9f%9f%e5%ae%89%e5%85%a8%e8%80%83%e8%99%91.html" title="谈谈Silverlight的一个跨域安全考虑 (2009/03/19)">谈谈Silverlight的一个跨域安全考虑</a> (2009/03/19)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/07/%e8%b7%a8%e5%9f%9f%e4%b8%8b%e8%af%b7%e6%b1%82silverlight-xap%e5%8c%85%e5%bc%95%e8%b5%b7%e7%9a%84%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>莫名其妙的Silverlight资源文件引用问题</title><link>http://www.imkevinyang.com/2009/07/%e8%8e%ab%e5%90%8d%e5%85%b6%e5%a6%99%e7%9a%84silverlight%e8%b5%84%e6%ba%90%e6%96%87%e4%bb%b6%e5%bc%95%e7%94%a8%e9%97%ae%e9%a2%98.html</link> <comments>http://www.imkevinyang.com/2009/07/%e8%8e%ab%e5%90%8d%e5%85%b6%e5%a6%99%e7%9a%84silverlight%e8%b5%84%e6%ba%90%e6%96%87%e4%bb%b6%e5%bc%95%e7%94%a8%e9%97%ae%e9%a2%98.html#comments</comments> <pubDate>Mon, 06 Jul 2009 15:22:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[技术随笔]]></category> <category><![CDATA[NeutralResourcesLanguageAttribute]]></category> <category><![CDATA[ResourceManager]]></category> <category><![CDATA[中立语言]]></category> <category><![CDATA[疑难问题]]></category> <category><![CDATA[资源文件]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/07/%e8%8e%ab%e5%90%8d%e5%85%b6%e5%a6%99%e7%9a%84silverlight%e8%b5%84%e6%ba%90%e6%96%87%e4%bb%b6%e5%bc%95%e7%94%a8%e9%97%ae%e9%a2%98.html</guid> <description><![CDATA[<h2>问题描述</h2><p>最近项目中遇到一个和资源文件相关的很奇怪的问题。有一个Silverlight应用会根据当前Url中的某个特定参数来决定使用什么文化的资源文件（关于资源的文件的使用见<a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" target="_blank">Silverlight 2 RTM 多国语言支持</a>）。在其他机器上运行没有问题，传入zh-Hans和en-US界面都能正确显示相应语言的文字。但是在我的系统上却不管传入什么都是显示的英文文字。</p><h2>问题分析</h2><p>打开工程看了一下，在资源文件夹下只定义了两个资源，一个是主资源XXX.res&#8230;</p>]]></description> <content:encoded><![CDATA[<h2>问题描述</h2><p>最近项目中遇到一个和资源文件相关的很奇怪的问题。有一个Silverlight应用会根据当前Url中的某个特定参数来决定使用什么文化的资源文件（关于资源的文件的使用见<a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" target="_blank">Silverlight 2 RTM 多国语言支持</a>）。在其他机器上运行没有问题，传入zh-Hans和en-US界面都能正确显示相应语言的文字。但是在我的系统上却不管传入什么都是显示的英文文字。</p><h2>问题分析</h2><p>打开工程看了一下，在资源文件夹下只定义了两个资源，一个是主资源XXX.resx，一个是英文中立资源XXX.en.resx。编译之后，主资源会被打包到主程序集中，而其他资源则被编译成独立的程序集，称为卫星程序集。Silverlight代码中在提取Url参数的时候也加上了一个检测逻辑，就是如果传入的语言不是英文，那么就使用zh-Hans。也就是说在其他人的机器上，如果你输入了fr，那么也是显示中文。分析加调试弄了好一会之后，我判定应该不是程序代码的bug。因为在某些人的机器上是正常的，而在我的机器还有另外一个同事的机器上却不正常，而且问题是可重现的。这说明了问题和本地环境有关。</p><p>清缓存，清Silverlight独立存储之后发现问题依然存在。难道是操作系统的问题？！我用的是win7，同事用的是win2008，都是高版本的windows，而其他人用的不是xp就是2003。为了证实我的想法，我又找了一台2008的机器，测试结果和我机器上的一样。看来很有可能问题就在这。可是，为什么呢？</p><p>为了查找问题的原因，我重新查阅了一下Silverlight使用资源文件的相关材料（和DotNet其实差不多）。</p><h2>Silverlight的资源查找方式</h2><p>Silverlight采用中心辐射型结构来打包和部署资源文件程序集。围绕在中心的是主程序集里面的资源，这个资源也被称为中立或者默认资源。<font color="#008000"><strong>如果主程序集没有显式设定语言，那么一个资源要是查找失败，最终会使用主程序集中的资源。</strong></font>每个辐射点指向的是每一种语言对应的卫星程序集。</p><p>Silverlight在查找资源文件的时候采用了如下的方式：</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/07/image-thumb3.png" width="665" height="221" /></p><p>最顶级是应用程序的默认程序集。第二级是语言相关程序集，它代表的是地域无关的语言文化，如英文，简体中文，繁体中文（zh-Hant）等；第三级是和地域相关的文化程序集，如美国英语，英国英语，大陆简体中文，新加坡简体中文。Silverlight在加载本地资源的时候首先会根据CultureInfo.CurrentUICulture属性来判断应该加载哪一种文化对应的资源。在查找的时候是按照上面的层次结构从下到上进行查找的。具体说来，当ResourceManager在查找一个资源时会经过以下几个步骤：</p><p>1. 查找具体语言相应的程序集是否存在。如设置了zh-CN，那么就查找XXX.zh-CN.resx资源文件是否存在（存在于卫星程序集中），如果程序集不存在或者在该程序集中找不到此资源的定义，那么查找失败。如果操作系统支持回溯（Fallback）逻辑，那么跳到第二步；否则跳到第三步。</p><p>2. 操作系统提供一份推荐的语言回溯清单，上面包含了具体语言文化字符串（如en-US）和相应的中立语言字符串（如en）。Resource Manager会根据这份清单去查找相应的卫星程序集和程序集内指定资源是否存在。如果查找失败，则跳到下一步。</p><p>3. 如果上面两步都失败，那么查找此具体文化的上一级文化的卫星程序集，也就是地域无关的文化，例如en-US查找失败，则查找en是否存在。</p><p>4. 如果上面3步都失败的话，那么Silverlight会查看主程序集的NeutralResourcesLanguageAttribute属性。NeutralResourcesLanguageAttribute是用在程序集上的属性，它是用来告知ResourceManager，某个程序集使用的语言是什么。ResourceManager会查看此属性的值，看是否满足条件。如果主程序集没有指定此属性，那么将会使用主程序集中的资源作为默认资源。</p><p>5. 如果第4步也查找失败，那么ResourceManager将使用文化无关（Invarient Culture）的资源。</p><h2>问题所在</h2></p><p>在网上查到MSDN的文章说，自打Vista开始，操作系统开始支持这种“Fallback”的逻辑了。通过系统API GetThreadPreferredUILanguages可以获取操作系统核心推荐使用的语言清单。</p><p>由于工程里面并没有指定zh-Hans的资源文件（于是也就没有zh-Hans的卫星程序集），也没有设置主程序集使用的语言是什么（通过NeutralResourcesLanguageAttribute属性指定）因此在第一步的时候查找失败；这个时候，在我win7的机器上，由于操作系统支持fallback逻辑，因此Silverlight会使用操作系统提供的语言清单去查找，由于我的系统是中文系统，因此清单上第一项肯定是zh-CN，接下来的猜测应该是en-US和en（老美搞的操作系统嘛，当然要把自家语言排前一点了）。查找zh-CN肯定又失败，但是查找en却能够找到，因此就出现了不管你参数中输入什么语言文化字符串，都会显示英文。</p><p>而在其他低版本的windows上，因为操作系统不支持这份清单，那么Silverlight始终没有办法找到zh-Hans相关的卫星程序集，而主程序集又没有显式的设置语言，因此ResourceManager就会使用主程序集里面的资源文件，也就是中文。</p><p>这就是为什么在低版本windows上，乱输入语言，显示的默认是中文，而在Vista等高版本windows上，默认显示的是英文的缘故。</p><p>再插一句，如果在主程序集中显式设置了NeutralResourcesLanguageAttribute为zh-Hans，然后在低版本的windows上访问此应用程序的时候输入例如fr等不支持的语言，那么Silverlight将会使用语言无关的资源（语言无关的资源具体被定义在哪不是很确定，可能是dotnet类库，也可能是本地操作系统），如果该语言无关的资源没有定义，则ResourceManager得到的是空字符串。因为此时ResourceManager就不会把主程序集里的资源当作最终Fallback的资源了。</p><h2>解决问题的办法</h2><p>经过上面的分析，解决问题的办法已经很清楚了，要么再添加一个zh-Hans的资源文件，要么显式的使用NeutralResourcesLanguageAttribute通知ResourceManager，主程序集使用的资源语言是zh-Hans。</p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/tags/neutralresourceslanguageattribute" title="NeutralResourcesLanguageAttribute" rel="tag">NeutralResourcesLanguageAttribute</a>, <a href="http://www.imkevinyang.com/tags/resourcemanager" title="ResourceManager" rel="tag">ResourceManager</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/%e4%b8%ad%e7%ab%8b%e8%af%ad%e8%a8%80" title="中立语言" rel="tag">中立语言</a>, <a href="http://www.imkevinyang.com/categories/techarticles" title="技术随笔" rel="tag">技术随笔</a>, <a href="http://www.imkevinyang.com/tags/%e7%96%91%e9%9a%be%e9%97%ae%e9%a2%98" title="疑难问题" rel="tag">疑难问题</a>, <a href="http://www.imkevinyang.com/tags/%e8%b5%84%e6%ba%90%e6%96%87%e4%bb%b6" title="资源文件" rel="tag">资源文件</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html" title="图片等资源的引用路径问题 (2009/03/19)">图片等资源的引用路径问题</a> (2009/03/19)</li><li><a href="http://www.imkevinyang.com/2009/07/%e8%b7%a8%e5%9f%9f%e4%b8%8b%e8%af%b7%e6%b1%82silverlight-xap%e5%8c%85%e5%bc%95%e8%b5%b7%e7%9a%84%e9%97%ae%e9%a2%98.html" title="跨域下请求Silverlight Xap包引起的问题 (2009/07/12)">跨域下请求Silverlight Xap包引起的问题</a> (2009/07/12)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/07/%e8%8e%ab%e5%90%8d%e5%85%b6%e5%a6%99%e7%9a%84silverlight%e8%b5%84%e6%ba%90%e6%96%87%e4%bb%b6%e5%bc%95%e7%94%a8%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> </channel> </rss>