<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.feedsky.com/styles/temp01.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link href="http://feed.feedsky.com/xiaoshatiantec" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/xiaoshatiantec" type="application/rss+xml"></fs:self_link><lastBuildDate>Thu, 17 May 2012 15:40:56 GMT</lastBuildDate><title>『 听 风 且 吟 』技术版</title><description>倚楼听风雨,淡看江湖路......</description><image><url>http://www.feedsky.com/feed/xiaoshatiantec/sc/gif</url><title>『 听 风 且 吟 』技术版</title><link>http://coding.windstyle.cn</link></image><link>http://coding.windstyle.cn</link><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><language>en</language><pubDate>Fri, 18 May 2012 01:53:30 GMT</pubDate><item><title>Windows Phone Background Agent杂谈</title><link>http://coding.windstyle.cn/2012/05/17/about-windows-phone-background-agent/</link><content:encoded>&lt;p&gt;Windows Phone从Mango开始开放了Background Agent，使得我们可以实现后台运行的任务。出于兴趣，我在第一时间使用这套API开发了一个应用——Human Calendar。随着时间的推移、功能的增加，Human Calendar越来越依赖于Background Agent，也逐渐遇到了更多让人头疼的问题。经过许多摸索和撞墙后，绝大多数问题都解决了，Human Calendar目前运行良好。所以我就用这篇文章来记录一下开发Background Agent过程中的一些事情，但我不会完整地介绍一个Background Agent的开发过程，你大可将本文看成一篇“吐槽”文。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1154&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;限制&lt;/h3&gt;
&lt;p&gt;在开发Background Agent之前，必须要考虑到它的限制，因为这些限制极其严格，对于定期代理（PeriodicTask）来说，限制了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;有一些API不能使用，并不是说你不调用就可以了，只要你在同一个程序集里使用了这些API，就不会通过验证；&lt;/li&gt;
&lt;li&gt;内存占用不能超过6MB，否则立即终止；&lt;/li&gt;
&lt;li&gt;生效时间最长只有14天，过期后就需要重新计划。Human Calendar和一些天气应用都属于那种只要有Tile就可以一辈子不去打开的应用，但是由于这个限制，我还得想办法提醒用户：“亲，记住两周内重新打开应用一次哦，不然Tile就没法更新了哦”；&lt;/li&gt;
&lt;li&gt;连续两次崩溃之后会被禁用，做好准备捕捉一切异常吧；&lt;/li&gt;
&lt;li&gt;每30分钟运行一次，每次最多执行25秒，超时后立即终止，所以如果在后台任务里下载文件的话，要特别注意文件的大小；&lt;/li&gt;
&lt;li&gt;节电模式会阻止执行；&lt;/li&gt;
&lt;li&gt;手机中的后台任务数量是有上限的，最少为6个，当手机中已启用的后台任务达到上限后，就无法再启用新的后台任务了，这时候你还得提醒用户：“亲，到这里的这里的这里看看后台任务是不是超过6个了，是的话，挑一个禁用了，然后回来再试试”……&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;资源密集型代理&lt;/h3&gt;
&lt;p&gt;除了定期代理之外，Windows Phone还支持另外一种后台任务——资源密集型代理（ResourceIntensiveTask），不过我们通常都不会用到它，因为它简直就是个杯具，它的限制不仅多，而且都很变态，除了拥有定期代理的前4挑限制之外，它还限制了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;电池电量不得低于90%，而且需要连接外部电源；&lt;/li&gt;
&lt;li&gt;需要非手机网络连接，连着WIFI或PC吧，亲；&lt;/li&gt;
&lt;li&gt;屏幕必须锁定，也不能接打电话，否则不执行；&lt;/li&gt;
&lt;li&gt;最多执行10分钟，超时立即终止；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;想像一下，假如有个应用使用了资源密集型代理，它该怎么向用户解释？&lt;/p&gt;
&lt;p&gt;“亲，想要使用我们的XXX功能，您得先充满电，再连着WIFI，锁住屏幕，安静的等待10分钟，期间千万别拔开电源线，也别解锁屏幕和接打电话哦。”&lt;/p&gt;
&lt;p&gt;用户“哦”了一声，然后随手卸载了应用。&lt;/p&gt;
&lt;h3&gt;调试&lt;/h3&gt;
&lt;p&gt;可以使用ScheduledActionService.LaunchForTest方法来随时随地执行后台任务，籍此来进行调试。此方法在Debug和Release模式下均可执行，但在用户下载的应用中是无效的，所以不要妄想用它来突破Background Agent的时间限制。&lt;/p&gt;
&lt;p&gt;虽然在Visual Studio中进行调试非常方便，但不可过于相信调试器。简单来说，附加了调试器的Background Agent就像被提升了权限一样，可以执行一些正常状态下不能执行的任务，譬如可以调用BitmapImage.SetSource方法，而在没有附加调试器的后台任务中调用这个方法是会抛出异常的（可以使用WriteableBitmapImage来代替）。&lt;/p&gt;
&lt;p&gt;所以很有必要在不附加调试器的情况下检查Background Agent的运行情况。&lt;/p&gt;
&lt;p&gt;这时就可以利用ScheduledActionService.LaunchForTest来将Background Agent安排在一段时间后执行，然后退出应用，关闭调试器（早期的SDK会在退出应用时自动关闭调试器），观察效果。&lt;/p&gt;
&lt;p&gt;假如发现后台任务出现了问题，该怎么定位问题？有两种特别原始的方法：第一种是在执行后台任务的的同时写日志；第二种是Toast通知（我想起了史前程序员使用alert调试JavaScript的故事）。&lt;/p&gt;
&lt;p&gt;由于第4条限制，所以很有必要勤快的使用try-catch，但比较不幸的是并不是所有异常都会被捕捉到，所有因为超出限制而导致的终止行为都无法捕捉到，而且在某些情况下，一些看起来很正常的异常也会跳过catch直接杀死后台任务。&lt;/p&gt;
&lt;p&gt;所以日志和Toast通知就相当重要，你可以根据最后一条消息的位置来推断代码执行到了何处，从而找到出问题的代码，然后再研究为什么会出问题。&lt;/p&gt;
&lt;p&gt;这里还有一个插曲，在早期的SDK中有这样一个问题，如果附加了调试器，Background Agent就永远不会执行，于是我眼睁睁的盯着模拟器浪费了一个大好的下午，人生苦短啊，还好这个问题现在已经修复了。&lt;/p&gt;
&lt;h3&gt;检测时间和内存占用&lt;/h3&gt;
&lt;p&gt;Background Agent在时间上有许多限制，对于第3条限制，我们别无他法，因为添加后台任务的API属于受限API，不能在Background Agent中调用，所以只能提醒用户每14天内至少要打开一次应用，然后在每次打开应用的时候自动重新启用后台任务（这样它就又能活14天了）。&lt;/p&gt;
&lt;p&gt;对于第2条和第5条限制，我们只能想办法控制执行时间，尽量把任务细化成小任务，让每个小任务都有自己的唯一标识和完成状态，并且可以被持久化，然后用递归或者遍历的方式依次执行这些小任务，每次执行时都要检查当前已执行的时间和已占用的内存，如果发现接近某个临界值，就NotifyComplete，然后期待半小时后继续。&lt;/p&gt;
&lt;p&gt;临界值可以根据第2条和第5条限制以及小任务们的平均执行时间和内存占用来设定，留出一定的空档以防不测。&lt;/p&gt;
&lt;p&gt;此外，如果应用中使用了本地数据库，最好不要在后台任务中初始化甚至使用，它会带来极大的内存消耗。就拿Human Calendar来说，用IsolatedStorageSettings取代了本地数据库之后，内存竟然节省了一半（而且这个数据库还无比简单，只有一张表、五个列和七八条数据）。&lt;/p&gt;
&lt;h3&gt;资源&lt;/h3&gt;
&lt;p&gt;应用：&lt;a href=&quot;http://windowsphone.com/s?appid=d725b5ad-9a39-47ba-8302-f742659290bb&quot; target=&quot;_blank&quot;&gt;Human Calendar&lt;/a&gt;，我承认这个应用很宅，不过还是欢迎捧场……&lt;/p&gt;
&lt;p&gt;MSDN：&lt;a href=&quot;http://msdn.microsoft.com/zh-cn/library/hh202961(v=vs.92)&quot; target=&quot;_blank&quot;&gt;《Windows Phone的后台代理》&lt;/a&gt;，写本文时候发现这篇文章在年初还更新了一次，增加了不少内容，MSDN上的Windows Phone文章更新速度还是蛮快的。&lt;/p&gt;
&lt;p&gt;最后吐槽一次，MSDN上把Reference翻译成“书评”这种事情是哪个实习生干的？&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/639608308/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/05/17/about-windows-phone-background-agent/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://coding.windstyle.cn/2012/05/17/about-windows-phone-background-agent/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>Windows Phone从Mango开始开放了Background Agent，使得我们可以实现后台运行的任务。出于兴趣，我在第一时间使用这套API开发了一个应用——Human Calendar。随着时间的推移、功能的增加，Human Calendar越来越依赖于Background Agent，也逐渐遇到了更多让人头疼的问题。经过许多摸索和撞墙后，绝大多数问题都解决了，Human Calendar目前运行良好。所以我就用这篇文章来记录一下开发Background Agent过程中的一些事情，但我不会完整地介绍一个Background Agent的开发过程，你大可将本文看成一篇“吐槽”文。 限制 在开发Background Agent之前，必须要考虑到它的限制，因为这些限制极其严格，对于定期代理（PeriodicTask）来说，限制了： 有一些API不能使用，并不是说你不调用就可以了，只要你在同一个程序集里使用了这些API，就不会通过验证； 内存占用不能超过6MB，否则立即终止； 生效时间最长只有14天，过期后就需要重新计划。Human Calendar和一些天气应用都属于那种只要有Tile就可以一辈子不去打开的应用，但是由于这个限制，我还得想办法提醒用户：“亲，记住两周内重新打开应用一次哦，不然Tile就没法更新了哦”； 连续两次崩溃之后会被禁用，做好准备捕捉一切异常吧； 每30分钟运行一次，每次最多执行25秒，超时后立即终止，所以如果在后台任务里下载文件的话，要特别注意文件的大小； 节电模式会阻止执行； 手机中的后台任务数量是有上限的，最少为6个，当手机中已启用的后台任务达到上限后，就无法再启用新的后台任务了，这时候你还得提醒用户：“亲，到这里的这里的这里看看后台任务是不是超过6个了，是的话，挑一个禁用了，然后回来再试试”…… 资源密集型代理 除了定期代理之外，Windows Phone还支持另外一种后台任务——资源密集型代理（ResourceIntensiveTask），不过我们通常都不会用到它，因为它简直就是个杯具，它的限制不仅多，而且都很变态，除了拥有定期代理的前4挑限制之外，它还限制了： 电池电量不得低于90%，而且需要连接外部电源； 需要非手机网络连接，连着WIFI或PC吧，亲； 屏幕必须锁定，也不能接打电话，否则不执行； 最多执行10分钟，超时立即终止； 想像一下，假如有个应用使用了资源密集型代理，它该怎么向用户解释？ “亲，想要使用我们的XXX功能，您得先充满电，再连着WIFI，锁住屏幕，安静的等待10分钟，期间千万别拔开电源线，也别解锁屏幕和接打电话哦。” 用户“哦”了一声，然后随手卸载了应用。 调试 可以使用ScheduledActionService.LaunchForTest方法来随时随地执行后台任务，籍此来进行调试。此方法在Debug和Release模式下均可执行，但在用户下载的应用中是无效的，所以不要妄想用它来突破Background Agent的时间限制。 虽然在Visual Studio中进行调试非常方便，但不可过于相信调试器。简单来说，附加了调试器的Background Agent就像被提升了权限一样，可以执行一些正常状态下不能执行的任务，譬如可以调用BitmapImage.SetSource方法，而在没有附加调试器的后台任务中调用这个方法是会抛出异常的（可以使用WriteableBitmapImage来代替）。 所以很有必要在不附加调试器的情况下检查Background Agent的运行情况。 这时就可以利用ScheduledActionService.LaunchForTest来将Background Agent安排在一段时间后执行，然后退出应用，关闭调试器（早期的SDK会在退出应用时自动关闭调试器），观察效果。 假如发现后台任务出现了问题，该怎么定位问题？有两种特别原始的方法：第一种是在执行后台任务的的同时写日志；第二种是Toast通知（我想起了史前程序员使用alert调试JavaScript的故事）。 由于第4条限制，所以很有必要勤快的使用try-catch，但比较不幸的是并不是所有异常都会被捕捉到，所有因为超出限制而导致的终止行为都无法捕捉到，而且在某些情况下，一些看起来很正常的异常也会跳过catch直接杀死后台任务。 所以日志和Toast通知就相当重要，你可以根据最后一条消息的位置来推断代码执行到了何处，从而找到出问题的代码，然后再研究为什么会出问题。 这里还有一个插曲，在早期的SDK中有这样一个问题，如果附加了调试器，Background Agent就永远不会执行，于是我眼睁睁的盯着模拟器浪费了一个大好的下午，人生苦短啊，还好这个问题现在已经修复了。 检测时间和内存占用 Background Agent在时间上有许多限制，对于第3条限制，我们别无他法，因为添加后台任务的API属于受限API，不能在Background Agent中调用，所以只能提醒用户每14天内至少要打开一次应用，然后在每次打开应用的时候自动重新启用后台任务（这样它就又能活14天了）。 对于第2条和第5条限制，我们只能想办法控制执行时间，尽量把任务细化成小任务，让每个小任务都有自己的唯一标识和完成状态，并且可以被持久化，然后用递归或者遍历的方式依次执行这些小任务，每次执行时都要检查当前已执行的时间和已占用的内存，如果发现接近某个临界值，就NotifyComplete，然后期待半小时后继续。 临界值可以根据第2条和第5条限制以及小任务们的平均执行时间和内存占用来设定，留出一定的空档以防不测。 此外，如果应用中使用了本地数据库，最好不要在后台任务中初始化甚至使用，它会带来极大的内存消耗。就拿Human Calendar来说，用IsolatedStorageSettings取代了本地数据库之后，内存竟然节省了一半（而且这个数据库还无比简单，只有一张表、五个列和七八条数据）。 资源 应用：Human [...]&lt;img src=&quot;http://www1.feedsky.com/t1/639608308/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/05/17/about-windows-phone-background-agent/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>Background Agent</category><category>Windows Phone</category><category>限制</category><pubDate>Thu, 17 May 2012 23:40:56 +0800</pubDate><author>Windie Chai</author><comments>http://coding.windstyle.cn/2012/05/17/about-windows-phone-background-agent/#comments</comments><guid isPermaLink="false">http://coding.windstyle.cn/?p=1154</guid><dc:creator>Windie Chai</dc:creator><fs:srclink>http://coding.windstyle.cn/2012/05/17/about-windows-phone-background-agent/</fs:srclink><fs:srcfeed>http://coding.windstyle.cn/feed/</fs:srcfeed><fs:itemid>feedsky/xiaoshatiantec/~7883976/639608308/1488721</fs:itemid></item><item><title>Linq to SharePoint，看上去很美</title><link>http://coding.windstyle.cn/2012/04/11/linq-to-sharepoint-just-looks-beautiful/</link><content:encoded>&lt;p&gt;Linq to SharePoint是SharePoint 2010引入的一组新API，在这之前，如果我们想要按照条件过滤SharePoint列表中的数据，只能通过CAML。&lt;/p&gt;
&lt;p&gt;但使用CAML并不是件令人身心愉悦的事情，至少我是这么认为的。我觉得在代码中嵌入一块冗长的XML字符串非常破坏美感，我尤其喜欢强类型，所以一直很难接受SPListItem用字符串作为键值去获取Field值的方式，更别提这些值都是Object类型，还得再经过一次转换。&lt;/p&gt;
&lt;p&gt;所以我比较喜欢将SPListItem转换成实体类来使用，只不过一直以来的做法都是自己写实体类和转换方法。而Linq to SharePoint则可以自动将列表映射为实体类，并且可以使用Linq语句来进行查询，看上去很美！&lt;span id=&quot;more-1151&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;那么Linq to SharePoint能不能帮我彻底拜托CAML呢，趁着重构代码的机会研究了一下，在这里简单总结一下。&lt;/p&gt;
&lt;p&gt;前面说过Linq to SharePoint可以自动生成列表的实体类，这是通过一个叫做SPMetal的工具来实现的，具体的用法请查阅&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ee538255.aspx&quot;&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;SPMetal会根据实际的列名来生成实体类中的属性名，所以如果你的列名是中文的话（譬如你安装了中文版SharePoint），你会得到一份非常诡异且冗长的代码文件。&lt;/p&gt;
&lt;p&gt;当然，如果你能接受中英文混排的代码的话，这倒也不是什么问题。&lt;/p&gt;
&lt;p&gt;SPMetal生成的属性大多是下面这个样子的：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;[ColumnAttribute(Name = &amp;quot;Body&amp;quot;, Storage = &amp;quot;_body&amp;quot;, FieldType = &amp;quot;Note&amp;quot;)]
public string Body
{
  get
  {
    return this._body;
  }
  set
  {
    if ((value != this._body))
    {
       this.OnPropertyChanging(&amp;quot;Body&amp;quot;, this._body);
       this._body = value;
       this.OnPropertyChanged(&amp;quot;Body&amp;quot;);
    }
  }
}
protected string _body;&lt;/pre&gt;
&lt;p&gt;Body属性被附加了一个ColumnAttribute，它的作用是将属性和SharePoint中的某一列关联起来。在它的命名参数中，Name表示的就是SharePoint中的列名，FieldType指列的类型，Storage表示的是实体类中用来存放列值的变量，可以看到这里为它指定的是一个变量，而不是Body属性，也就是说，在初始化这一实体的时候，该列的值会直接赋给_body变量，而不经过Body属性。那么Body属性的set访问器又是用来干什么的呢？实际上它的作用只是为了提供一种更改列值的机制，这一点从它复杂的内部流程也能看出端倪。&lt;/p&gt;
&lt;p&gt;如果你只是为了查询方便，并不需要修改和提交数据的话，完全可以使用下面的只读版本：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;[Column(Name = &amp;quot;Body&amp;quot;, Storage = &amp;quot;_body&amp;quot;, FieldType = &amp;quot;Note&amp;quot;)]
public string Body
{
  get
  {
    return this._body;
  }
}
protected string _body;
&lt;/pre&gt;
&lt;p&gt;此外，如果列表的包含一些设置为可空值的列的话，它们会被映射成一个Nullable&amp;lt;T&amp;gt;类型，如下所示：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;[ColumnAttribute(Name=&amp;quot;RatingCount&amp;quot;, Storage=&amp;quot;_ratingCount&amp;quot;, FieldType=&amp;quot;Number&amp;quot;)]
public System.Nullable&amp;lt;double&amp;gt; RatingCount{
  get {
    return this._ratingCount;
  }
  set {
    if ((value != this._ratingCount)) {
      this.OnPropertyChanging(&amp;quot;RatingCount&amp;quot;, this._ratingCount);
      this._ratingCount= value;
      this.OnPropertyChanged(&amp;quot;RatingCount&amp;quot;);
    }
  }
}
private System.Nullable&amp;lt;double&amp;gt; _ratingCount;
&lt;/pre&gt;
&lt;p&gt;虽然可以理解这么做的原因，但是却很难接受这种代码。尤其是在HTML中做绑定时，你不得不针对Nullable属性额外写一些代码来处理它的非空情况。&lt;/p&gt;
&lt;p&gt;好在我们可以将属性本身改成非空的类型，然后在get访问器里根据情况返回真实的值或者默认值：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;[Column(Name=&amp;quot;RatingCount&amp;quot;, Storage=&amp;quot;_ratingCount&amp;quot;, FieldType=&amp;quot;Counter&amp;quot;)]
public double RatingCount{
  get {
    return this._ratingCount ?? 0;
  }
}
private double? _ratingCount;
&lt;/pre&gt;
&lt;p&gt;但要注意Storage指向的变量还得是Nullable类型，以保存列的真实的值（包括空值）；属性的类型虽然可以改为非空类型，但要注意类型一定要和对应的变量相同，因为ColumnAttribute会在初始化时检查属性的实际类型。我曾尝试写过下面这样的属性，结果只收获了一个异常：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;[Column(Name=&amp;quot;RatingCount&amp;quot;, Storage=&amp;quot;_ratingCount&amp;quot;, FieldType=&amp;quot;Counter&amp;quot;)]
public int RatingCount{
  get {
    return this._id ? (int)this._id.Value : 0;
  }
}
private double? _ratingCount;
&lt;/pre&gt;
&lt;p&gt;为什么想要这么做呢？因为我实在想不出投票总数为什么会是一个小数？&lt;/p&gt;
&lt;p&gt;如果你刚巧需要使用Linq语句查询列表，而且查询条件刚巧也是一个包含可空值的列的话，就不能用上面提到的方法来修改属性的类型了，否则Linq to SharePoint将无法生成CAML，结果也是以异常告终。&lt;/p&gt;
&lt;p&gt;如果想让可空值列的映射属性既能在Linq语句里作为条件，又能让调用者方便使用的话，只能像下面这样定义它们，对，是它们：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;[ColumnAttribute(Name = &amp;quot;RatingCount&amp;quot;, Storage = &amp;quot;_ratingCount&amp;quot;, FieldType = &amp;quot;Number&amp;quot;)]
public double? RatingCountField
{
  get { return _ratingCount; }
}
protected double? _ratingCount;
public int RatingCount { get { return this._ratingCount.HasValue ? (int)this._ratingCount.Value : 0; } }
&lt;/pre&gt;
&lt;p&gt;平常使用int类型的RatingCount，在Lambda表达式里查询时使用double?类型的RatingCountField。&lt;/p&gt;
&lt;p&gt;坦白说，我很讨厌这样的代码，两个含义相同的属性必然会让其他阅读者感到困惑。&lt;/p&gt;
&lt;p&gt;此外，如果列是一个查阅项（譬如Author列），我们可以做到映射这个查阅项的完整字符串（譬如“12;#windstyle\chai”），或者查阅项的ID（譬如“12”），或者查阅项的值（譬如“windstyle\chai”），所做的仅仅是在ColumnAttribute里指定IsLookupId或IsLookupValue（如果要拿到完整字符串，则什么都别指定）：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;[Column(Name = &amp;quot;Author&amp;quot;, Storage = &amp;quot;_authorId&amp;quot;, FieldType = &amp;quot;Text&amp;quot;, IsLookupId = true)]
public int AuthorId
{
  get { return _authorId; }
}
protected int _authorId;
&lt;/pre&gt;
&lt;p&gt;而且如果指定了IsLookupId，就可以在Linq语句中使用这一属性来做查询了。&lt;/p&gt;
&lt;p&gt;以上提到的都是关于列与属性的映射，然而有一些列很难通过简单的映射变成属性，那就需要另外一种机制：自定义映射。&lt;/p&gt;
&lt;p&gt;自定义映射需要实体类实现ICustomMapping接口，并实现它的三个成员方法MapFrom、MapTo和Resolve，我们这里只讨论只读实体类的情况，只需实现MapFrom即可：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;[CustomMapping(Columns = new string[] { Attachments&amp;quot; })]
public override void MapFrom(object listItem)
{
  var item = listItem as Microsoft.SharePoint.SPListItem;
  this.IsRootPost = item[&amp;quot;IsRootPost&amp;quot;].ToString();
  if (this.IsRootPost == &amp;quot;1&amp;quot;)
    this.Url = item.Web.Url + &amp;quot;/&amp;quot; + item.Folder.Url;
  else
    this.Url = new Uri(new Uri(item.Web.Url), item.ParentList.DefaultDisplayFormUrl + &amp;quot;?id=&amp;quot; + item.ID).ToString();
}
&lt;/pre&gt;
&lt;p&gt;MapFrom方法包含一个listItem参数，可以通过它来拿到SPListItem的列值，具体能拿到哪些列，需要在修饰MapFrom的CustomMappingAttribute中指定。&lt;/p&gt;
&lt;p&gt;在使用Lambda表达式进行查询时，CustomMappingAttribute中指定的列名以及之前属性映射时指定的列名都会成为ViewFields的一员。&lt;/p&gt;
&lt;p&gt;但需要注意的是，如果你在Lambda表达式中使用了通过MapFrom映射而来的属性，那么它将不会出现在CAML的Query语句中，Linq to SharePoint采取的方法是把所有SPlistItem都获取并转换成实体类，然后通过Linq to Objects来进行第二次查询（而普通的映射属性则不存在这个问题）。&lt;/p&gt;
&lt;p&gt;这当然是极大的性能隐患，然而在Linq to SharePoint中，类似的性能隐患还不止这一处，而且稍不注意就会中招。&lt;/p&gt;
&lt;p&gt;譬如根据ID来查找某一Item，我们通常会写出这样的代码：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;var item = list.First(i =&amp;gt; i.Id == root.ID);
&lt;/pre&gt;
&lt;p&gt;或者&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;var item = list.Where(i =&amp;gt; i.Id == root.ID).First();
&lt;/pre&gt;
&lt;p&gt;或者&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;var item = list.Where(i =&amp;gt; i.Id == root.ID).Single();
&lt;/pre&gt;
&lt;p&gt;这三行代码看起来没有任何问题，而且最终也会被翻译成一模一样的CAML（我省去了ViewFields）：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;View&amp;gt;
  &amp;lt;Query&amp;gt;
    &amp;lt;Where&amp;gt;
      &amp;lt;Eq&amp;gt;
        &amp;lt;FieldRef Name=&amp;quot;ID&amp;quot; /&amp;gt;
        &amp;lt;Value Type=&amp;quot;Counter&amp;quot;&amp;gt;16&amp;lt;/Value&amp;gt;
      &amp;lt;/Eq&amp;gt;
    &amp;lt;/Where&amp;gt;
  &amp;lt;/Query&amp;gt;
  &amp;lt;RowLimit Paged=&amp;quot;TRUE&amp;quot;&amp;gt;2147483647&amp;lt;/RowLimit&amp;gt;
&amp;lt;/View&amp;gt;&lt;/pre&gt;
&lt;p&gt;注意RowLimit，它的值居然是2147483647，这表示查询会返回列表中的所有条目，并将它们都转换成实体类，然后再使用Linq to Objects来进行查询。&lt;/p&gt;
&lt;p&gt;MSDN的这篇&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ff798478.aspx&quot;&gt;文档&lt;/a&gt;中的“Additional Performance Considerations”一节虽然明确了哪些方法会导致这种行为，但First和Single这两个方法居然都被标记为Efficient。&lt;/p&gt;
&lt;p&gt;那么正确的获取单个条目的查询表达式该怎么写呢？使用Take方法，只有Take方法才会正确的翻译成RowLimit：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;this.Root = list.Where(i =&amp;gt; i.Id == root.ID).Take(1).Single();
&lt;/pre&gt;
&lt;p&gt;它会被翻译成（同样省去了ViewFields）：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;View&amp;gt;
  &amp;lt;Query&amp;gt;
    &amp;lt;Where&amp;gt;
      &amp;lt;Eq&amp;gt;
        &amp;lt;FieldRef Name=&amp;quot;ID&amp;quot; /&amp;gt;
        &amp;lt;Value Type=&amp;quot;Counter&amp;quot;&amp;gt;16&amp;lt;/Value&amp;gt;
      &amp;lt;/Eq&amp;gt;
    &amp;lt;/Where&amp;gt;
  &amp;lt;/Query&amp;gt;
  &amp;lt;RowLimit Paged=&amp;quot;TRUE&amp;quot;&amp;gt;1&amp;lt;/RowLimit&amp;gt;
&amp;lt;/View&amp;gt;
&lt;/pre&gt;
&lt;p&gt;同样的试验还可以参考&lt;a href=&quot;http://www.sharepointblues.com/2010/09/08/linq-to-sharepoint-performance-pitfalls/&quot;&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;此外，我们知道Linq可以使用Take和Skip方法来进行数据分页，但在Linq to SharePoint中，Skip方法并不会翻译成CAML的分页语句，它还是会拿到所有条目。&lt;/p&gt;
&lt;p&gt;写到这里，基本上已经把我所遇到的所有难以接受的部分都介绍完了，其实前面几条，若不是有严重的代码洁癖的话，也可以不必在意。&lt;/p&gt;
&lt;p&gt;最后提到的性能问题才是关键所在，而且你很难通过阅读代码来发现问题所在，微软的官方文档对性能问题的解释也模棱两可，一会儿说性能很棒，一会儿又说可能会导致极差的性能。所以最好还是检查一下每一条查询语句生成的CAML是否有问题（DataContext的Log属性会输出所有翻译后的CAML）。&lt;/p&gt;
&lt;p&gt;现在你应该明白标题的含义了。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/639608309/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/04/11/linq-to-sharepoint-just-looks-beautiful/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://coding.windstyle.cn/2012/04/11/linq-to-sharepoint-just-looks-beautiful/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>Linq to SharePoint是SharePoint 2010引入的一组新API，在这之前，如果我们想要按照条件过滤SharePoint列表中的数据，只能通过CAML。 但使用CAML并不是件令人身心愉悦的事情，至少我是这么认为的。我觉得在代码中嵌入一块冗长的XML字符串非常破坏美感，我尤其喜欢强类型，所以一直很难接受SPListItem用字符串作为键值去获取Field值的方式，更别提这些值都是Object类型，还得再经过一次转换。 所以我比较喜欢将SPListItem转换成实体类来使用，只不过一直以来的做法都是自己写实体类和转换方法。而Linq to SharePoint则可以自动将列表映射为实体类，并且可以使用Linq语句来进行查询，看上去很美！ 那么Linq to SharePoint能不能帮我彻底拜托CAML呢，趁着重构代码的机会研究了一下，在这里简单总结一下。 前面说过Linq to SharePoint可以自动生成列表的实体类，这是通过一个叫做SPMetal的工具来实现的，具体的用法请查阅这里。 SPMetal会根据实际的列名来生成实体类中的属性名，所以如果你的列名是中文的话（譬如你安装了中文版SharePoint），你会得到一份非常诡异且冗长的代码文件。 当然，如果你能接受中英文混排的代码的话，这倒也不是什么问题。 SPMetal生成的属性大多是下面这个样子的： Body属性被附加了一个ColumnAttribute，它的作用是将属性和SharePoint中的某一列关联起来。在它的命名参数中，Name表示的就是SharePoint中的列名，FieldType指列的类型，Storage表示的是实体类中用来存放列值的变量，可以看到这里为它指定的是一个变量，而不是Body属性，也就是说，在初始化这一实体的时候，该列的值会直接赋给_body变量，而不经过Body属性。那么Body属性的set访问器又是用来干什么的呢？实际上它的作用只是为了提供一种更改列值的机制，这一点从它复杂的内部流程也能看出端倪。 如果你只是为了查询方便，并不需要修改和提交数据的话，完全可以使用下面的只读版本： 此外，如果列表的包含一些设置为可空值的列的话，它们会被映射成一个Nullable&amp;#60;T&amp;#62;类型，如下所示： 虽然可以理解这么做的原因，但是却很难接受这种代码。尤其是在HTML中做绑定时，你不得不针对Nullable属性额外写一些代码来处理它的非空情况。 好在我们可以将属性本身改成非空的类型，然后在get访问器里根据情况返回真实的值或者默认值： 但要注意Storage指向的变量还得是Nullable类型，以保存列的真实的值（包括空值）；属性的类型虽然可以改为非空类型，但要注意类型一定要和对应的变量相同，因为ColumnAttribute会在初始化时检查属性的实际类型。我曾尝试写过下面这样的属性，结果只收获了一个异常： 为什么想要这么做呢？因为我实在想不出投票总数为什么会是一个小数？ 如果你刚巧需要使用Linq语句查询列表，而且查询条件刚巧也是一个包含可空值的列的话，就不能用上面提到的方法来修改属性的类型了，否则Linq to SharePoint将无法生成CAML，结果也是以异常告终。 如果想让可空值列的映射属性既能在Linq语句里作为条件，又能让调用者方便使用的话，只能像下面这样定义它们，对，是它们： 平常使用int类型的RatingCount，在Lambda表达式里查询时使用double?类型的RatingCountField。 坦白说，我很讨厌这样的代码，两个含义相同的属性必然会让其他阅读者感到困惑。 此外，如果列是一个查阅项（譬如Author列），我们可以做到映射这个查阅项的完整字符串（譬如“12;#windstyle\chai”），或者查阅项的ID（譬如“12”），或者查阅项的值（譬如“windstyle\chai”），所做的仅仅是在ColumnAttribute里指定IsLookupId或IsLookupValue（如果要拿到完整字符串，则什么都别指定）： 而且如果指定了IsLookupId，就可以在Linq语句中使用这一属性来做查询了。 以上提到的都是关于列与属性的映射，然而有一些列很难通过简单的映射变成属性，那就需要另外一种机制：自定义映射。 自定义映射需要实体类实现ICustomMapping接口，并实现它的三个成员方法MapFrom、MapTo和Resolve，我们这里只讨论只读实体类的情况，只需实现MapFrom即可： MapFrom方法包含一个listItem参数，可以通过它来拿到SPListItem的列值，具体能拿到哪些列，需要在修饰MapFrom的CustomMappingAttribute中指定。 在使用Lambda表达式进行查询时，CustomMappingAttribute中指定的列名以及之前属性映射时指定的列名都会成为ViewFields的一员。 但需要注意的是，如果你在Lambda表达式中使用了通过MapFrom映射而来的属性，那么它将不会出现在CAML的Query语句中，Linq to SharePoint采取的方法是把所有SPlistItem都获取并转换成实体类，然后通过Linq to Objects来进行第二次查询（而普通的映射属性则不存在这个问题）。 这当然是极大的性能隐患，然而在Linq to SharePoint中，类似的性能隐患还不止这一处，而且稍不注意就会中招。 譬如根据ID来查找某一Item，我们通常会写出这样的代码： 或者 或者 这三行代码看起来没有任何问题，而且最终也会被翻译成一模一样的CAML（我省去了ViewFields）： 注意RowLimit，它的值居然是2147483647，这表示查询会返回列表中的所有条目，并将它们都转换成实体类，然后再使用Linq to Objects来进行查询。 MSDN的这篇文档中的“Additional Performance Considerations”一节虽然明确了哪些方法会导致这种行为，但First和Single这两个方法居然都被标记为Efficient。 那么正确的获取单个条目的查询表达式该怎么写呢？使用Take方法，只有Take方法才会正确的翻译成RowLimit： [...]&lt;img src=&quot;http://www1.feedsky.com/t1/639608309/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/04/11/linq-to-sharepoint-just-looks-beautiful/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>Linq</category><category>SharePoint</category><category>SharePoint 2010</category><category>CAML</category><category>Performance</category><category>Linq to SharePoint</category><pubDate>Wed, 11 Apr 2012 14:32:44 +0800</pubDate><author>Windie Chai</author><comments>http://coding.windstyle.cn/2012/04/11/linq-to-sharepoint-just-looks-beautiful/#comments</comments><guid isPermaLink="false">http://coding.windstyle.cn/?p=1151</guid><dc:creator>Windie Chai</dc:creator><fs:srclink>http://coding.windstyle.cn/2012/04/11/linq-to-sharepoint-just-looks-beautiful/</fs:srclink><fs:srcfeed>http://coding.windstyle.cn/feed/</fs:srcfeed><fs:itemid>feedsky/xiaoshatiantec/~7883976/639608309/1488721</fs:itemid></item><item><title>Windows Phone自定义主题</title><link>http://coding.windstyle.cn/2012/03/08/windows-phone-custom-theme/</link><content:encoded>&lt;p&gt;我们知道Windows Phone默认的主题系统是由黑白两色为背景和一些强调色组成的，用户可以随意切换。通常来说，应用开发者无需关心这一部分，系统会去更新相关的资源，然后再体现在应用中。&lt;/p&gt;
&lt;p&gt;但有一些时候，我们基于品牌等因素的考量，可能不想使用Windows Phone的默认主题。比如我开发的“豆芽”是豆瓣网的一个客户端，我希望尽可能贴近豆瓣网本身清新的风格，而不是给用户呈现一个和豆瓣网风格大相径庭的黑色背景的界面；再比如我想让应用使用Windows Phone的默认字体（等线），而不是SDK的默认字体（雅黑）。&lt;/p&gt;
&lt;p&gt;这些都需要我们去自定义应用的主题。&lt;span id=&quot;more-1148&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;在介绍如何创建自定义主题之前，先来简单的描述一下Windows Phone主题的原理。&lt;/p&gt;
&lt;p&gt;在Windows Phone中，系统预定义了许多资源，这些资源包括了画笔、颜色、字体、粗细、字号、文本样式等等最基本的元素（详细的资源名称可以查看&lt;a href=&quot;http://msdn.microsoft.com/zh-cn/library/ff769552%28v=vs.92%29.aspx&quot; target=&quot;_blank&quot;&gt;这里&lt;/a&gt;）。此外，Windows Phone中的所有控件都会有自己的样式，样式中还包括了定义控件布局的模板，而模板又利用系统内置的资源定义了控件在各种状态下的外观（所以我们在XAML中随处可以见类似{StaticResource PhoneBackgroundBrush}这样的对内置资源的引用）。&lt;/p&gt;
&lt;p&gt;所以我们可以想到，修改内置资源或者修改控件的样式都可以达到自定义主题的效果。&lt;/p&gt;
&lt;p&gt;在早期的Windows Phone v7.0），我们可以使用前一种方式，只需要在应用中增加一个ResourceDictionary的XAML文件，里边添加若干和系统资源相同键名的资源，即可实现对系统资源的覆盖。&lt;/p&gt;
&lt;p&gt;但这种方法在Mango （v7.1）中无效了，它被当作一个Bug修复了，所以我们只能另寻方法。代价最小的一种方法是在App初始化的时候动态的读取我们定义的ResourceDictionary，并替换系统内置资源。具体的步骤可以参考&lt;a href=&quot;http://windowsphonegeek.com/articles/Windows-Phone-Mango-Custom-application-Theme-Step-by-Step&quot; target=&quot;_blank&quot;&gt;这里&lt;/a&gt; ，我就不赘述了。&lt;/p&gt;
&lt;p&gt;此外，还可以利用Mango带来的另外一个变化，新的Silverlight 4带来的“隐式样式”(Implicit Style)。隐式样式是指只有TargetType却没有指定Key的Style，在Silverlight 4中，会将这个Style应用到所有匹配的TargetType对象上。&lt;/p&gt;
&lt;p&gt;我们可以利用“隐式样式”来更改内置控件的样式，只需要将需要修改的控件的样式添加到应用的ResourceDictionary中，将其Key值去掉即可（当然不去掉也可以，这就需要手工设置所有匹配控件的Style属性）。&lt;/p&gt;
&lt;p&gt;但一般情况下，既然我们想要更改应用级别的主题，基本上我们会修改整套配色方案，如果单纯用“隐式样式”来实现的话，我们就需要实现所有控件的隐式样式，看起来似乎也不是一件简单的事情。&lt;/p&gt;
&lt;p&gt;本文来介绍另外一种方法，这种方法不仅实现了所有控件的样式，还一并接管了所有的内置资源，但它的实现过程却一点儿也不复杂。&lt;/p&gt;
&lt;p&gt;首先&lt;/p&gt;
&lt;p&gt;我们在项目中添加一个XAML文件，用来存放新的主题，这里将文件名定为“CustomTheme.xaml”，下面是它的内容：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;ResourceDictionary

xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;

xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;

xmlns:System=&amp;quot;clr-namespace:System;assembly=mscorlib&amp;quot;&amp;gt;

&amp;lt;/ResourceDictionary&amp;gt;&lt;/pre&gt;
&lt;p&gt;然后编辑App.xaml，添加相应的ResourceDictionary：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;Application.Resources&amp;gt;

&amp;lt;ResourceDictionary&amp;gt;

&amp;lt;ResourceDictionary.MergedDictionaries&amp;gt;

&amp;lt;ResourceDictionary Source=&amp;quot;CustomTheme.xaml&amp;quot;/&amp;gt;

&amp;lt;/ResourceDictionary.MergedDictionaries&amp;gt;

&amp;lt;/ResourceDictionary&amp;gt;

&amp;lt;/Application.Resources&amp;gt;&lt;/pre&gt;
&lt;p&gt;接着打开Windows Phone SDK附带的设计资源文件夹：C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Design。我们会看到若干文件夹，这些文件夹都对应于Windows Phone中的一个主题搭配，譬如LightGreen表示浅色背景色和绿色强调色的搭配。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/03/clip_image001.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;clip_image001&quot; src=&quot;http://coding.windstyle.cn/files/2012/03/clip_image001_thumb.png&quot; alt=&quot;clip_image001&quot; width=&quot;417&quot; height=&quot;272&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;挑选一个最贴近我们想要的主题配色的文件夹打开，我们会看到两个XAML文件，其中ThemeResources.xaml中定义了系统资源，System.Windows.xaml中定义了大多数控件的样式。&lt;/p&gt;
&lt;p&gt;将ThemeResources.xaml和System.Windows.xaml添加到项目中，由于System.Windows.xaml引用了ThemeResources.xaml中定义的资源，所以在System.Windows.xaml的根元素下添加一个ResourceDictionary来引用ThemeResources.xaml（否则在运行时会抛出找不到资源的异常）：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;ResourceDictionary.MergedDictionaries&amp;gt;

&amp;lt;ResourceDictionary Source=&amp;quot;ThemeResources.xaml&amp;quot;/&amp;gt;

&amp;lt;/ResourceDictionary.MergedDictionaries&amp;gt;&lt;/pre&gt;
&lt;p&gt;然后在我们的CustomTheme.xaml中也添加一个对System.Windows.xaml引用的ResourceDictionary：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;ResourceDictionary.MergedDictionaries&amp;gt;

&amp;lt;ResourceDictionary Source=&amp;quot;System.Windows.xaml&amp;quot;/&amp;gt;

&amp;lt;/ResourceDictionary.MergedDictionaries&amp;gt;&lt;/pre&gt;
&lt;p&gt;现在这几个文件的关系是：App.xaml引用了CustomTheme.xaml,CustomTheme.xaml引用了System.Windows.xaml，System.Windows.xaml引用了ThemeResources.xaml。也就是说，在应用运行时，这几个XAML会被全部加载。&lt;/p&gt;
&lt;p&gt;至此，我们的应用中已经包含了Windows Phone的几乎所有资源和样式，但无论我们怎么修改它们的值，都不会影响应用在运行时呈现的外观。因为我们所有的模版和页面元素依然引用了系统内置的资源，而这些资源是不可覆盖的。&lt;/p&gt;
&lt;p&gt;这里有个奇怪的现象，如果我们修改了这些资源的值，是可以在设计器中看到效果的，但丝毫不会影响运行时的效果，我相信这也是一个迟早要修复的Bug。&lt;/p&gt;
&lt;p&gt;回到正题，既然我们已经包含了Windows Phone的几乎所有的资源和样式，那还何必去覆盖系统预置的资源和模版呢？直接使用我们自己的不就好了吗？&lt;/p&gt;
&lt;p&gt;没错，就是这样。&lt;/p&gt;
&lt;p&gt;我们观察到Windows Phone内置的资源和样式的名称都以“Phone”开头，非常有规律，也就非常容易替换。所以接下来我们在整个项目（或解决方案，取决于你的实际情况）里搜索x:Key=”Phone这个字符串，将其替换为x:Key=”Custom，这样会将所有资源的名称修改为CustomXXX；然后在搜索{StaticResource Phone开头的字符串，将其替换为{StaticResource Custom，这样会把所有对系统资源的引用修改为对应用内资源的引用。&lt;/p&gt;
&lt;p&gt;如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/03/clip_image002.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;clip_image002&quot; src=&quot;http://coding.windstyle.cn/files/2012/03/clip_image002_thumb.png&quot; alt=&quot;clip_image002&quot; width=&quot;550&quot; height=&quot;393&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;完成这步操作之后，我们的应用就已经基本和Windows Phone内置主题说再见了，这时我们可以修改一些资源的值，运行一下看看效果：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/03/clip_image003.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;clip_image003&quot; src=&quot;http://coding.windstyle.cn/files/2012/03/clip_image003_thumb.png&quot; alt=&quot;clip_image003&quot; width=&quot;480&quot; height=&quot;800&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;不仅仅是颜色，因为我们已经将系统内置的绝大多数样式都包含了进来了，所以还可以修改控件的布局。譬如我们想更改CheckBox的对钩的样式，没有问题，它在模版中使用一个名为CheckMark的Path来表示的，直接修改就好：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/03/clip_image004.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;clip_image004&quot; src=&quot;http://coding.windstyle.cn/files/2012/03/clip_image004_thumb.png&quot; alt=&quot;clip_image004&quot; width=&quot;353&quot; height=&quot;83&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;前面我一直在强调我们只包含了“绝大多数模版”，是因为还有一些控件的模版并未在System.Windows.xaml中定义，譬如Panorama和Pivot，对于这两个控件的样式我们该如何自定义呢？&lt;/p&gt;
&lt;p&gt;需要一些小手段，我们用.NET Reflector这个工具打开C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Libraries\Silverlight\Microsoft.Phone.Controls.dll，查看它的Resources，将MicrosoftPhone.Controls.g.resources中的themes/generic.xaml保存下来。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/03/clip_image005.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;clip_image005&quot; src=&quot;http://coding.windstyle.cn/files/2012/03/clip_image005_thumb.png&quot; alt=&quot;clip_image005&quot; width=&quot;550&quot; height=&quot;446&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个文件定义了Panorama和Pivot控件的样式，同样将其添加到项目中。&lt;/p&gt;
&lt;p&gt;然后在项目中添加对Microsoft.Phone.Controls.dll的引用并将generic.xaml文件根元素中定义的两个命名空间（local和localPrimitives）的值修改一下：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;xmlns:local=&amp;quot;clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls&amp;quot;

xmlns:localPrimitives=&amp;quot;clr-namespace:Microsoft.Phone.Controls.Primitives;assembly=Microsoft.Phone.Controls&amp;quot;&lt;/pre&gt;
&lt;p&gt;现在我们需要把generic.xaml插入到之前创建好的“资源引用链”中，先在generic.xaml文件的根元素下增加对System.Windows.xaml的引用：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;ResourceDictionary.MergedDictionaries&amp;gt;

&amp;lt;ResourceDictionary Source=&amp;quot;System.Windows.xaml&amp;quot;/&amp;gt;

&amp;lt;/ResourceDictionary.MergedDictionaries&amp;gt;&lt;/pre&gt;
&lt;p&gt;再将CustomTheme.xaml中对System.Windows.xaml的引用改为对generic.xaml的引用。&lt;/p&gt;
&lt;p&gt;现在这几个文件的关系变成了：App.xaml应用了CustomTheme.xaml,CustomTheme.xaml引用了generic.xaml，generic.xaml引用了System.Windows.xaml，System.Windows.xaml引用了ThemeResources.xaml。&lt;/p&gt;
&lt;p&gt;OK，现在再添加一个Panorama页面，修改一下布局（Title的尺寸），试试效果：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/03/clip_image006.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;clip_image006&quot; src=&quot;http://coding.windstyle.cn/files/2012/03/clip_image006_thumb.png&quot; alt=&quot;clip_image006&quot; width=&quot;480&quot; height=&quot;801&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;方法介绍完了，简单归纳一下，就是找出系统内置的资源和样式，添加到应用的项目中，修改所有资源和样式的Key值，修改所有对系统内置资源和样式的引用，听起来似乎工程浩大，其实只是几步简单的复制粘贴和查找替换。&lt;/p&gt;
&lt;p&gt;唯一比较麻烦的是要维护几个xaml文件之间的互相引用，还要保持一定的顺序，其实你也可以不必这么做，如果你愿意的话，完全可以把ThemeResources.xaml、System.Windows.xaml和generic.xaml文件根元素中的内容依次复制到CustomTheme.xaml文件中，这样只需要CustomTheme.xaml一个文件就可以了，但我个人认为把这几个文件混在一块并不利于维护。&lt;/p&gt;
&lt;p&gt;当然，这种方法也并不是十分完美的，在我看来，它存在如下一些缺陷：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每次添加一个新的页面，都要检查其中对系统内置资源的引用，将其修改为引用我们接管的资源&lt;/li&gt;
&lt;li&gt;假如微软在将来的版本中修改了内置样式的模板，我们也得做对应的修改，这就会比较棘手，我的方法是，在修改这些资源的值的时候，在其旁边加一个注释来表明这个值被修改过（譬如&amp;lt;!&amp;#8211;Changed&amp;#8211;&amp;gt;），将来微软升级了SDK，我们可以先备份一下现有XAML文件，然后重复之前的步骤接管系统内置资源和样式，再根据备份文件中的特定注释来逐一修改。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，你可能会担心最后在接管Panorama和Pivot样式的时候使用了一点Hack的手段，会不会被市场拒绝，对此我也不能给出确切的答案，我只能说，“&lt;a href=&quot;http://www.windowsphone.com/en-HK/apps/8852eb99-68fb-4bf4-8c7b-e0c0ff61cd58&quot; target=&quot;_blank&quot;&gt;豆芽&lt;/a&gt;”也使用了这种方法，目前还没有遇到这方面的问题。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/03/CustomThemeDemo.zip&quot;&gt;轻触这里下载源码&lt;/a&gt;。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/639608310/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/03/08/windows-phone-custom-theme/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://coding.windstyle.cn/2012/03/08/windows-phone-custom-theme/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>我们知道Windows Phone默认的主题系统是由黑白两色为背景和一些强调色组成的，用户可以随意切换。通常来说，应用开发者无需关心这一部分，系统会去更新相关的资源，然后再体现在应用中。 但有一些时候，我们基于品牌等因素的考量，可能不想使用Windows Phone的默认主题。比如我开发的“豆芽”是豆瓣网的一个客户端，我希望尽可能贴近豆瓣网本身清新的风格，而不是给用户呈现一个和豆瓣网风格大相径庭的黑色背景的界面；再比如我想让应用使用Windows Phone的默认字体（等线），而不是SDK的默认字体（雅黑）。 这些都需要我们去自定义应用的主题。 在介绍如何创建自定义主题之前，先来简单的描述一下Windows Phone主题的原理。 在Windows Phone中，系统预定义了许多资源，这些资源包括了画笔、颜色、字体、粗细、字号、文本样式等等最基本的元素（详细的资源名称可以查看这里）。此外，Windows Phone中的所有控件都会有自己的样式，样式中还包括了定义控件布局的模板，而模板又利用系统内置的资源定义了控件在各种状态下的外观（所以我们在XAML中随处可以见类似{StaticResource PhoneBackgroundBrush}这样的对内置资源的引用）。 所以我们可以想到，修改内置资源或者修改控件的样式都可以达到自定义主题的效果。 在早期的Windows Phone v7.0），我们可以使用前一种方式，只需要在应用中增加一个ResourceDictionary的XAML文件，里边添加若干和系统资源相同键名的资源，即可实现对系统资源的覆盖。 但这种方法在Mango （v7.1）中无效了，它被当作一个Bug修复了，所以我们只能另寻方法。代价最小的一种方法是在App初始化的时候动态的读取我们定义的ResourceDictionary，并替换系统内置资源。具体的步骤可以参考这里 ，我就不赘述了。 此外，还可以利用Mango带来的另外一个变化，新的Silverlight 4带来的“隐式样式”(Implicit Style)。隐式样式是指只有TargetType却没有指定Key的Style，在Silverlight 4中，会将这个Style应用到所有匹配的TargetType对象上。 我们可以利用“隐式样式”来更改内置控件的样式，只需要将需要修改的控件的样式添加到应用的ResourceDictionary中，将其Key值去掉即可（当然不去掉也可以，这就需要手工设置所有匹配控件的Style属性）。 但一般情况下，既然我们想要更改应用级别的主题，基本上我们会修改整套配色方案，如果单纯用“隐式样式”来实现的话，我们就需要实现所有控件的隐式样式，看起来似乎也不是一件简单的事情。 本文来介绍另外一种方法，这种方法不仅实现了所有控件的样式，还一并接管了所有的内置资源，但它的实现过程却一点儿也不复杂。 首先 我们在项目中添加一个XAML文件，用来存放新的主题，这里将文件名定为“CustomTheme.xaml”，下面是它的内容： 然后编辑App.xaml，添加相应的ResourceDictionary： 接着打开Windows Phone SDK附带的设计资源文件夹：C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Design。我们会看到若干文件夹，这些文件夹都对应于Windows Phone中的一个主题搭配，譬如LightGreen表示浅色背景色和绿色强调色的搭配。 挑选一个最贴近我们想要的主题配色的文件夹打开，我们会看到两个XAML文件，其中ThemeResources.xaml中定义了系统资源，System.Windows.xaml中定义了大多数控件的样式。 将ThemeResources.xaml和System.Windows.xaml添加到项目中，由于System.Windows.xaml引用了ThemeResources.xaml中定义的资源，所以在System.Windows.xaml的根元素下添加一个ResourceDictionary来引用ThemeResources.xaml（否则在运行时会抛出找不到资源的异常）： 然后在我们的CustomTheme.xaml中也添加一个对System.Windows.xaml引用的ResourceDictionary： 现在这几个文件的关系是：App.xaml引用了CustomTheme.xaml,CustomTheme.xaml引用了System.Windows.xaml，System.Windows.xaml引用了ThemeResources.xaml。也就是说，在应用运行时，这几个XAML会被全部加载。 至此，我们的应用中已经包含了Windows Phone的几乎所有资源和样式，但无论我们怎么修改它们的值，都不会影响应用在运行时呈现的外观。因为我们所有的模版和页面元素依然引用了系统内置的资源，而这些资源是不可覆盖的。 这里有个奇怪的现象，如果我们修改了这些资源的值，是可以在设计器中看到效果的，但丝毫不会影响运行时的效果，我相信这也是一个迟早要修复的Bug。 回到正题，既然我们已经包含了Windows Phone的几乎所有的资源和样式，那还何必去覆盖系统预置的资源和模版呢？直接使用我们自己的不就好了吗？ 没错，就是这样。 我们观察到Windows Phone内置的资源和样式的名称都以“Phone”开头，非常有规律，也就非常容易替换。所以接下来我们在整个项目（或解决方案，取决于你的实际情况）里搜索x:Key=”Phone这个字符串，将其替换为x:Key=”Custom，这样会将所有资源的名称修改为CustomXXX；然后在搜索{StaticResource Phone开头的字符串，将其替换为{StaticResource Custom，这样会把所有对系统资源的引用修改为对应用内资源的引用。 如下图所示： 完成这步操作之后，我们的应用就已经基本和Windows Phone内置主题说再见了，这时我们可以修改一些资源的值，运行一下看看效果： 不仅仅是颜色，因为我们已经将系统内置的绝大多数样式都包含了进来了，所以还可以修改控件的布局。譬如我们想更改CheckBox的对钩的样式，没有问题，它在模版中使用一个名为CheckMark的Path来表示的，直接修改就好： [...]&lt;img src=&quot;http://www1.feedsky.com/t1/639608310/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/03/08/windows-phone-custom-theme/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>模板</category><category>资源</category><category>样式</category><category>主题</category><category>Windows Phone</category><pubDate>Thu, 08 Mar 2012 09:29:40 +0800</pubDate><author>Windie Chai</author><comments>http://coding.windstyle.cn/2012/03/08/windows-phone-custom-theme/#comments</comments><guid isPermaLink="false">http://coding.windstyle.cn/?p=1148</guid><dc:creator>Windie Chai</dc:creator><fs:srclink>http://coding.windstyle.cn/2012/03/08/windows-phone-custom-theme/</fs:srclink><fs:srcfeed>http://coding.windstyle.cn/feed/</fs:srcfeed><fs:itemid>feedsky/xiaoshatiantec/~7883976/639608310/1488721</fs:itemid></item><item><title>SharePoint 2010 JavaScript技巧两则</title><link>http://coding.windstyle.cn/2012/02/26/two-sharepoint-2010-javascript-tricks/</link><content:encoded>&lt;p&gt;SharePoint开发，从某种程度上，也可以认为是Web开发，所以也就不可避免的要使用JavaScript，本文就来介绍SharePoint 2010上的两则JavaScript小技巧。&lt;span id=&quot;more-1134&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;1.禁用Ribbon，保留导航&lt;/h3&gt;
&lt;p&gt;SharePoint 2010在UI上最大的变化就是和Office一致的Ribbon界面，Ribbon虽然有各种好处，但对于有些类型的网站（譬如面向互联网的网站）来说，Ribbon可能一个令人困扰的东西，那么我们怎么去掉Ribbon呢？&lt;/p&gt;
&lt;p&gt;首先，我们可以观察到，Ribbon分为两个部分，一部分是上方的Tab，它是一个id为“s4-ribbonrow”的div；另一部分是下面的容器（包含导航和实际的操作按钮），它是一个id为“s4-titlerow”的div。&lt;/p&gt;
&lt;p&gt;对于s4-ribbonrow来说，我们可以直接将其隐藏。但对于s4-titlerow来说，直接隐藏却不是一个很好的方法。一来s4-titlerow还包含这导航，二来就算隐藏了，我们的一些触发Ribbon Tab切换的操作（譬如选中某个条目）依然会让Ribbon显示出来，所以我们需要另外一种方法。&lt;/p&gt;
&lt;p&gt;通过跟踪Ribbon相关的JavaScript代码可以发现，触发Ribbon Tab切换的所有事件都会调用一个叫做“_ribbonStartInit”的方法，而且大多数调用之前都会判断_ribbonStartInit的存在性以及类型（只有直接点击Ribbon Tab时不会判断，但Ribbon Tab已经通过s4-ribbonrow隐藏了，所以不会出现脚本错误），所以我们可以将这个变量去掉或者换一个类型，这样切换Ribbon的代码就无法继续执行，Ribbon也就相当于被禁用了，如下面的代码所示：&lt;/p&gt;
&lt;pre class=&quot;brush: jscript; title: ; notranslate&quot;&gt;_ribbonStartInit = &amp;quot;Ribbon Disabled&amp;quot;;&lt;/pre&gt;
&lt;h3&gt;2.让Rating只读&lt;/h3&gt;
&lt;p&gt;Rating也是SharePoint 2010新增的一个功能，但这个功能一旦启用之后，便对所有用户开放，哪怕是只有查看权限的用户也可以进行打分。有时候我们并不喜欢这种默认行为，而是想让Rating信息对某些用户只读，想要实现这个功能，我们先来分析一下Rating控件。&lt;/p&gt;
&lt;p&gt;SharePoint 2010的Rating控件会Render成一个span，它的ID以“RatingsCtrl_”开头，内部包含一个a和一个span。除此之外，每一个Rating控件都会在页面上注册一段JavaScript，用来初始化一个RatingsControl对象，而这个对象在初始化的时候又会向Rating控件这个span添加一些事件绑定（mouseover、mouseout、keypress）。&lt;/p&gt;
&lt;p&gt;所以我们只需要把这个span上的这几个事件绑定去掉，就可以让Rating控件变为只读了，如下面的代码所示：&lt;/p&gt;
&lt;pre class=&quot;brush: jscript; title: ; notranslate&quot;&gt;function ids_ratingDisabling(){{

var rc =$get('Rating控件ID');

if(rc != null)

$clearHandlers(rc);

}}

_spBodyOnLoadFunctionNames.push('ids_ratingDisabling');&lt;/pre&gt;
&lt;p&gt;如果页面上有多个Rating控件，可以想办法先把这些控件都找出来，然后遍历它们依次执行$clearHandlers方法。&lt;/p&gt;
&lt;p&gt;需要注意的是Rating控件注册的JavaScript会在rating.js加载完成后执行，所以我们的这段代码务必不能过早执行，这里将禁用Rating的函数添加到_spBodyOnLoadFunctionNames中，可以保证我们的代码在执行时，Rating控件自己的代码已经执行完毕了。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/639608311/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/02/26/two-sharepoint-2010-javascript-tricks/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://coding.windstyle.cn/2012/02/26/two-sharepoint-2010-javascript-tricks/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>SharePoint开发，从某种程度上，也可以认为是Web开发，所以也就不可避免的要使用JavaScript，本文就来介绍SharePoint 2010上的两则JavaScript小技巧。 1.禁用Ribbon，保留导航 SharePoint 2010在UI上最大的变化就是和Office一致的Ribbon界面，Ribbon虽然有各种好处，但对于有些类型的网站（譬如面向互联网的网站）来说，Ribbon可能一个令人困扰的东西，那么我们怎么去掉Ribbon呢？ 首先，我们可以观察到，Ribbon分为两个部分，一部分是上方的Tab，它是一个id为“s4-ribbonrow”的div；另一部分是下面的容器（包含导航和实际的操作按钮），它是一个id为“s4-titlerow”的div。 对于s4-ribbonrow来说，我们可以直接将其隐藏。但对于s4-titlerow来说，直接隐藏却不是一个很好的方法。一来s4-titlerow还包含这导航，二来就算隐藏了，我们的一些触发Ribbon Tab切换的操作（譬如选中某个条目）依然会让Ribbon显示出来，所以我们需要另外一种方法。 通过跟踪Ribbon相关的JavaScript代码可以发现，触发Ribbon Tab切换的所有事件都会调用一个叫做“_ribbonStartInit”的方法，而且大多数调用之前都会判断_ribbonStartInit的存在性以及类型（只有直接点击Ribbon Tab时不会判断，但Ribbon Tab已经通过s4-ribbonrow隐藏了，所以不会出现脚本错误），所以我们可以将这个变量去掉或者换一个类型，这样切换Ribbon的代码就无法继续执行，Ribbon也就相当于被禁用了，如下面的代码所示： 2.让Rating只读 Rating也是SharePoint 2010新增的一个功能，但这个功能一旦启用之后，便对所有用户开放，哪怕是只有查看权限的用户也可以进行打分。有时候我们并不喜欢这种默认行为，而是想让Rating信息对某些用户只读，想要实现这个功能，我们先来分析一下Rating控件。 SharePoint 2010的Rating控件会Render成一个span，它的ID以“RatingsCtrl_”开头，内部包含一个a和一个span。除此之外，每一个Rating控件都会在页面上注册一段JavaScript，用来初始化一个RatingsControl对象，而这个对象在初始化的时候又会向Rating控件这个span添加一些事件绑定（mouseover、mouseout、keypress）。 所以我们只需要把这个span上的这几个事件绑定去掉，就可以让Rating控件变为只读了，如下面的代码所示： 如果页面上有多个Rating控件，可以想办法先把这些控件都找出来，然后遍历它们依次执行$clearHandlers方法。 需要注意的是Rating控件注册的JavaScript会在rating.js加载完成后执行，所以我们的这段代码务必不能过早执行，这里将禁用Rating的函数添加到_spBodyOnLoadFunctionNames中，可以保证我们的代码在执行时，Rating控件自己的代码已经执行完毕了。&lt;img src=&quot;http://www1.feedsky.com/t1/639608311/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/02/26/two-sharepoint-2010-javascript-tricks/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>Rating</category><category>SharePoint</category><category>SharePoint 2010</category><category>JavaScript</category><category>Ribbon</category><pubDate>Sun, 26 Feb 2012 10:57:15 +0800</pubDate><author>Windie Chai</author><comments>http://coding.windstyle.cn/2012/02/26/two-sharepoint-2010-javascript-tricks/#comments</comments><guid isPermaLink="false">http://coding.windstyle.cn/?p=1134</guid><dc:creator>Windie Chai</dc:creator><fs:srclink>http://coding.windstyle.cn/2012/02/26/two-sharepoint-2010-javascript-tricks/</fs:srclink><fs:srcfeed>http://coding.windstyle.cn/feed/</fs:srcfeed><fs:itemid>feedsky/xiaoshatiantec/~7883976/639608311/1488721</fs:itemid></item><item><title>CSS文字围绕效果</title><link>http://coding.windstyle.cn/2012/02/10/css-text-around-effect/</link><content:encoded>&lt;p&gt;前两天同事问我能不能用CSS实现这样一个效果，页面上有一段文本，但文本的左下方有一个图片，他希望文本在遇到图片时，能绕开图片。如果图片位于左上方的话，其实很容易做到，我同事遇到的这种情况我之前也没有处理过，研究了一下，发现了一种方法。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1133&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;先来看看最终效果，红色的方块用来模拟图片：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/02/image3.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;image&quot; src=&quot;http://coding.windstyle.cn/files/2012/02/image_thumb3.png&quot; alt=&quot;image&quot; width=&quot;558&quot; height=&quot;109&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;完整的HTML如下：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Untitled Page&amp;lt;/title&amp;gt;
&amp;lt;style&amp;gt;
.left div
{
float: left;
clear: left;
margin-right:5px
}
.left .placeholder
{
margin-right:0px;
width:1px
}
.text
{
line-height: 20px
}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;div&amp;gt;
&amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;placeholder&amp;quot; style=&amp;quot;height: 60px&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div style=&amp;quot;width: 100px; height: 40px; background-color: red&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;text&amp;quot;&amp;gt;
Windows Phone是微软发布的一款手机操作系统，它将微软旗下的Xbox LIVE游戏、Zune音乐与独特的视频体验整合至手机中。2010年10月11日晚上9点30分，微软公司正式发布了智能手机操作系统Windows Phone，同时将谷歌的Android和苹果的IOS列为主要竞争对手。2011年2月，诺基亚与微软达成全球战略同盟并深度合作共同研发，建立庞大的生态系统。
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;
&lt;p&gt;简单解释一下，.left中的所有div都默认将float和clear都设置为left，这样做一方面能保证其他与这些div视觉上相邻的元素都会贴着它们，同时这些div自身又能保证独处一行。所以.text中的文本就会围绕.left中的所有div来呈现。&lt;/p&gt;
&lt;p&gt;.text设置了line-height为20px，这样做是为了给.left中的div带来计算高度上的便利。.left中的第一个div是一个占位符，它的作用是把红色方块向下推一段距离，所以它设置了height为60px，即.text行高的3倍，也就是三行文本（同理红色方块的高度是两行文本）。此外，它的width是1px，而不是0px，这是为了兼容IE7所做的让步。&lt;/p&gt;
&lt;p&gt;如果将这段代码拓展一下，我们还可以实现两边边框都扭曲的文本段，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/02/image4.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;image&quot; src=&quot;http://coding.windstyle.cn/files/2012/02/image_thumb4.png&quot; alt=&quot;image&quot; width=&quot;413&quot; height=&quot;164&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;完整的HTML代码如下：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Untitled Page&amp;lt;/title&amp;gt;
&amp;lt;style&amp;gt;
.border
{
padding:0px;
margin:0px;
list-style:none
}
.border .left
{
float: left;
clear: left;
margin-right:5px;
height:20px;
background-color:Red
}
.border .right
{
float: right;
clear: right;
margin-left:5px;
height:20px;
background-color:Blue
}
.border .placeholder
{
margin-left:0px;
margin-right:0px;
width:1px
}
.text
{
line-height: 20px
}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;div&amp;gt;
&amp;lt;ul class=&amp;quot;border&amp;quot;&amp;gt;
&amp;lt;li class=&amp;quot;left placeholder&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;right&amp;quot; style=&amp;quot;width: 30px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;left&amp;quot; style=&amp;quot;width: 10px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;right&amp;quot; style=&amp;quot;width: 20px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;left&amp;quot; style=&amp;quot;width: 20px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;right&amp;quot; style=&amp;quot;width: 10px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;left&amp;quot; style=&amp;quot;width: 30px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;right placeholder&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;left&amp;quot; style=&amp;quot;width: 20px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;right&amp;quot; style=&amp;quot;width: 10px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;left&amp;quot; style=&amp;quot;width: 10px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;right&amp;quot; style=&amp;quot;width: 20px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;left placeholder&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;right&amp;quot; style=&amp;quot;width: 30px&amp;quot;&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;div class=&amp;quot;text&amp;quot;&amp;gt;
Windows Phone是微软发布的一款手机操作系统，它将微软旗下的Xbox LIVE游戏、Zune音乐与独特的视频体验整合至手机中。2010年10月11日晚上9点30分，微软公司正式发布了智能手机操作系统Windows Phone，同时将谷歌的Android和苹果的IOS列为主要竞争对手。2011年2月，诺基亚与微软达成全球战略同盟并深度合作共同研发，建立庞大的生态系统。
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;
&lt;p&gt;以上代码均在IE7、IE8以及Chrome16中表现良好。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/639608312/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/02/10/css-text-around-effect/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://coding.windstyle.cn/2012/02/10/css-text-around-effect/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>前两天同事问我能不能用CSS实现这样一个效果，页面上有一段文本，但文本的左下方有一个图片，他希望文本在遇到图片时，能绕开图片。如果图片位于左上方的话，其实很容易做到，我同事遇到的这种情况我之前也没有处理过，研究了一下，发现了一种方法。 先来看看最终效果，红色的方块用来模拟图片： 完整的HTML如下： 简单解释一下，.left中的所有div都默认将float和clear都设置为left，这样做一方面能保证其他与这些div视觉上相邻的元素都会贴着它们，同时这些div自身又能保证独处一行。所以.text中的文本就会围绕.left中的所有div来呈现。 .text设置了line-height为20px，这样做是为了给.left中的div带来计算高度上的便利。.left中的第一个div是一个占位符，它的作用是把红色方块向下推一段距离，所以它设置了height为60px，即.text行高的3倍，也就是三行文本（同理红色方块的高度是两行文本）。此外，它的width是1px，而不是0px，这是为了兼容IE7所做的让步。 如果将这段代码拓展一下，我们还可以实现两边边框都扭曲的文本段，如下图所示： 完整的HTML代码如下： 以上代码均在IE7、IE8以及Chrome16中表现良好。&lt;img src=&quot;http://www1.feedsky.com/t1/639608312/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/02/10/css-text-around-effect/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>效果</category><category>CSS</category><category>围绕</category><category>HTML</category><category>Web</category><pubDate>Fri, 10 Feb 2012 20:16:37 +0800</pubDate><author>Windie Chai</author><comments>http://coding.windstyle.cn/2012/02/10/css-text-around-effect/#comments</comments><guid isPermaLink="false">http://coding.windstyle.cn/?p=1133</guid><dc:creator>Windie Chai</dc:creator><fs:srclink>http://coding.windstyle.cn/2012/02/10/css-text-around-effect/</fs:srclink><fs:srcfeed>http://coding.windstyle.cn/feed/</fs:srcfeed><fs:itemid>feedsky/xiaoshatiantec/~7883976/639608312/1488721</fs:itemid></item><item><title>Windows Phone WebBrowser的技巧</title><link>http://coding.windstyle.cn/2012/02/09/windows-phone-webbrowser-tips/</link><content:encoded>&lt;p&gt;无论是在桌面级开发中，还是在手机端开发中，WebBrowser都是一个经常会用到的控件；Windows Phone中的WebBrowser虽然远远没有桌面版那么强大，但依然足够应付常规用途。本文就来介绍几则Windows Phone中的WebBrowser控件的小技巧。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1127&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;1.显示HTML片段&lt;/h3&gt;
&lt;p&gt;WebBrowser的NavigateToString方法可以用来将一段HTML片段显示在WebBrowser中。利用这个方法可以把WebBrowser当作一个增强版的RichTextBox来使用，京东商城的Windows Phone客户端在展示商品信息时就使用了这种技术。而且这种技术还有助于解决Windows Phone中TextBlock显示长文本的一个bug，具体表现为当文本过长时，TextBlock只显示文本的前半段内容，后半段内容不予显示，但却留出了位置（滚动条还能到达，非常诡异），而WebBrowser在显示长文本时就没有这种困扰。&lt;/p&gt;
&lt;p&gt;但NavigateToString并不是完美的，假若传入的字符串中包含中文（或其他UTF-8字符）的话，就会显示为乱码。&lt;/p&gt;
&lt;p&gt;解决这个问题的方法之一是提前对字符串进行转码，可以参考&lt;a href=&quot;http://blog.csdn.net/huangliangjie/article/details/7196464&quot; target=&quot;_blank&quot;&gt;这篇文章&lt;/a&gt;。但这样做的代价是需要遍历所有字符，其实只要把需要显示的HTML片段简单构造成HTML文件，存储到独立存储中，然后再用WebBrowser以常规的方式打开即可解决这个问题。如下面的代码所示：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication())
 {
 if (!file.DirectoryExists(&amp;quot;temp&amp;quot;))
 file.CreateDirectory(&amp;quot;temp&amp;quot;);
 using (IsolatedStorageFileStream fs = new IsolatedStorageFileStream(&amp;quot;temp\\review.html&amp;quot;, FileMode.Create, file))
 {
 string html = &amp;quot;&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;html lang='zh-CN'&amp;gt;&amp;lt;head&amp;gt;&amp;lt;meta http-equiv='Content-Type' content='text/html; charset=utf-8'&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot;;
 html += e.Review.Summary;
 html += &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;
 byte[] bytes = Encoding.UTF8.GetBytes(html);
 fs.Write(bytes, 0, bytes.Length);
 }
 }
 this.wb.Navigate(new Uri(&amp;quot;temp\\review.html&amp;quot;, UriKind.Relative));&lt;/pre&gt;
&lt;h3&gt;2.禁止缩放&lt;/h3&gt;
&lt;p&gt;WebBrowser支持缩放，但有时我们并不需要缩放功能，譬如在用它来解决TextBlock的长文本bug时。&lt;/p&gt;
&lt;p&gt;如果需要禁用一切手势，可以将WebBrowser的IsHitTestVisible设置为False，但这样做的后果是WebBrowser滑动显示内容的功能都会失去。但如果仅仅想要禁用缩放功能，可以在WebBrowser将要显示的HTML的Head中加入这样下面的脚本：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;meta name='viewport' content='width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0' /&amp;gt;&lt;/pre&gt;
&lt;p&gt;关于viewport的更多细节可以参考MSDN Blog的&lt;a href=&quot;http://blogs.msdn.com/b/iemobile/archive/2010/11/22/the-ie-mobile-viewport-on-windows-phone-7.aspx&quot; target=&quot;_blank&quot;&gt;这篇文章&lt;/a&gt;。值得注意的是原文在发表时，Windows Phone中的IE还不支持initial-scale、minimum-scale和maximum-scale，而在最新的Windows Phone Mango更新中，除了initial-scale之外的其余属性都已经可以很好的支持了。&lt;/p&gt;
&lt;h3&gt;3.接管横向滑动&lt;/h3&gt;
&lt;p&gt;如果用WebBrowser来解决TextBlock的bug，那么还有一个问题需要注意，WebBrowser会接管横向滑动手势，用来移动页面位置，也就是说，假如你把WebBrowser方知道Pivot或Panorama控件中时，就没有办法切换到其他Item了（除非从Header部分横向滑动）。&lt;/p&gt;
&lt;p&gt;不过一般在用WebBrowser代替TextBlock时，并需要它内置的横向滑动功能（通常会禁用缩放），所以我们可以想办法侦测发生在WebBrowser上的横向滑动手势，并用来修改Pivot或Panorama的SelectedIndex。所幸的是，Silverlight Toolkit For Windows Phone中有一个组件可以帮我们轻松的完成这项工作。&lt;/p&gt;
&lt;p&gt;首先在Xaml中添加GestureService.GestureListener：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;phone:WebBrowser Name=&amp;quot;wb&amp;quot; Loaded=&amp;quot;wb_Loaded&amp;quot; LoadCompleted=&amp;quot;wb_LoadCompleted&amp;quot;&amp;gt;
 &amp;lt;toolkit:GestureService.GestureListener&amp;gt;
 &amp;lt;toolkit:GestureListener Flick=&amp;quot;GestureListener_Flick&amp;quot; /&amp;gt;
 &amp;lt;/toolkit:GestureService.GestureListener&amp;gt;
 &amp;lt;/phone:WebBrowser&amp;gt;&lt;/pre&gt;
&lt;p&gt;在GestureService.GestureListener的Flick事件中修改Pivot或Panorama的SelectedIndex：&lt;/p&gt;
&lt;pre class=&quot;brush: csharp; title: ; notranslate&quot;&gt;private void GestureListener_Flick(object sender, FlickGestureEventArgs e)
 {
 if (e.Direction.ToString() == &amp;quot;Horizontal&amp;quot;)
 {
 this.p.SelectedIndex = 1;
 }

}&lt;/pre&gt;
&lt;p&gt;除了Flick之外，GestureService还支持Tap、Double Tap、Touch and Hold、Pan、以及Pinch and Stretch多种手势。关于GestureService的更多信息请参考&lt;a href=&quot;http://windowsphonegeek.com/articles/WP7-GestureService-in-depth--key-concepts-and-API&quot; target=&quot;_blank&quot;&gt;这篇文章&lt;/a&gt;。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/639608313/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/02/09/windows-phone-webbrowser-tips/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://coding.windstyle.cn/2012/02/09/windows-phone-webbrowser-tips/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>无论是在桌面级开发中，还是在手机端开发中，WebBrowser都是一个经常会用到的控件；Windows Phone中的WebBrowser虽然远远没有桌面版那么强大，但依然足够应付常规用途。本文就来介绍几则Windows Phone中的WebBrowser控件的小技巧。 1.显示HTML片段 WebBrowser的NavigateToString方法可以用来将一段HTML片段显示在WebBrowser中。利用这个方法可以把WebBrowser当作一个增强版的RichTextBox来使用，京东商城的Windows Phone客户端在展示商品信息时就使用了这种技术。而且这种技术还有助于解决Windows Phone中TextBlock显示长文本的一个bug，具体表现为当文本过长时，TextBlock只显示文本的前半段内容，后半段内容不予显示，但却留出了位置（滚动条还能到达，非常诡异），而WebBrowser在显示长文本时就没有这种困扰。 但NavigateToString并不是完美的，假若传入的字符串中包含中文（或其他UTF-8字符）的话，就会显示为乱码。 解决这个问题的方法之一是提前对字符串进行转码，可以参考这篇文章。但这样做的代价是需要遍历所有字符，其实只要把需要显示的HTML片段简单构造成HTML文件，存储到独立存储中，然后再用WebBrowser以常规的方式打开即可解决这个问题。如下面的代码所示： 2.禁止缩放 WebBrowser支持缩放，但有时我们并不需要缩放功能，譬如在用它来解决TextBlock的长文本bug时。 如果需要禁用一切手势，可以将WebBrowser的IsHitTestVisible设置为False，但这样做的后果是WebBrowser滑动显示内容的功能都会失去。但如果仅仅想要禁用缩放功能，可以在WebBrowser将要显示的HTML的Head中加入这样下面的脚本： 关于viewport的更多细节可以参考MSDN Blog的这篇文章。值得注意的是原文在发表时，Windows Phone中的IE还不支持initial-scale、minimum-scale和maximum-scale，而在最新的Windows Phone Mango更新中，除了initial-scale之外的其余属性都已经可以很好的支持了。 3.接管横向滑动 如果用WebBrowser来解决TextBlock的bug，那么还有一个问题需要注意，WebBrowser会接管横向滑动手势，用来移动页面位置，也就是说，假如你把WebBrowser方知道Pivot或Panorama控件中时，就没有办法切换到其他Item了（除非从Header部分横向滑动）。 不过一般在用WebBrowser代替TextBlock时，并需要它内置的横向滑动功能（通常会禁用缩放），所以我们可以想办法侦测发生在WebBrowser上的横向滑动手势，并用来修改Pivot或Panorama的SelectedIndex。所幸的是，Silverlight Toolkit For Windows Phone中有一个组件可以帮我们轻松的完成这项工作。 首先在Xaml中添加GestureService.GestureListener： 在GestureService.GestureListener的Flick事件中修改Pivot或Panorama的SelectedIndex： 除了Flick之外，GestureService还支持Tap、Double Tap、Touch and Hold、Pan、以及Pinch and Stretch多种手势。关于GestureService的更多信息请参考这篇文章。&lt;img src=&quot;http://www1.feedsky.com/t1/639608313/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/02/09/windows-phone-webbrowser-tips/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>手势</category><category>WebBrowser</category><category>乱码</category><category>HTML</category><category>bug</category><category>Windows Phone</category><pubDate>Thu, 09 Feb 2012 21:46:59 +0800</pubDate><author>Windie Chai</author><comments>http://coding.windstyle.cn/2012/02/09/windows-phone-webbrowser-tips/#comments</comments><guid isPermaLink="false">http://coding.windstyle.cn/?p=1127</guid><dc:creator>Windie Chai</dc:creator><fs:srclink>http://coding.windstyle.cn/2012/02/09/windows-phone-webbrowser-tips/</fs:srclink><fs:srcfeed>http://coding.windstyle.cn/feed/</fs:srcfeed><fs:itemid>feedsky/xiaoshatiantec/~7883976/639608313/1488721</fs:itemid></item><item><title>隐藏SharePoint User Profile页面中的提示文本</title><link>http://coding.windstyle.cn/2012/02/01/hide-tip-text-in-sharepoint-user-profile-page/</link><content:encoded>&lt;p&gt;在SharePoint 2010的User Profile页面中存在一些提示，本文的内容就是如何去掉这些提示而又不影响其他功能，这是一件简单而又意义不大的事情，但我却不小心想复杂了，前后花了几个小时，用jQuery写了几行代码，中间还发现bug修改了一遍，终于发现走了弯路，用区区3行CSS搞定。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1126&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;首先是“标签和注释”页面（thoughts.aspx）中的提示文本，位于标签云的下方，如图所示：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/02/image.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;image&quot; src=&quot;http://coding.windstyle.cn/files/2012/02/image_thumb.png&quot; alt=&quot;image&quot; width=&quot;384&quot; height=&quot;365&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;最下面几行提示文本的标签既没有id也没有class，还好标签云是有class的，可以用它来定位到之后的元素，并将其隐藏，只需一句Style：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;.ms-TagCloud.ms-socialThoughtBoxTags ~ div {display:none;}&lt;/pre&gt;
&lt;p&gt;其中~表示“之后的所有元素”，IE6不支持这个选择器，不过没关系，SharePoint 2010 不支持IE6。&lt;/p&gt;
&lt;p&gt;接着是“概述”页面（person.aspx）的记事板提示文本，这段提示文本是通过AJAX技术动态填充的，仅在没有Notes的情况下显示（包括将Notes全部删除之后）。&lt;/p&gt;
&lt;p&gt;没有Notes时的样子：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/02/image1.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;image&quot; src=&quot;http://coding.windstyle.cn/files/2012/02/image_thumb1.png&quot; alt=&quot;image&quot; width=&quot;553&quot; height=&quot;293&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;有Notes时的样子：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2012/02/image2.png&quot;&gt;&lt;img style=&quot;display: inline;&quot; title=&quot;image&quot; src=&quot;http://coding.windstyle.cn/files/2012/02/image_thumb2.png&quot; alt=&quot;image&quot; width=&quot;542&quot; height=&quot;230&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这段提示文本的标签也没有id和class，而且多层嵌套，可以依靠有class的分页元素（“上一步”和“下一步”的功能居然是为Notes翻页，我还以为是引导提示文本的向导按钮）来定位它。值得注意的是提示文本和Notes位于同一个div中，但结构却大相径庭，还好Notes的元素具有id，所以可以先将该层的所有div隐藏，然后再将具有id的div显示出来，籍此来隐藏提示文本，而又不影响Notes本身：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;.ms-socialCommentPaging + div &amp;gt; div {display:none}
.ms-socialCommentPaging + div &amp;gt; div[id] {display:block;}&lt;/pre&gt;
&lt;p&gt;其中+表示相邻的下一个元素，&amp;gt;表示第一级子元素，[id]表示包含id属性的元素。&lt;/p&gt;
&lt;p&gt;最终的CSS样式如下：&lt;/p&gt;
&lt;pre class=&quot;brush: xml; title: ; notranslate&quot;&gt;&amp;lt;style&amp;gt;
.ms-socialCommentPaging + div &amp;gt; div {display:none}
.ms-socialCommentPaging + div &amp;gt; div[id] {display:block;}
.ms-TagCloud.ms-socialThoughtBoxTags ~ div {display:none;}
&amp;lt;/style&amp;gt;&lt;/pre&gt;
&lt;p&gt;将这段CSS添加到MySite Host的Custom Master Page中即可（默认为MySite.master）。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/639608314/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/02/01/hide-tip-text-in-sharepoint-user-profile-page/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://coding.windstyle.cn/2012/02/01/hide-tip-text-in-sharepoint-user-profile-page/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>在SharePoint 2010的User Profile页面中存在一些提示，本文的内容就是如何去掉这些提示而又不影响其他功能，这是一件简单而又意义不大的事情，但我却不小心想复杂了，前后花了几个小时，用jQuery写了几行代码，中间还发现bug修改了一遍，终于发现走了弯路，用区区3行CSS搞定。 首先是“标签和注释”页面（thoughts.aspx）中的提示文本，位于标签云的下方，如图所示： 最下面几行提示文本的标签既没有id也没有class，还好标签云是有class的，可以用它来定位到之后的元素，并将其隐藏，只需一句Style： 其中~表示“之后的所有元素”，IE6不支持这个选择器，不过没关系，SharePoint 2010 不支持IE6。 接着是“概述”页面（person.aspx）的记事板提示文本，这段提示文本是通过AJAX技术动态填充的，仅在没有Notes的情况下显示（包括将Notes全部删除之后）。 没有Notes时的样子： 有Notes时的样子： 这段提示文本的标签也没有id和class，而且多层嵌套，可以依靠有class的分页元素（“上一步”和“下一步”的功能居然是为Notes翻页，我还以为是引导提示文本的向导按钮）来定位它。值得注意的是提示文本和Notes位于同一个div中，但结构却大相径庭，还好Notes的元素具有id，所以可以先将该层的所有div隐藏，然后再将具有id的div显示出来，籍此来隐藏提示文本，而又不影响Notes本身： 其中+表示相邻的下一个元素，&amp;#62;表示第一级子元素，[id]表示包含id属性的元素。 最终的CSS样式如下： 将这段CSS添加到MySite Host的Custom Master Page中即可（默认为MySite.master）。&lt;img src=&quot;http://www1.feedsky.com/t1/639608314/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2012/02/01/hide-tip-text-in-sharepoint-user-profile-page/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>SharePoint</category><category>SharePoint 2010</category><category>提示</category><category>CSS</category><pubDate>Wed, 01 Feb 2012 22:42:52 +0800</pubDate><author>Windie Chai</author><comments>http://coding.windstyle.cn/2012/02/01/hide-tip-text-in-sharepoint-user-profile-page/#comments</comments><guid isPermaLink="false">http://coding.windstyle.cn/?p=1126</guid><dc:creator>Windie Chai</dc:creator><fs:srclink>http://coding.windstyle.cn/2012/02/01/hide-tip-text-in-sharepoint-user-profile-page/</fs:srclink><fs:srcfeed>http://coding.windstyle.cn/feed/</fs:srcfeed><fs:itemid>feedsky/xiaoshatiantec/~7883976/639608314/1488721</fs:itemid></item><item><title>SharePoint HttpModule和SharePoint Designer的冲突</title><link>http://coding.windstyle.cn/2011/12/23/conflict-of-sharepoint-designer-and-sharepoint-httpmodule/</link><content:encoded>&lt;p&gt;前段时间为SharePoint写了一个HttpModule来将对重定向对某些页面的请求,结果发现有一个副作用,会和SharePoint Designer有冲突.&lt;/p&gt;
&lt;p&gt;具体表现为启用了这个HttpModule之后,SharePoint Designer在打开aspx页面时会报以下错误:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;服务器不能完成您的请求.&lt;/p&gt;
&lt;p&gt;soap:Server服务器无法处理请求。 &amp;#8212;&amp;gt; 无法完成此操作。 请重试。 &amp;#8212;&amp;gt; 无法完成此操作。 请重试。&amp;lt;nativehr&amp;gt;0&amp;#215;80004005&amp;lt;/nativehr&amp;gt;&amp;lt;nativestack&amp;gt;&amp;lt;/nativestack&amp;gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;span id=&quot;more-1117&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;排除了HttpModule代码对该文件路径的影响之后,开始考虑是不是事件顺序的缘故.&lt;/p&gt;
&lt;p&gt;之前这个HttpModule是在PostAuthorizeRequest事件中处理重定向逻辑的,经过一番尝试,最后发现只要使用的事件早于PostRequestHandlerExecute,就会引发SharePoint Designer出错.&lt;/p&gt;
&lt;p&gt;具体原因未知.&lt;/p&gt;
&lt;p&gt;另附上HttpApplication中的事件触发顺序：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;BeginRequest&lt;/li&gt;
&lt;li&gt;AuthenticateRequest&lt;/li&gt;
&lt;li&gt;PostAuthenticateRequest&lt;/li&gt;
&lt;li&gt;AuthorizeRequest&lt;/li&gt;
&lt;li&gt;PostAuthorizeRequest&lt;/li&gt;
&lt;li&gt;ResolveRequestCache&lt;/li&gt;
&lt;li&gt;PostResolveRequestCache&lt;/li&gt;
&lt;li&gt;PostMapRequestHandler&lt;/li&gt;
&lt;li&gt;AcquireRequestState&lt;/li&gt;
&lt;li&gt;PostAcquireRequestState&lt;/li&gt;
&lt;li&gt;PreRequestHandlerExecute&lt;/li&gt;
&lt;li&gt;PostRequestHandlerExecute&lt;/li&gt;
&lt;li&gt;ReleaseRequestState&lt;/li&gt;
&lt;li&gt;PostReleaseRequestState&lt;/li&gt;
&lt;li&gt;UpdateRequestCache&lt;/li&gt;
&lt;li&gt;PostUpdateRequestCache&lt;/li&gt;
&lt;li&gt;EndReques&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;另：据说事件过于靠前还会使SharePoint无法上传文件。&lt;/div&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/639608315/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2011/12/23/conflict-of-sharepoint-designer-and-sharepoint-httpmodule/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://coding.windstyle.cn/2011/12/23/conflict-of-sharepoint-designer-and-sharepoint-httpmodule/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>前段时间为SharePoint写了一个HttpModule来将对重定向对某些页面的请求,结果发现有一个副作用,会和SharePoint Designer有冲突. 具体表现为启用了这个HttpModule之后,SharePoint Designer在打开aspx页面时会报以下错误: 服务器不能完成您的请求. soap:Server服务器无法处理请求。 &amp;#8212;&amp;#62; 无法完成此操作。 请重试。 &amp;#8212;&amp;#62; 无法完成此操作。 请重试。&amp;#60;nativehr&amp;#62;0&amp;#215;80004005&amp;#60;/nativehr&amp;#62;&amp;#60;nativestack&amp;#62;&amp;#60;/nativestack&amp;#62; 排除了HttpModule代码对该文件路径的影响之后,开始考虑是不是事件顺序的缘故. 之前这个HttpModule是在PostAuthorizeRequest事件中处理重定向逻辑的,经过一番尝试,最后发现只要使用的事件早于PostRequestHandlerExecute,就会引发SharePoint Designer出错. 具体原因未知. 另附上HttpApplication中的事件触发顺序： BeginRequest AuthenticateRequest PostAuthenticateRequest AuthorizeRequest PostAuthorizeRequest ResolveRequestCache PostResolveRequestCache PostMapRequestHandler AcquireRequestState PostAcquireRequestState PreRequestHandlerExecute PostRequestHandlerExecute ReleaseRequestState PostReleaseRequestState UpdateRequestCache PostUpdateRequestCache EndReques 另：据说事件过于靠前还会使SharePoint无法上传文件。&lt;img src=&quot;http://www1.feedsky.com/t1/639608315/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/2011/12/23/conflict-of-sharepoint-designer-and-sharepoint-httpmodule/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>SharePoint Designer</category><category>SharePoint</category><category>错误</category><category>HttpModule</category><pubDate>Fri, 23 Dec 2011 19:00:18 +0800</pubDate><author>Windie Chai</author><comments>http://coding.windstyle.cn/2011/12/23/conflict-of-sharepoint-designer-and-sharepoint-httpmodule/#comments</comments><guid isPermaLink="false">http://coding.windstyle.cn/?p=1117</guid><dc:creator>Windie Chai</dc:creator><fs:srclink>http://coding.windstyle.cn/2011/12/23/conflict-of-sharepoint-designer-and-sharepoint-httpmodule/</fs:srclink><fs:srcfeed>http://coding.windstyle.cn/feed/</fs:srcfeed><fs:itemid>feedsky/xiaoshatiantec/~7883976/639608315/1488721</fs:itemid></item><item><title>版本历史</title><link>http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/changelog/</link><content:encoded>&lt;h3&gt;&lt;a href=&quot;http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/&quot;&gt;« Tagging Contacts 钛金联系人 for Windows Phone 7&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;v1.1.0.0 &lt;/strong&gt;2011-12-03 &lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;+ 支持查看拥有同一标签的所有联系人 &lt;/li&gt;
&lt;li&gt;+ 支持将联系人固定到“开始屏幕” &lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;strong&gt;v1.0.0.0 &lt;/strong&gt;2011-11-24 &lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;+ 自动显示“人脉”中的所有联系人 &lt;/li&gt;
&lt;li&gt;+ 查看联系人的详细信息 &lt;/li&gt;
&lt;li&gt;+ 管理联系人的标签&lt;/li&gt;
&lt;li&gt;+ 通过各种途径与联系人联络&lt;/li&gt;
&lt;li&gt;+ 可以向联系人的任何电话号码发送短信&lt;/li&gt;
&lt;li&gt;+ 查看所有标签&lt;/li&gt;
&lt;li&gt;+ 支持各种主题&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/639608316/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/changelog/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/changelog/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>« Tagging Contacts 钛金联系人 for Windows Phone 7 v1.1.0.0 2011-12-03 + 支持查看拥有同一标签的所有联系人 + 支持将联系人固定到“开始屏幕” v1.0.0.0 2011-11-24 + 自动显示“人脉”中的所有联系人 + 查看联系人的详细信息 + 管理联系人的标签 + 通过各种途径与联系人联络 + 可以向联系人的任何电话号码发送短信 + 查看所有标签 + 支持各种主题&lt;img src=&quot;http://www1.feedsky.com/t1/639608316/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/changelog/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><pubDate>Thu, 08 Dec 2011 10:34:24 +0800</pubDate><author>Windie Chai</author><comments>http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/changelog/#comments</comments><guid isPermaLink="false">http://coding.windstyle.cn/changelog/</guid><dc:creator>Windie Chai</dc:creator><fs:srclink>http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/changelog/</fs:srclink><fs:srcfeed>http://coding.windstyle.cn/feed/</fs:srcfeed><fs:itemid>feedsky/xiaoshatiantec/~7883976/639608316/1488721</fs:itemid></item><item><title>Tagging Contacts 钛金联系人 for Windows Phone</title><link>http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/</link><content:encoded>&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/&quot;&gt;&lt;img style=&quot;display: inline&quot; title=&quot;&quot; alt=&quot;&quot; src=&quot;http://coding.windstyle.cn/files/2011/12/banner.jpg&quot; width=&quot;560&quot; height=&quot;225&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;钛金联系人是一个增强版的联系人应用。    &lt;br /&gt;您可以通过它来为您的联系人打标签，标签的内容没有任何限制，可以是他（她）最喜爱的食物、特长、昵称，也可以是你们认识的地方、你们的关系等等……     &lt;br /&gt;通过标签，您可以在瞬间回忆起他（她)的点点滴滴。     &lt;br /&gt;在未来的更新中，您还可以给拥有同一个标签的所有联系人群发短信和邮件，可以完全取代“人脉”的分组功能，而且没有联系人数量限制。&lt;/p&gt;
&lt;h3&gt;试用版功能&lt;/h3&gt;
&lt;p&gt;自动显示“人脉”中的所有联系人，并按照首字母分组。    &lt;br /&gt;查看联系人的详细信息。     &lt;br /&gt;为联系人添加和删除标签。     &lt;br /&gt;通过各种途径与联系人联络。     &lt;br /&gt;可以向联系人的任何电话号码发送短信。     &lt;br /&gt;查看所有标签。     &lt;br /&gt;浏览拥有同一个标签的所有联系人。     &lt;br /&gt;支持各种主题。&lt;/p&gt;
&lt;h3&gt;收费版功能&lt;/h3&gt;
&lt;p&gt;将联系人固定在开始屏幕&lt;/p&gt;
&lt;h3&gt;系统要求&lt;/h3&gt;
&lt;p&gt;Windows Phone 7.1（Mango）以及更新的系统&lt;/p&gt;
&lt;h3&gt;版本&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;当前版本：1.1.0.0 &lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/changelog/&quot;&gt;版本历史»&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;截图&amp;amp;预览：&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_01.png&quot;&gt;&lt;img style=&quot;display: inline&quot; title=&quot;增强的联系人列表&quot; alt=&quot;增强的联系人列表&quot; src=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_01_thumb.png&quot; width=&quot;240&quot; height=&quot;400&quot; /&gt;&lt;/a&gt;&amp;#160;&lt;a href=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_02.png&quot;&gt;&lt;img style=&quot;display: inline&quot; title=&quot;标签列表&quot; alt=&quot;标签列表&quot; src=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_02_thumb.png&quot; width=&quot;240&quot; height=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_03.png&quot;&gt;&lt;img style=&quot;display: inline&quot; title=&quot;增强的联系人信息&quot; alt=&quot;增强的联系人信息&quot; src=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_03_thumb.png&quot; width=&quot;240&quot; height=&quot;400&quot; /&gt;&lt;/a&gt;&amp;#160;&lt;a href=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_04.png&quot;&gt;&lt;img style=&quot;display: inline&quot; title=&quot;添加标签&quot; alt=&quot;添加标签&quot; src=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_04_thumb.png&quot; width=&quot;240&quot; height=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_05.png&quot;&gt;&lt;img style=&quot;display: inline&quot; title=&quot;批量删除标签&quot; alt=&quot;批量删除标签&quot; src=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_05_thumb.png&quot; width=&quot;240&quot; height=&quot;400&quot; /&gt;&lt;/a&gt;&amp;#160;&lt;a href=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_06.png&quot;&gt;&lt;img style=&quot;display: inline&quot; title=&quot;白色主题&quot; alt=&quot;白色主题&quot; src=&quot;http://coding.windstyle.cn/files/2011/12/snapshot_06_thumb.png&quot; width=&quot;240&quot; height=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;下载&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://windowsphone.com/s?appid=30df6cbe-c2e5-42e8-b678-e064b2746575&quot; target=&quot;_blank&quot;&gt;前往Windows Phone Marketplace下载安装&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/639608317/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>钛金联系人是一个增强版的联系人应用。 您可以通过它来为您的联系人打标签，标签的内容没有任何限制，可以是他（她）最喜爱的食物、特长、昵称，也可以是你们认识的地方、你们的关系等等…… 通过标签，您可以在瞬间回忆起他（她)的点点滴滴。 在未来的更新中，您还可以给拥有同一个标签的所有联系人群发短信和邮件，可以完全取代“人脉”的分组功能，而且没有联系人数量限制。 试用版功能 自动显示“人脉”中的所有联系人，并按照首字母分组。 查看联系人的详细信息。 为联系人添加和删除标签。 通过各种途径与联系人联络。 可以向联系人的任何电话号码发送短信。 查看所有标签。 浏览拥有同一个标签的所有联系人。 支持各种主题。 收费版功能 将联系人固定在开始屏幕 系统要求 Windows Phone 7.1（Mango）以及更新的系统 版本 当前版本：1.1.0.0 版本历史» 截图&amp;#38;预览： &amp;#160; &amp;#160; &amp;#160; 下载 前往Windows Phone Marketplace下载安装&lt;img src=&quot;http://www1.feedsky.com/t1/639608317/xiaoshatiantec/feedsky/s.gif?r=http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><pubDate>Thu, 08 Dec 2011 10:28:30 +0800</pubDate><author>Windie Chai</author><comments>http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/#comments</comments><guid isPermaLink="false">http://coding.windstyle.cn/?page_id=1114</guid><dc:creator>Windie Chai</dc:creator><fs:srclink>http://coding.windstyle.cn/apps/tagging-contacts-for-windows-phone/</fs:srclink><fs:srcfeed>http://coding.windstyle.cn/feed/</fs:srcfeed><fs:itemid>feedsky/xiaoshatiantec/~7883976/639608317/1488721</fs:itemid></item></channel></rss>
