<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" 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/"
  version="2.0">
  <channel>
    <title>Windows China Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/windows_china_blog/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 03:27:21 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>博客园UAP版开发心得之推荐应用的实现</title>
      <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/uap-2</link>
      <pubDate>Wed, 10 Jun 2015 23:13:06 GMT</pubDate>
      <dc:creator><![CDATA[Windows-China]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows_china_blog/2015/06/10/uap-2/</guid>
      <description><![CDATA[&nbsp;　　最近做了一个博客园UAP升级项目，增加了一些新的功能，下面简单说一下都有什么新功能在等着我们，并且着重介绍一下推荐应用的实现过程，希望能给一些感兴趣的博友们一些帮助:)
&nbsp;...]]></description>
      <content:encoded><![CDATA[<p><span>&nbsp;</span><span>　　最近做了一个博客园UAP升级项目，增加了一些新的功能，下面简单说一下都有什么新功能在等着我们，并且着重介绍一下推荐应用的实现过程，希望能给一些感兴趣的博友们一些帮助:)</span></p>
<p><span>&nbsp;</span></p>
<p><span><span>1.在首页增加了"热门"和"精选"的快速访问入口，省了好多事儿</span> </span></p>
<p><span>&nbsp;</span></p>
<p><span><img src="http://images.cnitblog.com/blog/700062/201505/061145146101303.png" alt="" /></span></p>
<p><span>&nbsp;</span></p>
<p><span>2.可以离线收藏文章啦（离线所有的文字内容）</span></p>
<p><span>&nbsp;</span></p>
<p><span>3.实现透明磁贴，去开始屏幕看看吧</span></p>
<p><span>&nbsp;</span></p>
<p><span><img src="http://images.cnitblog.com/blog/700062/201505/061145175637800.png" alt="" /></span></p>
<p><span>4.在博主页面二级菜单里面增加了"查找博主"的功能菜单，找人再也不费劲儿了</span><span>&nbsp;</span></p>
<div>
<table border="0"><colgroup><col /><col /><col /></colgroup>
<tbody valign="top">
<tr>
<td>
<p><span><img src="http://images.cnitblog.com/blog/700062/201505/061145186885356.png" alt="" /></span></p>
</td>
<td>
<p><span><img src="http://images.cnitblog.com/blog/700062/201505/061145198296142.png" alt="" /></span></p>
</td>
<td>
<p><span><img src="http://images.cnitblog.com/blog/700062/201505/061145208299969.png" alt="" /></span></p>
</td>
</tr>
</tbody>
</table>
</div>
<p><span>&nbsp;</span></p>
<p><span>5.在栏目中增加几个推荐应用，马上去看看有哪些有意思的应用吧</span></p>
<p><span>&nbsp;</span></p>
<p><span><img src="http://images.cnitblog.com/blog/700062/201505/061145222518968.png" alt="" /></span></p>
<p><span>&nbsp;</span></p>
<p><span>　　下面我们重点说一下增加的推荐应用的实现过程，我们利用Web API + Cloud实现荐应用的服务器端的控制，Web API大家可能并不陌生，国内外介绍Web API的文章有很多，在这里我就不详细的介绍了，简单地介绍一下服务器端如何实现推荐频道，从sql server到Web API再到cnblogs客户端的整体实现过程</span></p>
<p><span>&nbsp;</span></p>
<p><span>一、SQL Server数据库的创建</span></p>
<p><span>&nbsp;</span></p>
<p><span>　　在SQL Server数据库中创建一个名为CnblogsDB的数据库实例，创建一个名为Cnblogs_Recommend_Columns的数据库表字段包括Id，Quick，Icon，Name，Desc，Page，Color，Language等，我们不必关心具体字段的含义。</span></p>
<p><span>&nbsp;</span></p>
<p><span><img src="http://images.cnitblog.com/blog/700062/201505/061145230483326.png" alt="" /></span></p>
<p><span>&nbsp;</span></p>
<p><span>创建数据库表<span>Cnblogs_Recommend_Columns</span>的脚本如下</span></p>
<p><span>&nbsp;</span></p>
<p><span>CREATE<span> <span>TABLE<span> [dbo]<span>.<span>[Cnblogs_Recommend_Columns] </span></span></span></span></span></span></p>
<p><span>(</span></p>
<p><span>[Id] <span>INT<span> <span>NOT<span> <span>NULL<span> <span>PRIMARY<span> <span>KEY<span> <span>IDENTITY <span>(<span>1<span>,<span> 1<span>),</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span> [Quick] <span>VARCHAR<span>(<span>50<span>)<span> <span>NULL,</span></span></span></span></span></span></span></p>
<p><span> [Icon] <span>VARCHAR<span>(<span>200<span>)<span> <span>NULL,</span></span></span></span></span></span></span></p>
<p><span> [Name] <span>NVARCHAR<span>(<span>50<span>)<span> <span>NULL,</span></span></span></span></span></span></span></p>
<p><span> [Desc] <span>VARCHAR<span>(<span>500<span>)<span> <span>NULL,</span></span></span></span></span></span></span></p>
<p><span> [Page] <span>VARCHAR<span>(<span>100<span>)<span> <span>NULL,</span></span></span></span></span></span></span></p>
<p><span> [Color] <span>VARCHAR<span>(<span>10<span>)<span> <span>NULL,</span></span></span></span></span></span></span></p>
<p><span> [Language] <span>VARCHAR<span>(<span>10<span>)<span> <span>NULL</span></span></span></span></span></span></span></p>
<p><span>)</span></p>
<p><span>&nbsp;</span></p>
<p><span>insert<span> <span>into<span> [dbo]<span>.<span>[Cnblogs_Recommend_Columns]<span>(<span>[Quick]<span>,<span>[Icon]<span>,<span>[Name]<span>,<span>[Desc]<span>,<span>[Page]<span>,<span>[Color]<span>,<span>[Language]<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>values <span>(<span>'false'<span>,<span>'Images/bingdicticon.png'<span>,<span>N'</span></span></span></span></span></span></span><span>必应词典</span><span><span>'<span>,<span>N'</span></span></span><span>推荐应用</span><span>'<span>,<span>'ms-windows-store:navigate?appid=71bbd0fd-23e8-4157-ab29-a1cbd82e425b'<span>,<span>'#AA7EAE'<span>,<span>'zh-CN'<span>)</span></span></span></span></span></span></span></span></span></span></p>
<p><span>insert<span> <span>into<span> [dbo]<span>.<span>[Cnblogs_Recommend_Columns]<span>(<span>[Quick]<span>,<span>[Icon]<span>,<span>[Name]<span>,<span>[Desc]<span>,<span>[Page]<span>,<span>[Color]<span>,<span>[Language]<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span>values <span>(<span>'false'<span>,<span>'Images/bingdicticon.png'<span>,<span>'BingDict'<span>,<span>'Recommendations'<span>,<span>'ms-windows-store:navigate?appid=71bbd0fd-23e8-4157-ab29-a1cbd82e425b'<span>,<span>'#AA7EAE'<span>,<span>'en-US'<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span>insert<span> <span>into<span> [dbo]<span>.<span>[Cnblogs_Recommend_Columns]<span>(<span>[Quick]<span>,<span>[Icon]<span>,<span>[Name]<span>,<span>[Desc]<span>,<span>[Page]<span>,<span>[Color]<span>,<span>[Language]<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>values <span>(<span>'false'<span>,<span>'Images/coupleticon.png'<span>,<span>N'</span></span></span></span></span></span></span><span>微软对联</span><span><span>'<span>,<span>N'</span></span></span><span>推荐应用</span><span>'<span>,<span>'ms-windows-store:navigate?appid=25035c46-0362-40b9-9c84-fd4a3cafe4df'<span>,<span>'#AA7EAE'<span>,<span>'zh-CN'<span>)</span></span></span></span></span></span></span></span></span></span></p>
<p><span>insert<span> <span>into<span> [dbo]<span>.<span>[Cnblogs_Recommend_Columns]<span>(<span>[Quick]<span>,<span>[Icon]<span>,<span>[Name]<span>,<span>[Desc]<span>,<span>[Page]<span>,<span>[Color]<span>,<span>[Language]<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span>values <span>(<span>'false'<span>,<span>'Images/coupleticon.png'<span>,<span>'Couplet'<span>,<span>'Recommendations'<span>,<span>'ms-windows-store:navigate?appid=25035c46-0362-40b9-9c84-fd4a3cafe4df'<span>,<span>'#AA7EAE'<span>,<span>'en-US'<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span>insert<span> <span>into<span> [dbo]<span>.<span>[Cnblogs_Recommend_Columns]<span>(<span>[Quick]<span>,<span>[Icon]<span>,<span>[Name]<span>,<span>[Desc]<span>,<span>[Page]<span>,<span>[Color]<span>,<span>[Language]<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>values <span>(<span>'false'<span>,<span>'Images/doubanicon.png'<span>,<span>N'</span></span></span></span></span></span></span><span>豆瓣一刻</span><span><span>'<span>,<span>N'</span></span></span><span>推荐应用</span><span>'<span>,<span>'ms-windows-store:navigate?appid=ed23f20b-3b0d-4efb-97f8-e70ef709b31b'<span>,<span>'#AA7EAE'<span>,<span>'zh-CN'<span>)</span></span></span></span></span></span></span></span></span></span></p>
<p><span>insert<span> <span>into<span> [dbo]<span>.<span>[Cnblogs_Recommend_Columns]<span>(<span>[Quick]<span>,<span>[Icon]<span>,<span>[Name]<span>,<span>[Desc]<span>,<span>[Page]<span>,<span>[Color]<span>,<span>[Language]<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span>values <span>(<span>'false'<span>,<span>'Images/doubanicon.png'<span>,<span>'BouBan'<span>,<span>'Recommendations'<span>,<span>'ms-windows-store:navigate?appid=ed23f20b-3b0d-4efb-97f8-e70ef709b31b'<span>,<span>'#AA7EAE'<span>,<span>'en-US'<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span>insert<span> <span>into<span> [dbo]<span>.<span>[Cnblogs_Recommend_Columns]<span>(<span>[Quick]<span>,<span>[Icon]<span>,<span>[Name]<span>,<span>[Desc]<span>,<span>[Page]<span>,<span>[Color]<span>,<span>[Language]<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>values <span>(<span>'false'<span>,<span>'Images/riddleicon.png'<span>,<span>N'</span></span></span></span></span></span></span><span>微软字谜</span><span><span>'<span>,<span>N'</span></span></span><span>推荐应用</span><span>'<span>,<span>'ms-windows-store:navigate?appid=4a54f6f0-d387-4517-8026-dd8b93bcdf19'<span>,<span>'#AA7EAE'<span>,<span>'zh-CN'<span>)</span></span></span></span></span></span></span></span></span></span></p>
<p><span>insert<span> <span>into<span> [dbo]<span>.<span>[Cnblogs_Recommend_Columns]<span>(<span>[Quick]<span>,<span>[Icon]<span>,<span>[Name]<span>,<span>[Desc]<span>,<span>[Page]<span>,<span>[Color]<span>,<span>[Language]<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span>values <span>(<span>'false'<span>,<span>'Images/riddleicon.png'<span>,<span>'Riddle'<span>,<span>'Recommendations'<span>,<span>'ms-windows-store:navigate?appid=4a54f6f0-d387-4517-8026-dd8b93bcdf19'<span>,<span>'#AA7EAE'<span>,<span>'en-US'<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span>&nbsp;</span></p>
<p><span>二、Web API的实现与部署</span></p>
<p><span>&nbsp;</span></p>
<p><span>1.创建一个Web API 项目，命名为CNBlogsWebAPI </span></p>
<p><span>&nbsp;</span></p>
<p><span><img src="http://images.cnitblog.com/blog/700062/201505/061145255483895.png" alt="" /></span></p>
<p><span>&nbsp;</span></p>
<p><span>2.在Models文件夹中创建一个LINQ to SQL Classes，名为CnblogsDB.dbml，双击打开主文件 </span></p>
<p><span>3.利用VS的Server Explorer与数据库连接，并且打开，拖拽表Cnblogs_Recommend_Columns进入CnblogsDB.dbml </span></p>
<p><span>4.在Controllers文件夹增加一个RecommendController类 </span></p>
<p><span>类的代码如下</span></p>
<p><span>using<span> CNBlogsWebAPI.Models; </span></span></p>
<p><span>using<span> System; </span></span></p>
<p><span>using<span> System.Collections.Generic; </span></span></p>
<p><span>using<span> System.Linq; </span></span></p>
<p><span>using<span> System.Net; </span></span></p>
<p><span>using<span> System.Net.Http; </span></span></p>
<p><span>using<span> System.Text; </span></span></p>
<p><span>using<span> System.Web.Http; </span></span></p>
<p><span>using<span> System.Xml.Serialization; </span></span></p>
<p><span>namespace<span> CNBlogsWebAPI.Controllers </span></span></p>
<p><span>{ </span></p>
<p><span> [<span>RoutePrefix<span>(<span>"api/cnblogs"<span>)] </span></span></span></span></span></p>
<p><span><span>public<span> <span>class<span> <span>RecommendController<span> : <span>ApiController</span></span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>CnblogsDBDataContext<span> _db = <span>new<span> <span>CnblogsDBDataContext<span>(); </span></span></span></span></span></span></span></p>
<p><span> [<span>Route<span>(<span>"recommendcolumns/{language}"<span>)] </span></span></span></span></span></p>
<p><span> [<span>HttpGet<span>] </span></span></span></p>
<p><span><span>public<span> <span>IHttpActionResult<span> GetRecommendColumns(<span>string<span> language) </span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>if<span> (<span>string<span>.IsNullOrEmpty(language)) language = <span>"zh-CN"<span>; </span></span></span></span></span></span></span></p>
<p><span><span>var<span> result = _db.Cnblogs_Recommend_Columns.Where(c =&gt; c.Language.ToLower() == language.ToLower()); </span></span></span></p>
<p><span><span>return<span> Ok( </span></span></span></p>
<p><span><span>new</span></span></p>
<p><span> { </span></p>
<p><span> Columns = result.ToList() </span></p>
<p><span> }); </span></p>
<p><span> } </span></p>
<p><span>&nbsp;</span></p>
<p><span><span>protected<span> <span>override<span> <span>void<span> Dispose(<span>bool<span> disposing) </span></span></span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>base<span>.Dispose(disposing);&nbsp;</span></span></span><span>&nbsp;</span></p>
<p><span><span>if<span> (_db != <span>null<span>) </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>this<span>._db.Dispose(); </span></span></span></p>
<p><span> } </span></p>
<p><span> } </span></p>
<p><span> } </span></p>
<p><span>} </span></p>
<p><span>&nbsp;</span></p>
<p><span>测试一下，运行CNBlogsWebAPI会出现如下见面</span></p>
<p><span>&nbsp;</span></p>
<p><span><img src="http://images.cnitblog.com/blog/700062/201505/061145267043208.png" alt="" /></span></p>
<p><span>&nbsp;</span></p>
<p><span>不过，没关系，我们可以根据RoutePrefix和Route拼接出如下的链接<a href="http://localhost:34023/api/cnblogs/recommendcolumns/zh-CN">http://localhost:34023/api/cnblogs/recommendcolumns/zh-CN</a>，然后在地址栏中输入这个链接，回车，值得一提的是用IE浏览器打开会返回一个Json串，据说用火狐返回是XML格式（本人不用火狐的，所以并没有验证过，感兴趣的朋友可以自己试试）</span></p>
<p><span>&nbsp;</span></p>
<p><span>5.至于部署，采用IIS托管即可，博客园UAP是在云服务器上部署的 </span></p>
<p><span>&nbsp;</span></p>
<p><span>三、Cnblogs WP客户端调用</span></p>
<p><span>&nbsp;</span></p>
<p><span>接下来到了最关键的一步了，那就是在APP中如何调用，说起来介绍这方面的文章在网上一搜一大把，在这里也不赘述了，直接上Code（这段代码仅为示例）</span></p>
<p><span><span>using<span> Windows.Web.Http;</span></span> </span></p>
<p><span>public<span> <span>async<span> <span>static<span> <span>Task<span> GetColumns() </span></span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>var<span> rootUrl = <span>"http://localhost:34023/"<span>; </span></span></span></span></span></p>
<p><span><span>var<span> url = rootUrl + <span>"api/cnblogs/recommendcolumns/"<span> + System.Globalization.<span>CultureInfo<span>.CurrentCulture.Name; </span></span></span></span></span></span></span></p>
<p><span><span>var<span> client = <span>new<span> <span>HttpClient<span>(); </span></span></span></span></span></span></span></p>
<p><span><span>var<span> request = <span>new<span> <span>HttpRequestMessage<span>(<span>HttpMethod<span>.Get, <span>new<span> <span>Uri<span>(url)); </span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>var<span> response = <span>await<span> client.SendRequestAsync(request); </span></span></span></span></span></p>
<p><span><span>if<span> (response.StatusCode == <span>HttpStatusCode<span>.Ok) </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span><span>var<span> result = response.Content;<span>//</span></span></span></span><span>此处为返回结果，</span><span><span>Json</span><span>格式</span></span></span></p>
<p><span> } </span></p>
<p><span> } </span></p>
<p><span>通过如上的方法调用，我们得到了result，结果是Json格式的数据，得到了数据，就是我们为所欲为，大显身手的时候啦，最好是Json to object，这样我们就可以更好地与XAML界面Binding啦，最后的结果大家已经看到了，就是红色方框里的喽</span></p>
<p><span><img src="http://images.cnitblog.com/blog/700062/201505/061145281107978.png" alt="" /></span></p>]]></content:encoded>
    </item>
    <item>
      <title>将Win8.1/WP8.1应用迁移到Universal Windows Platform</title>
      <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/win8-1wp8-1universal-windows-platform</link>
      <pubDate>Wed, 10 Jun 2015 23:11:33 GMT</pubDate>
      <dc:creator><![CDATA[Windows-China]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows_china_blog/2015/06/10/win8-1wp8-1universal-windows-platform/</guid>
      <description><![CDATA[在上一篇在VS2015 RC打开CTP中创建的工程，我们介绍了怎么在RC中打开CTP中创建的Universal 工程，这一篇我们来讲下怎么将Windows...]]></description>
      <content:encoded><![CDATA[<p>在上一篇<a id="cb_post_title_url" class="postTitle2" href="http://www.cnblogs.com/ms-uap/p/4475975.html">在VS2015 RC打开CTP中创建的工程</a>，我们介绍了怎么在RC中打开CTP中创建的Universal 工程，这一篇我们来讲下怎么将Windows 8.1/WP8.1的应用迁移到Universal Windows Platform上。</p>
<p><span>2015RC中，我们可以将8.1的应用迁移到统一平台上，进而使用新的API进行开发，下面我们使用wp8.1的应用作为例子讲解下步骤。</span></p>
<p>1. 首先我们使用2015打开之前的工程。</p>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/041643518607321.png" alt="" /></p>
<p>2. 右键点击工程，选择&ldquo;卸载项目&rdquo;。</p>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/041647461886232.png" alt="" /></p>
<p>3. 右键点击工程，选择&ldquo;编辑XXX.csproj&rdquo;</p>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/041647572824310.png" alt="" /></p>
<p>4. 和上一篇一样，取得平台版本号，路径是&ldquo;<strong>\Program Files (x86)\Windows Kits\10\Platforms\UAP</strong>&rdquo;</p>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/051043227984036.png" alt="" /></p>
<p>下面就开始修改工程文件了</p>
<p>5. 找到个包含子节点<strong>TargetPlatformVersion</strong>、且值为8.1的PropertyGroup节点（其实一般第一个PropertyGroup就是了），进行下面的修改：</p>
<ul>
<li>&nbsp; 把<strong>Platform</strong>的值改成<strong>x86</strong></li>
<li>&nbsp; 添加<strong>TargetPlatformIdentifier</strong>节点，值为<strong>UAP</strong></li>
<li>&nbsp; 把<strong>TargetPlatformVersion</strong>的值改成4中取得的版本号</li>
<li>&nbsp; 添加<strong>TargetPlatformMinVersion</strong>节点，值为4中的版本号</li>
<li>&nbsp; 把<strong>MinimumVisualStudioVersion</strong>的值改成<strong>14</strong></li>
<li>&nbsp; 把<strong>ProjectTypeGuids</strong>的值改成<strong><em>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</em></strong></li>
<li><span class="label">&nbsp; 添加<strong>EnableDotNetNativeCompatibleProfile</strong>节点，值为<strong>true</strong></span></li>
</ul>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/041655115637801.png" alt="" /></p>
<p><span>6. 把所有的vs版本从12.0替换成14.0，这一步直接替换即可（CTRL+H）</span></p>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/041700505793664.png" alt="" /></p>
<p>7. 删掉配置为<strong>AnyCPU</strong>的PropertyGroup节点</p>
<p>8.&nbsp;查看剩下配置是Release的PropertyGroup节点，如果下面没有<strong>UseDotNetNativeToolchain</strong>子节点的话，就动手加一个，值一定要是<strong>true</strong>， 即：&lt;UseDotNetNativeToolchain&gt;true&lt;/UseDotNetNativeToolchain&gt;</p>
<p>9. 如果是手机项目的话，还需要删除下面这个节点</p>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/041704171881610.png" alt="" /></p>
<p>10. 现在重新加载我们的工程，会发现工程类型变成了Windows Universal了！下面还是需要修改manifest。</p>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/051111390958474.png" alt="" /></p>
<p>11. 打开manifest文件，首先我们需要替换掉所有的schema，把Package节点用下面这段替换。</p>
<div class="cnblogs_code">
<pre><span>&lt;</span><span>Package </span><span>xmlns</span><span>="http://schemas.microsoft.com/appx/manifest/foundation/windows10"</span><span> xmlns:uap</span><span>="http://schemas.microsoft.com/appx/manifest/uap/windows10"</span><span> xmlns:mp</span><span>="http://schemas.microsoft.com/appx/2014/phone/manifest"</span><span> IgnorableNamespaces</span><span>= "uap mp"</span><span>&gt;</span></pre>
</div>
<p>对于Win8.1应用，还需要额外添加mp:PhoneIdentity的节点，如下，其中PhoneProductId就是Identity的Name, PhonePushedId目前是固定的值</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre>    <span>&lt;</span><span>Identity </span><span>Name</span><span>="fe8a6971-8349-489b-8941-83dd308e9b9b"</span><span> Publisher</span><span>="CN=xxxxxxx"</span><span> Version</span><span>="1.0.0.0"</span> <span>/&gt;</span>

    <span>&lt;</span><span>mp:PhoneIdentity </span><span>PhoneProductId</span><span>="fe8a6971-8349-489b-8941-83dd308e9b9b"</span><span> PhonePublisherId</span><span>="00000000-0000-0000-0000-000000000000"</span><span>/&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p><span>12. 在Package下添加如下子节点，其中的版本号就是我们之前一直用的</span></p>
<div class="cnblogs_code">
<pre><span>&lt;</span><span>Dependencies</span><span>&gt;</span>
<span>&lt;</span><span>TargetDeviceFamily </span><span>Name</span><span>="Windows.Universal"</span><span> MinVersion</span><span>="10.0.10069.0"</span><span> MaxVersionTested</span><span>="10.0.10069.0"</span> <span>/&gt;</span>
<span>&lt;/</span><span>Dependencies</span><span>&gt;</span></pre>
</div>
<p>13. 删除<strong>Prerequisites</strong>节点</p>
<p>14. 检查你的Resources节点，如果是用到了<strong>Scale</strong>和<strong>DXFeatureLevel</strong>的话，为他们加上<strong>uap</strong>命名空间，如下</p>
<div class="cnblogs_code">
<pre>    &lt;Resources&gt;
        &lt;Resource Language="x-generate"/&gt;
        &lt;Resource uap:Scale="180"/&gt;
        &lt;Resource uap:DXFeatureLevel="dx11"/&gt;
    &lt;/Resources&gt;</pre>
</div>
<p>15. 检查你的Capability节点，如果使用声明了下列这些权限，需要加上uap命名空间。</p>
<ul>
<li>documentsLibrary</li>
<li>picturesLibrary</li>
<li>videosLibrary</li>
<li>musicLibrary</li>
<li>enterpriseAuthentication</li>
<li>sharedUserCertificates</li>
<li>removableStorage</li>
<li>appointments</li>
<li>contacts</li>
</ul>
<p>如：</p>
<div class="cnblogs_code">
<pre><span>&lt;</span><span>Capabilities</span><span>&gt;</span>
  <span>&lt;</span><span>uap:Capability </span><span>Name</span><span>="documentsLibrary"</span><span>/&gt;</span>
  <span>&lt;</span><span>uap:Capability </span><span>Name</span><span>="removableStorage"</span><span>/&gt;</span>
<span>&lt;/</span><span>Capabilities</span><span>&gt;</span></pre>
</div>
<p>16. 将VirsualElements节点及其子节点的命名空间改成uap&nbsp;</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>&lt;</span><span>uap:VisualElements </span><span>DisplayName</span><span>="App9"</span><span> Square150x150Logo</span><span>="Assets\Logo.png"</span><span> Square44x44Logo</span><span>="Assets\SmallLogo.png"</span><span> Description</span><span>="App9"</span><span> BackgroundColor</span><span>="transparent"</span><span>&gt;</span>
    <span>&lt;</span><span>uap:DefaultTile </span><span>Wide310x150Logo</span><span>="Assets\WideLogo.png"</span><span> Square71x71Logo</span><span>="Assets\Square71x71Logo.png"</span><span>/&gt;</span>
    <span>&lt;</span><span>uap:SplashScreen </span><span>Image</span><span>="Assets\SplashScreen.png"</span><span>/&gt;</span>
<span>&lt;/</span><span>uap:VisualElements</span><span>&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p><span>对于Win8.1应用，这里需要注意的是，属性Square{SIZE}Logo中的size有了变化，70x70变成了71x71, 30x30变成44x44.</span></p>
<p><span>旧的：</span></p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>&lt;</span><span>m2:VisualElements </span><span>&hellip; Square30x30Logo</span><span>="Assets\SmallLogo.png"</span><span> &hellip;</span><span>&gt;</span>
 <span>&lt;</span><span>m2:DefaultTile </span><span>&hellip; Square70x70Logo</span><span>="images/70x70.png"</span><span>&gt;</span>
<span>&lt;/</span><span>m2:VisualElements</span><span>&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>新的：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>&lt;</span><span>uap:VisualElements </span><span>&hellip; Square44x44Logo</span><span>="Assets\SmallLogo.png"</span><span> &hellip;</span><span>&gt;</span>
 <span>&lt;</span><span>uap:DefaultTile </span><span>&hellip; Square71x71Logo</span><span>="images/70x70.png"</span><span>&gt;</span>
<span>&lt;/</span><span>uap:VisualElements</span><span>&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p><span>17. 检查Extensions节点，为下列节点添加命名空间uap</span></p>
<ul>
<li>windows.accountPictureProvide</li>
<li>windows.alarm</li>
<li>windows.appointmentsProvider</li>
<li>windows.autoPlayContent</li>
<li>windows.autoPlayDevice</li>
<li>windows.cachedFileUpdate</li>
<li>windows.cameraSettings</li>
<li>windows.fileOpenPicker</li>
<li>windows.fileTypeAssociation</li>
<li>windows.fileSavePicke</li>
<li>windows.lockScreenCall</li>
<li>windows.printTaskSettings</li>
<li>windows.protocol</li>
<li>windows.search</li>
<li>windows.shareTarget</li>
</ul>
<p>如：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>&lt;</span><span>Extensions</span><span>&gt;</span>
  <span>&lt;</span><span>uap:Extension </span><span>Category</span><span>="windows.alarm"</span><span>/&gt;</span>
  <span>&lt;</span><span>uap:Extension </span><span>Category</span><span>="windows.search"</span><span> EntryPoint</span><span>="MyActivateableClassId.baz"</span><span>/&gt;</span>
  <span>&lt;</span><span>uap:Extension </span><span>Category</span><span>="windows.protocol"</span><span>&gt;</span>
    <span>&lt;</span><span>uap:Protocol </span><span>Name</span><span>="mailto"</span><span> DesiredView</span><span>="useHalf"</span><span>&gt;</span>
     <span>&lt;</span><span>uap:DisplayName</span><span>&gt;</span>MailTo Protocol<span>&lt;/</span><span>uap:DisplayName</span><span>&gt;</span>
    <span>&lt;/</span><span>uap:Protocol</span><span>&gt;</span>
  <span>&lt;/</span><span>uap:Extension</span><span>&gt;</span>
<span>&lt;/</span><span>Extensions</span><span>&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>18. 为类型为<strong>chatMessageNotification</strong>的后台任务加上uap命名空间</p>
<p>如：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>&lt;</span><span>Extension </span><span>Category</span><span>="windows.backgroundTasks"</span><span> EntryPoint</span><span>="Fabrikam.BackgroundTask"</span><span> Executable</span><span>="MyBackground.exe"</span><span>&gt;</span>
 <span>&lt;</span><span>BackgroundTasks </span><span>ServerName</span><span>="MyBackgroundTasks"</span><span>&gt;</span>
    <span>&lt;</span><span>uap:Task </span><span>Type</span><span>="chatMessageNotification"</span><span>/&gt;</span>
  <span>&lt;/</span><span>BackgroundTasks</span><span>&gt;</span>
<span>&lt;/</span><span>Extension</span><span>&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>19. 修改PackageDependency，添加Publisher和MinVersion属性</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>&lt;</span><span>Dependencies</span><span>&gt;</span>
 <span>&lt;</span><span>PackageDependency </span><span>Name</span><span>="Microsoft.VCLibs.120.00"</span><span> Publisher</span><span>="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"</span><span> MinVersion</span><span>="12.0.30113.0"</span> <span>/&gt;</span>
<span>&lt;/</span><span>Dependencies</span><span>&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>20. 将类型为gattCharacteristicNotification 和rfcommConnection的后台任务替换为Bluetooth类型。</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>&lt;</span><span>Extension </span><span>Category</span><span>="windows.backgroundTasks"</span><span> EntryPoint</span><span>="Fabrikam.BackgroundTask"</span><span> Executable</span><span>="MyBackground.exe"</span><span>&gt;</span>
<span>&lt;</span><span>BackgroundTasks </span><span>ServerName</span><span>="MyBackgroundTasks"</span><span>&gt;</span>
           <span>&lt;</span><span>Task </span><span>Type</span><span>="bluetooth"</span><span>/&gt;</span>
<span>&lt;/</span><span>BackgroundTasks</span><span>&gt;</span>
<span>&lt;/</span><span>Extension</span><span>&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>21. 使用新的bluetooth capability替换bluetooth.rfcomm和bluetooth.genericAttributeProfile&nbsp;</p>
<p>旧的：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>&lt;</span><span>Capabilities</span><span>&gt;</span>
  <span>&lt;</span><span>m2:DeviceCapability </span><span>Name</span><span>="bluetooth.rfcomm"</span><span>&gt;</span>
    <span>&lt;</span><span>m2:Device </span><span>Id</span><span>="any"</span><span>&gt;</span>
     <span>&lt;</span><span>m2:Function </span><span>Type</span><span>="serviceId:34B1CF4D-1069-4AD6-89B6-E161D79BE4D8"</span><span>/&gt;</span>
    <span>&lt;/</span><span>m2:Device</span><span>&gt;</span>
  <span>&lt;/</span><span>m2:DeviceCapability</span><span>&gt;</span>
  <span>&lt;</span><span>m2:DeviceCapability </span><span>Name</span><span>="bluetooth.genericAttributeProfile"</span><span>&gt;</span>
    <span>&lt;</span><span>m2:Device </span><span>Id</span><span>="any"</span><span>&gt;</span>
     <span>&lt;</span><span>m2:Function </span><span>Type</span><span>="name:heartRate"</span><span>/&gt;</span>
    <span>&lt;/</span><span>m2:Device</span><span>&gt;</span>
  <span>&lt;/</span><span>m2:DeviceCapability</span><span>&gt;</span>
<span>&lt;/</span><span>Capabilities</span><span>&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>新的：</p>
<div class="cnblogs_code">
<pre><span>&lt;</span><span>Capabilities</span><span>&gt;</span>
  <span>&lt;</span><span>uap:DeviceCapability </span><span>Name</span><span>="bluetooth"</span><span>/&gt;</span>
<span>&lt;/</span><span>Capabilities</span><span>&gt;</span></pre>
</div>
<p>22. 删除Windows.contact和windows.contactPicker扩展</p>
<p>23. 删除VisualElements的ForgroundText和ToastCapable属性</p>
<p>24. 删除DefaultTitle的DefaultSize属性</p>
<p>25. 删除ApplicationView节点</p>
<p>26. 到此manifest文件就修改完了，保存吧！虽然看上去步骤有点多，其实17之后的很多步骤可能是用不到的</p>
<p>27. 下面我们需要删除一些额外的文件</p>
<ul>
<li>检查解决方案目录下的子目录"\.vs\{project name}\v14"，如果存在".suo"文件，删掉它<img src="http://images.cnitblog.com/blog2015/700062/201505/051152576421030.png" alt="" /></li>
<li>删除掉工程目录下所有的后缀为.csproj.user文件</li>
</ul>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/051153211108227.png" alt="" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>现在我们的工程就已经成功的迁移到了Universal Windows Platform了，但是对于很多应用来说，还是需要进一步修改code，因为Windows 10的很多API都有了变化。</p>]]></content:encoded>
    </item>
    <item>
      <title>在VS2015 RC打开CTP中创建的工程</title>
      <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/vs2015-rcctp</link>
      <pubDate>Wed, 10 Jun 2015 23:10:16 GMT</pubDate>
      <dc:creator><![CDATA[Windows-China]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows_china_blog/2015/06/10/vs2015-rcctp/</guid>
      <description><![CDATA[VS2015终于出了RC了！小伙伴们快来安装试用吧，地址在这里，还有新的Windows 10开发工具哦，要不然是开发不了Universal Windows...]]></description>
      <content:encoded><![CDATA[<h1 class="postTitle"><span style="font-size: 12px;">VS2015终于出了RC了！小伙伴们快来安装试用吧，地址在</span><a style="font-size: 12px;" href="https://www.visualstudio.com/products/visual-studio-2015-downloads-vs" target="_blank">这里</a><span style="font-size: 12px;">，还有新的</span><a style="font-size: 12px;" href="https://dev.windows.com/zh-CN/downloads/install-dev-tools-visual-studio-2015" target="_blank">Windows 10开发工具</a><span style="font-size: 12px;">哦，要不然是开发不了Universal Windows App的，安装前记得卸载CTP版本。</span></h1>
<div class="postBody">
<div id="cnblogs_post_body">
<p>&nbsp;</p>
<p>新的RC版本有了些新变化，不能直接打开CTP中创建的工程-。-，需要手动做一些修改才行。</p>
<p>&nbsp;</p>
<p>如果你之前使用VS2015 CTP创建过工程的话，直接使用RC打开会提示项目需要更新，如下图：</p>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/041322168605745.png" alt="" /></p>
<p>&nbsp;</p>
<p>&nbsp;修改方法很简单，下面以C#工程为例：</p>
<p>&nbsp;</p>
<p>1. 首先需要确认你电脑上的Universal Windows Platform(我们现在开发的通用应用都是在一个平台啦)，如果使用的是默认安装的话，会在<strong>\Program Files (x86)\Windows Kits\10\Platforms\UAP</strong>这个目录，如下图，复制这个版本号，之后需要用到。</p>
<p>&nbsp;<img src="http://images.cnitblog.com/blog2015/700062/201505/041323380016757.png" alt="" /></p>
<p>2. 右键点击需要更新的工程，选择&ldquo;编辑XXX.csproj&rdquo;来编辑工程文件。</p>
<p>&nbsp; &nbsp;&nbsp;<img src="http://images.cnitblog.com/blog2015/700062/201505/041327212986805.png" alt="" /></p>
<p>3. 在编辑页面找到包含<strong>TargetPlatformVersion</strong>和<strong>TargetPlatformMinVersion</strong>两个节点的PropertyGroup节点（一般第一个就是-_-）， 把这两个节点的值替换成第一步中得到的版本号。</p>
<p>&nbsp;</p>
<p>修改后如下：</p>
<p><img src="http://images.cnitblog.com/blog2015/700062/201505/041334129388212.png" alt="" /></p>
<p>&nbsp;</p>
<p>4. 删除所有配置是AnyCPU的PropertyGroup节点，包括子节点，因为这个RC是不支持的了</p>
<p>5. 查看剩下配置是Release的PropertyGroup节点，如果下面没有<strong>UseDotNetNativeToolchain</strong>子节点的话，就动手加一个，值一定要是true， 即：&lt;UseDotNetNativeToolchain&gt;true&lt;/UseDotNetNativeToolchain&gt;</p>
<p>6. 保存之后，右键点击项目，选择&ldquo;重新加载项目&rdquo;，我们的工程终于回来了lol</p>
<p>7. 先不要急，我们还有最后一步，修改manifest文件，将<strong>TargetPlatform</strong>节点的名字改成<strong>TargetDeviceFamily</strong>，两个version属性值改成第一步的版本号，现在我们的工程就可以使用啦。</p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre>  <span>&lt;</span><span>Dependencies</span><span>&gt;</span>
    <span>&lt;</span><span>TargetDeviceFamily </span><span>Name</span><span>="Windows.Universal"</span><span> MinVersion</span><span>="10.0.10069.0"</span><span> MaxVersionTested</span><span>="10.0.10069.0"</span> <span>/&gt;</span>
  <span>&lt;/</span><span>Dependencies</span><span>&gt;</span></pre>
</div>
<p>&nbsp;</p>
<p>PS：如果用上面的方法后，启动的时候出现错误提示的话，可能是系统版本的问题（我在10069上出错的。。），请检查你的Windows 版本号，升级到<strong>10074</strong>或者更高版本就可以了。</p>
</div>
</div>]]></content:encoded>
    </item>
    <item>
      <title>微软颜龄Windows Phone版开发小记</title>
      <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/windows-phone</link>
      <pubDate>Wed, 10 Jun 2015 23:08:15 GMT</pubDate>
      <dc:creator><![CDATA[Windows-China]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows_china_blog/2015/06/10/windows-phone/</guid>
      <description><![CDATA[随着微软颜龄中文网cn.how-old.net的上线，她也顺势来到了3大移动平台。
用户在微软颜龄这一应用中选择一张包含若干人脸的照片，就可以通过云计算得到他们的性别和年龄。
今天我们就和大家分享...]]></description>
      <content:encoded><![CDATA[<p>随着微软颜龄中文网cn.how-old.net的上线，她也顺势来到了3大移动平台。</p>
<p>用户在微软颜龄这一应用中选择一张包含若干人脸的照片，就可以通过云计算得到他们的性别和年龄。</p>
<p>今天我们就和大家分享一下开发windows phone 平台的 <a href="http://www.windowsphone.com/zh-cn/store/app/%E5%BE%AE%E8%BD%AF%E9%A2%9C%E9%BE%84/8f4e7547-7ecb-4736-8306-11b97ba293e1" target="_blank">微软颜龄</a> 中的经验。</p>
<p>用Windows Phone的小伙伴也可以扫描下面的二维码来安装体验一下：</p>
<p><img src="http://images0.cnblogs.com/blog2015/700062/201505/211351488381517.png" alt="" /></p>
<h1>技术背景</h1>
<p>微软颜龄的技术来自必应和微软研究院的<a href="http://www.projectoxford.ai/">Oxford</a>项目。该项目包含大量面部、语言和视觉方面的服务。微软颜龄 这款有趣的应用仅仅使用了其中人脸侦测的部分api。有兴趣的小伙伴可以访问<a href="http://www.projectoxford.ai/"><span>http://www.projectoxford.ai/</span></a>来尝试一下其他api，或许结合上你的好点子，一个有趣的应用就会从你手中诞生。</p>
<h1>FACE API应用</h1>
<p>微软颜龄windows phone版从开始开发到第一版发布只有短短几天时间，能做到这么快的发布，得益于Project Oxford优秀的SDK和例子程序，以及我们在之前的CNBLOGS等UAP应用开发中的积累。</p>
<p>在引用了Project Oxford的.Net <a href="http://www.projectoxford.ai/sdk">SDK</a>之后，我们只要调用<span>FileOpenPicker</span>在应用中得到用户所选择照片的Stream，就可以通过SDK的api分析出照片中人脸的信息：</p>
<p><span><span>///<span> <span>&lt;summary&gt;</span></span></span></span></p>
<p><span><span>///<span> Detects an image asynchronously.</span></span></span></p>
<p><span><span>///<span> <span>&lt;/summary&gt;</span></span></span></span></p>
<p><span><span>///<span> <span>&lt;param name="<span>imageStream<span>"&gt;<span>The image stream.<span>&lt;/param&gt;</span></span></span></span></span></span></span></span></p>
<p><span><span>///<span> <span>&lt;param name="<span>analyzesFaceLandmarks<span>"&gt;<span>If set to <span>&lt;c&gt;<span>true<span>&lt;/c&gt;<span> [analyzes face landmarks].<span>&lt;/param&gt;</span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>///<span> <span>&lt;param name="<span>analyzesAge<span>"&gt;<span>If set to <span>&lt;c&gt;<span>true<span>&lt;/c&gt;<span> [analyzes age].<span>&lt;/param&gt;</span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>///<span> <span>&lt;param name="<span>analyzesGender<span>"&gt;<span>If set to <span>&lt;c&gt;<span>true<span>&lt;/c&gt;<span> [analyzes gender].<span>&lt;/param&gt;</span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>///<span> <span>&lt;param name="<span>analyzesHeadPose<span>"&gt;<span>If set to <span>&lt;c&gt;<span>true<span>&lt;/c&gt;<span> [analyzes head pose].<span>&lt;/param&gt;</span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>///<span> <span>&lt;returns&gt;<span>The detected faces.<span>&lt;/returns&gt;</span></span></span></span></span></span></p>
<p><span><span>public<span> <span>async<span> <span>Task<span>&lt;<span>Face<span>[]&gt; DetectAsync(<span>Stream<span> imageStream, <span>bool<span> analyzesFaceLandmarks = <span>false<span>, <span>bool<span> analyzesAge = <span>false<span>, <span>bool<span> analyzesGender = <span>false<span>, <span>bool<span> analyzesHeadPose = <span>false<span>) </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p>&nbsp;</p>
<p>SDK的api本身可以设置检测包括人脸的整体位置，五官位置(<span>analyzesFaceLandmarks</span>)，年龄(<span>analyzesAge</span>)，性别(<span>analyzesGender</span>)，甚至相对照片平面的三维角度(<span>analyzesHeadPose</span>)，而微软颜龄应用则只是利用了其中的年龄和性别信息。具体可以查看SDK中的Face.cs文件，或是通过在<a href="http://www.projectoxford.ai/demo/face">API Sample</a>上提交一张照片取得分析结果来查看。</p>
<p><img src="http://images0.cnblogs.com/blog/700062/201505/211222428853098.png" alt="" /></p>
<p>在通过SDK的api取得必要的人脸信息之后，我们就可以经过一系列计算，将其展示在用户的图片之上了。这一过程在SDK的例子程序的UIHelper.cs文件中也有现成的，我们可以根据自己的需求对其进行自定义。比如在windows phone版微软颜龄的第二版中，我们就将性别替换为相应图标的路径，并且增加了边框颜色的属性，使得男女在界面上区别更明显：</p>
<p>原版：</p>
<p><img src="http://images0.cnblogs.com/blog/700062/201505/211222475256914.png" alt="" /></p>
<p>第二版：</p>
<p><img src="http://images0.cnblogs.com/blog/700062/201505/211222486196816.png" alt="" /></p>
<h1>不断进步</h1>
<p>接下来我们结合在之前的开发中积累的经验与创新的思路，终于很快地将cn.how-old.net上的体验在windows Phone平台展现出来：</p>
<p>比如首页的自带图片选择控件，就是巧妙地控制了ScrollViewer与StackPanel的共同运作。通过设置ScrollViewer的HorizontalSnapPointsAlignment 及 HorizontalSnapPointsType属性，使得在滑动的时候，Image元素可以总是停在屏幕的正中，就像在浏览相册一样。</p>
<p><span><span>&lt;<span>ScrollViewer<span> x<span>:<span>Name<span>="sc"<span> Grid.Row<span>="1"<span> Margin<span>="0,20,0,0"</span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span> HorizontalScrollBarVisibility<span>="Hidden"</span></span></span></p>
<p><span><span> HorizontalSnapPointsAlignment<span>="Center"</span></span></span></p>
<p><span><span> HorizontalSnapPointsType<span>="Mandatory"</span></span></span></p>
<p><span><span> VerticalAlignment<span>="Top"<span> ViewChanged<span>="sc_ViewChanged"</span></span></span></span></span></p>
<p><span><span> HorizontalAlignment<span>="Center"<span> Width<span>="780"<span> Background<span>="{<span>ThemeResource<span> BackgroundColor<span>}"&gt;</span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;<span>StackPanel<span> Orientation<span>="Horizontal"<span> Height<span>="260"<span> HorizontalAlignment<span>="Center"&gt;</span></span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;<span>Image<span> Source<span>="Assets/Images/Left_Edge.png"<span> Stretch<span>="UniformToFill"<span> Width<span>="260"/&gt;</span></span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;<span>Image<span> Source<span>="Assets/Images/0.png"<span> Stretch<span>="UniformToFill"<span> Width<span>="260"/&gt;</span></span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;<span>Image<span> Source<span>="Assets/Images/1.png"<span> Stretch<span>="UniformToFill"<span> Width<span>="260"/&gt;</span></span></span></span></span></span></span></span></span></p>
<p><span><span>&hellip;</span></span></p>
<p><span><span>&lt;<span>Image<span> Source<span>="Assets/Images/13.png"<span> Stretch<span>="UniformToFill"<span> Width<span>="260"/&gt;</span></span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;<span>Image<span> Source<span>="Assets/Images/14.png"<span> Stretch<span>="UniformToFill"<span> Width<span>="260"/&gt;</span></span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;<span>Image<span> Source<span>="Assets/Images/Right_Edge.jpg"<span> Stretch<span>="UniformToFill"<span> Width<span>="260"/&gt;</span></span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;/<span>StackPanel<span>&gt;</span></span></span></span></p>
<p><span><span>&lt;/<span>ScrollViewer<span>&gt;</span></span></span></span></p>
<p>然而ScrollViewer并不像ListView那样有<span>SelectedIndex属性，</span>那么我们如何知道用户选择的是哪张图片呢？因为我们设置了相同的Image元素宽度，并且ScrollViewer是3倍Image元素的宽度，加上Image元素序列首尾有单独的首尾元素，所以简单的计算一下index就可以了：</p>
<p><span><span>private<span> <span>int<span> idx = 0;</span></span></span></span> </span></p>
<p><span><span>private<span> <span>void<span> sc_ViewChanged(<span>object<span> sender, <span>ScrollViewerViewChangedEventArgs<span> e) </span></span></span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span> idx = (<span>int<span>)(<span>this<span>.sc.HorizontalOffset / 260.0f); </span></span></span></span></span></p>
<p><span> }</span></p>
<p>&nbsp;</p>
<p>另一方面页面布局则是我们的designer的设计与我们在实现UI布局的经验的结合。我们的页面上有不少固定大小的元素，比如上面用来选择自带例子图片的ScrollViewer控件。如果不做任何处理，在大屏手机上就会显得比较小。所以我们在这里利用了Grid与Viewbox的组合：</p>
<p><span>&lt;<span>Grid<span> x<span>:<span>Name<span>="grid_Main"<span> Opacity<span>="0"&gt;</span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;<span>Grid.RowDefinitions<span>&gt;</span></span></span></span></p>
<p><span><span>&lt;<span>RowDefinition<span> Height<span>="100"/&gt;</span></span></span></span></span></p>
<p><span><span>&lt;<span>RowDefinition<span> Height<span>="*"/&gt;</span></span></span></span></span></p>
<p><span><span>&lt;<span>RowDefinition<span> Height<span>="auto"/&gt;</span></span></span></span></span></p>
<p><span><span>&lt;/<span>Grid.RowDefinitions<span>&gt;</span></span></span></span></p>
<p><span><span>&lt;<span>StackPanel<span> Orientation<span>="Horizontal"<span> Margin<span>="10"&gt;</span></span></span></span></span></span></span></p>
<p><span><span>&hellip;</span><span>title行 </span></span></p>
<p><span><span>&lt;/<span>StackPanel<span>&gt;</span></span></span></span></p>
<p><span><span>&lt;<span>Viewbox<span> Grid.Row<span>="1"<span> Width<span>="10000"<span> HorizontalAlignment<span>="Center"<span> Margin<span>="-5000,20"&gt;</span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>&hellip;</span><span>ScrollViewer等图片选择控件 </span></span></p>
<p><span><span>&lt;/<span>Viewbox<span>&gt;</span></span></span></span></p>
<p><span><span>&lt;<span>StackPanel<span> Grid.Row<span>="2"<span> Orientation<span>="Vertical"<span> VerticalAlignment<span>="Center"<span> Margin<span>="0,10"&gt;</span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>&hellip;</span><span>footer行 </span></span></p>
<p><span><span>&lt;/<span>StackPanel<span>&gt;</span></span></span></span></p>
<p><span><span>&lt;/<span>Grid<span>&gt;</span></span></span></span></p>
<p>用Grid设置title和footer为固定高度，而中间ScrollViewer等图片选择控件所占据的空间可以随屏幕变化。加入Viewbox让我们固定大小的控件可以在布局中自动缩放而不必费心费力地通过代码来调整:</p>
<p>Wxga:<img src="http://images0.cnblogs.com/blog/700062/201505/211222507919446.png" alt="" /> 1080p:<img src="http://images0.cnblogs.com/blog/700062/201505/211222526821290.png" alt="" /></p>
<p>是不是很方便呢？</p>
<p>&nbsp;</p>
<h1>小结</h1>
<p>今天就先向大家分享这些心得，欢迎大家继续关注和拍砖，让我们共同进步。</p>
<p>我们的已经发布的应用和代码可以在下面找到：</p>
<p>Windows Phone Store App link:</p>
<p><a href="http://www.windowsphone.com/zh-cn/store/app/%E5%8D%9A%E5%AE%A2%E5%9B%AD-uap/500f08f0-5be8-4723-aff9-a397beee52fc">http://www.windowsphone.com/zh-cn/store/app/博客园-uap/500f08f0-5be8-4723-aff9-a397beee52fc</a></p>
<p>Windows Store App link:</p>
<p><a href="http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059">http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059</a></p>
<p>GitHub open source link:</p>
<p><a href="https://github.com/MS-UAP/cnblogs-UAP">https://github.com/MS-UAP/cnblogs-UAP</a></p>
<p>MSDN Sample Code:</p>
<p><a href="https://code.msdn.microsoft.com/CNBlogs-Client-Universal-9c9692d1">https://code.msdn.microsoft.com/CNBlogs-Client-Universal-9c9692d1</a></p>]]></content:encoded>
    </item>
    <item>
      <title>博客园客户端UAP开发随笔 – 让自己的App连接世界(2)：WinRT中的内置分享</title>
      <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/uap-app2winrt</link>
      <pubDate>Sun, 01 Feb 2015 07:28:00 GMT</pubDate>
      <dc:creator><![CDATA[Windows-China]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows_china_blog/2015/02/01/uap-app2winrt/</guid>
      <description><![CDATA[看到一篇眼前一亮的博文，是不是有一种希望其他小伙伴都能看到的感觉呢？有没有一种&ldquo;不转不是程序员&rdquo;的冲动呢？在 PC 浏览器上看到还好办，直接网址复制，另一边 IM...]]></description>
      <content:encoded><![CDATA[<p>看到一篇眼前一亮的博文，是不是有一种希望其他小伙伴都能看到的感觉呢？有没有一种&ldquo;不转不是程序员&rdquo;的冲动呢？在 PC 浏览器上看到还好办，直接网址复制，另一边 IM 上就发过去了，但是如果是 App 中的内容，就没这么方便了，总不能那边 IM 上喊话：&ldquo;隔壁老王，博客园上有篇叫&lsquo;博客园客户端(Universal App)开发随笔 &ndash; 为应用插上分享的翅膀&rsquo;的博文超好看，要不你也瞅瞅？&rdquo;。隔壁老王再去搜索就太麻烦了。可能你会说了，嗨，直接分享不就完了么。嗯，没错，就是分享功能。那么如何把分享功能引入我们的 App 中呢？往下看。</p>
<p>&nbsp;</p>
<h4>Universal App 中 Windows / Windows Phone 之间分享的异同</h4>
<p>既然是 Universal App，那自然是共享一套分享的代码啦。但是在这两个之间还是有点不一样的。区别在于，Windows 版由于有 Charm Bar 这个系统级的菜单，而这菜单里是自带分享入口的，所以 Windows 版只需要提前准备好需要分享的内容，而不需要再提供另外的分享入口。而 Windows Phone 没有这个入口，所以除了需要准备好内容，还需要通过菜单或按钮的形式，显式提供一个分享的入口。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/221742377979459.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/221742390009458.png" alt="image" width="44" height="244" border="0" /></a></p>
<p>&nbsp;</p>
<p>不过随着 Windows 10 的发布，Charm Bar 的寿命也走到了尽头，在之前的 Technical Preview 中还是偶尔可以（误触）调出 Charm Bar 的，但是在刚刚发布的 Costumer Preview，我们应该就见不到 Charm Bar 的身影了，所有它提供的入口，都被移到了下图所示的位置：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/221742404382933.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/221742419851205.png" alt="image" width="224" height="180" border="0" /></a></p>
<p>&nbsp;</p>
<p>这一点倒是不难理解，因为所有的 App 都可以窗口化了，右滑调出 Charm Bar 的方法已经不好用，所以单独提供一个入口。不过不得不说，这个入口的尺寸不是很适合点击，而且呼出的菜单更是容易误触，尤其是在 Surface Pro 的高分屏上。这个改动，也使得原来上/下滑呼出 App Commands 的操作需要两步才能完成，极为繁琐。我们也因此不得不在新版的博客园中添加了 App Commands 的快捷入口。</p>
<p>另外，Windows 默认提供了两种分享的方式，一是使用开发者提供的信息，二是直接分享当前屏幕截图。而截至到目前的 Windows Phone Technical Preview 中，也是只有一种分享方式的，没有截屏的选项。在 Windows Phone 中，我们还需要手动添加一个入口，如下图所示。</p>
<p>&nbsp;<img src="http://images.cnitblog.com/blog/700062/201501/271133073166758.png" alt="" width="300" height="146" />&nbsp;</p>
<h4>创建分享（以 Text 举例）</h4>
<p>好了，我们以博客园的博文分享举例，来介绍一下如何创建一个分享。</p>
<p>在动手之前，我们要先在脑海里想一下需要分享的内容。例如，博客园我们需要分享如下格式的信息（分割线以内）：</p>
<p>--------------</p>
<p>标题：博文标题</p>
<p>作者：博文作者</p>
<p>摘要：博文摘要</p>
<p>博文链接</p>
<p>--------------</p>
<p>思路是这样的，我们先创建一个字符串，包含以上信息，然后加入注册到分享内容，最后显式或系统调用出分享入口，进行分享。</p>
<p>具体实现如下：</p>
<p>首先添加引用：</p>
<div class="cnblogs_code">
<pre><span>using</span> Windows.ApplicationModel.DataTransfer;</pre>
</div>
<p>然后创建一个叫RegisterForShare的方法，将需要分享的内容注册到分享区：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>private</span> <span>void</span> RegisterForShare()
        {
            DataTransferManager dataTransferManager = DataTransferManager.GetForCurrentView();
            dataTransferManager.DataRequested += <span>new</span> TypedEventHandler&lt;DataTransferManager, DataRequestedEventArgs&gt;(<span>this</span>.ShareTextHandler);
        }</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>在这个方法里，我们创建了一个 DataTransferManager，并让他在 DataRequested 事件时出发 ShareTextHandler 方法：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>private</span> <span>void</span> ShareTextHandler(DataTransferManager sender, DataRequestedEventArgs e)
        {
                DataRequest request = e.Request;
                request.Data.Properties.Title = loader.GetString(<span>"</span><span>ShareTitlePrefixText</span><span>"</span>) + <span>this</span>.post.Title;
                request.Data.Properties.Description = <span>this</span>.post.Summary;
                <span>string</span> summaryText = (<span>this</span>.post.Author != <span>null</span> ? loader.GetString(<span>"</span><span>ShareContentAuthor</span><span>"</span>) + <span>this</span>.post.Author.Name : <span>""</span>) + <span>"</span><span>\n</span><span>"</span>
                    + loader.GetString(<span>"</span><span>ShareContentSummary</span><span>"</span>)               
                    + (<span>this</span>.post.Summary.Length &gt; <span>50</span> ? <span>this</span>.post.Summary.Substring(<span>0</span>, <span>50</span>) : <span>this</span>.post.Summary) + <span>"</span><span>\n</span><span>"</span>
                    + <span>this</span>.post.Link.Href;
            request.Data.SetText(summaryText);
        }</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>接下来实现这个方法，创建一个 request，并完善其中的内容，其中 request.Data.Properties.Title 是会显示在分享的标题部分的内容，例如如果是邮件分享，那么邮件标题就是 request.Data.Properties.Title，如果 Onenote 分享，那么 note 的标题也会是 request.Data.Properties.Title。request.Data.Properties.Description 不是必选项，仅仅是个备注参考，不会在分享时显示出来。最后的 request.Data.SetText(summaryText); 将其余需要分享的内容设置好。这样，我们的需要分享的内容就像之前想的一样都已经填写进去了。</p>
<p>接下来要做的，是先调用 RegisterForShare 方法，这个过程可以在构造函数中完成。</p>
<p>&nbsp;</p>
<h4>分享入口</h4>
<p>如果是 Windows，那么在构造函数调用了 RegisterForShare 方法以后，就已经可以直接分享了，入口就是之前提到过的 Charm Bar 或 菜单：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/221742467972009.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/221742481258280.png" alt="image" width="244" height="218" border="0" /></a></p>
<p>右边的下拉菜单，可以选择分享内容或截屏：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/221742492354953.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/221742504389654.png" alt="image" width="244" height="194" border="0" /></a></p>
<p>我们选择邮件分享内容</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/221742516723599.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/221742530479585.png" alt="image" width="398" height="273" border="0" /></a></p>
<p>就可以发送了。</p>
<p>&nbsp;</p>
<p>如果是 Windows Phone，那么我们还需要多做一步。</p>
<p>创建一个菜单的入口：</p>
<div class="cnblogs_code">
<pre><span>&lt;</span><span>AppBarButton </span><span>x:Name</span><span>="btn_Share"</span><span> x:Uid</span><span>="ShareBlogButton"</span><span> Label</span><span>="分享博文"</span><span> Click</span><span>="btn_Share_Click"</span><span> Icon</span><span>="ReShare"</span><span>/&gt;</span></pre>
</div>
<p>然后在点击的方法中，显式调用分享入口：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>private</span> <span>void</span> btn_Share_Click(<span>object</span> sender, RoutedEventArgs e)
        {
            Windows.ApplicationModel.DataTransfer.DataTransferManager.ShowShareUI();
        }</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>这样，就会调出系统的分享入口：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/221742544065099.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/221742553753028.png" alt="image" width="244" height="156" border="0" /></a></p>
<p>由于是模拟器测试，所以没有 MS Account，因此没有邮件分享的入口。</p>
<p>我们选择短信</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/221742573754373.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/221742594537974.png" alt="image" width="301" height="532" border="0" /></a></p>
<p>&nbsp;</p>
<p>就可以发送分享内容了。</p>
<p>&nbsp;</p>
<h4>其他分享格式</h4>
<p>除了 SetText 来分享 text 格式的内容，我们还可以创建 HTML，WebLink 和 files 等内容。具体实现和 Text 大同小异，实现细节，可以参考：</p>
<p>Text：<a title="https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh871372.aspx" href="https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh871372.aspx">https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh871372.aspx</a></p>
<p>WebLink： <a title="https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh973056.aspx" href="https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh973056.aspx">https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh973056.aspx</a></p>
<p>HTML：<a title="https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh973055.aspx" href="https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh973055.aspx">https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh973055.aspx</a></p>
<p>files：<a title="https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh871371.aspx" href="https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh871371.aspx">https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh871371.aspx</a></p>
<p>&nbsp;</p>
<h4>总结</h4>
<p>通过以上的介绍，我们可以用不多的代码实现将我们喜欢的内容快速分享给他人的目的。我们再也不用担心隔壁老王看不到我们给他们的分（sao）享（rao）了。</p>
<p>&nbsp;</p>
<h2><strong>分享代码，改变世界！</strong></h2>
<p>Windows Phone Store App link:</p>
<p><a href="http://www.windowsphone.com/zh-cn/store/app/">http://www.windowsphone.com/zh-cn/store/app/博客园-uap/500f08f0-5be8-4723-aff9-a397beee52fc</a></p>
<p>Windows Store App link:</p>
<p><a href="http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059">http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059</a></p>
<p>GitHub open source link:</p>
<p><a href="https://github.com/MS-UAP/cnblogs-UAP">https://github.com/MS-UAP/cnblogs-UAP</a></p>
<p>MSDN Sample Code:</p>
<p><a href="https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab">https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab</a></p>]]></content:encoded>
    </item>
    <item>
      <title>博客园客户端UAP开发随笔 – 最后一哆嗦：App发布</title>
      <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/uap-app</link>
      <pubDate>Sun, 01 Feb 2015 07:27:04 GMT</pubDate>
      <dc:creator><![CDATA[Windows-China]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows_china_blog/2015/02/01/uap-app/</guid>
      <description><![CDATA[在费尽无数脑细胞开发出一款 App 并且通过测试，自我感觉良好的时候，我们一定希望我们的 App...]]></description>
      <content:encoded><![CDATA[<p>在费尽无数脑细胞开发出一款 App 并且通过测试，自我感觉良好的时候，我们一定希望我们的 App 能够尽快出现在商店的首页上，被人下载，使用，打分，评价，反馈，甚至是被无情地喷。但据本人经验，通常从项目打包好（打包的具体注意事项，请参见前文：<a id="cb_post_title_url" class="postTitle2" href="http://www.cnblogs.com/ms-uap/p/4182149.html">博客园客户端(Universal App)开发随笔 &ndash; App也需要物流前的打包</a>），到通过审核，其他用户在商店可以看到，往往都像新手第一次编译程序一样，一波三折，弹出不同的错误和警告，这个时候，只有耐下性子，一个一个问题都解决了，才能顺利通过审核。所以我觉得还是很有必要写点什么，讲一下 App 发布时的注意事项，省得大家多走弯路。</p>
<h4>&nbsp;</h4>
<p>虽说开发时已经选择了 Universal App，但是上传到商店的入口还没有统一。所以我们还是要像以前一样，分别将 App 上传到：</p>
<p>Windows 应用商店：<a title="https://appdev.microsoft.com/StorePortals/zh-CN/Home/Index" href="https://appdev.microsoft.com/StorePortals/zh-CN/Home/Index">https://appdev.microsoft.com/StorePortals/zh-CN/Home/Index</a></p>
<p>Windows Phone 应用商店：<a title="http://dev.windows.com/zh-cn" href="http://dev.windows.com/zh-cn">http://dev.windows.com/zh-cn</a></p>
<p>希望能早日看到这两个商店大一统的一天。</p>
<p>&nbsp;</p>
<h4>Windows App 提交：</h4>
<p>提交应用前，非常重要的一点：</p>
<p>确认账户信息中：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121723463702650.png"><img title="Capture" src="http://images.cnitblog.com/blog/700062/201501/121723480115349.png" alt="Capture" width="499" height="297" border="0" /></a></p>
<p>用户显示的名称和 ID 和打包的应用的 Manifest 文件中的一致，否则上传应用的时候不会通过自动审核。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121723501366733.png"><img title="w8_1" src="http://images.cnitblog.com/blog/700062/201501/121723514481532.png" alt="w8_1" width="225" height="278" border="0" /></a></p>
<p><a title="https://appdev.microsoft.com/StorePortals/zh-CN/Home/Index" href="https://appdev.microsoft.com/StorePortals/zh-CN/Home/Index">https://appdev.microsoft.com/StorePortals/zh-CN/Home/Index</a></p>
<p>进入商店以后，在 Dashboard 的下面有一行不起眼的小字：Submit an app。这就是提交新应用的入口了。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121723534791944.png"><img title="w8_2" src="http://images.cnitblog.com/blog/700062/201501/121723556831071.png" alt="w8_2" width="792" height="931" border="0" /></a></p>
<p>点击进入提交入口以后，可不是上传之前打包的应用就可以了，看着这么长长的一串需要填写的东西，千万不要被吓到。App 开发的过程比这难多了，App 都开发了，岂能败在这小小的提交步骤上。</p>
<p>一步一步慢慢来。首先从 App Name开始。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121723580266155.png"><img title="w8_3" src="http://images.cnitblog.com/blog/700062/201501/121724003548010.png" alt="w8_3" width="803" height="337" border="0" /></a></p>
<p>每个应用都要有一个独一无二的名字，这应该在开发之前就已经定下来了，这个时候就是检验创意的时候了。大家都做天气应用，那可千万不要都&ldquo;不约而同&rdquo;地选择&ldquo;天气预报&rdquo;这个名字。名字要独一无二，这样才不至于和其他的应用混淆，但又不要太标新立异，以至于用户看到都不知道是什么应用，因此错过就不好了。所以起名字一定要选择一个好记，明确，个性的好名字。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724017292024.png"><img title="w8_4" src="http://images.cnitblog.com/blog/700062/201501/121724032149237.png" alt="w8_4" width="812" height="359" border="0" /></a></p>
<p>起完名字，就要选择应用的价位了。作者得意的应用当然有自信开个好价位了。不过我们的博客园 UAP 是一个共同学习的过程，自然是免费多销啦。</p>
<p>P.S. 如果发布收费应用，需要在开发者账户中将信用卡和税务信息都填写完整。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724049488207.png"><img title="w8_5" src="http://images.cnitblog.com/blog/700062/201501/121724062766235.png" alt="w8_5" width="680" height="405" border="0" /></a></p>
<p>如果希望应用被更多的人看到，那尽量是全球多多益善了。要知道，其他国家的华人也是一个不小的数目呢。当然，还有那些 Windows 账户故意填写了其他国家或填错了的用户&hellip;&hellip;</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724079178934.png"><img title="w8_6" src="http://images.cnitblog.com/blog/700062/201501/121724092922948.png" alt="w8_6" width="778" height="441" border="0" /></a></p>
<p>如果希望应用通过审核以后立刻发布，就选择 Release my app as soon as it passes certification. 这一选项。否则，就选择一个特定时间发布。</p>
<p>应用的分类尽量填写准确，大家是不是也不想我们的博客园应用在饮食频道被搜索到呢。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724108231446.png"><img title="w8_7" src="http://images.cnitblog.com/blog/700062/201501/121724121831230.png" alt="w8_7" width="813" height="406" border="0" /></a></p>
<p>如果开发的时候没有使用特殊的需求，这些选项可以不先用管。如果你的应用必须触摸操作，硬件要求很高或为特殊人士设计，就针对自己的应用进行选择。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724135891702.png"><img title="w8_8" src="http://images.cnitblog.com/blog/700062/201501/121724148237757.png" alt="w8_8" width="800" height="486" border="0" /></a></p>
<p>内购现在已经是一个很大的潮流，如果你希望自己的应用走免费推广+内购赚钱的模式，就需要在这里填写相应的信息。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724161204028.png"><img title="w8_9" src="http://images.cnitblog.com/blog/700062/201501/121724176209769.png" alt="w8_9" width="363" height="661" border="0" /></a></p>
<p>针对自己的应用填写对应的年龄分级审核信息。如果没有特殊针对儿童的内容和儿童不适的内容，推荐填写12+。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724186679583.png"><img title="w8_10" src="http://images.cnitblog.com/blog/700062/201501/121724198393126.png" alt="w8_10" width="191" height="366" border="0" /></a></p>
<p>针对这四个地区推出的游戏需要填写特殊材料。其他应用可以无视。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724214488366.png"><img title="w8_11" src="http://images.cnitblog.com/blog/700062/201501/121724228544137.png" alt="w8_11" width="477" height="496" border="0" /></a></p>
<p>特殊加密和安全的应用需要填写相关信息。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724241673636.png"><img title="w8_12" src="http://images.cnitblog.com/blog/700062/201501/121724255114893.png" alt="w8_12" width="807" height="603" border="0" /></a></p>
<p>关键的内容来了。终于要上传我们辛辛苦苦打好的包了。找到打包的文件夹，把 appxupload 文件拖进去就行。如果没有问题，会显示上传成功，否则会提示错误信息，例如开发者 ID 不符，打包在 debug 模式下进行，应用内缺少某些文件等等。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724268541448.png"><img title="w8_13" src="http://images.cnitblog.com/blog/700062/201501/121724287925590.png" alt="w8_13" width="588" height="530" border="0" /></a></p>
<p>这些应用描述信息，应用功能等信息大家自己填写就好，不要嫌麻烦，越详细越好，毕竟到时候所有用户都会根据这些信息决定是否下载应用。</p>
<p>需要注意的是，支持多语言的应用，每种语言都要填写对应语言的信息。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724303234089.png"><img title="w8_14" src="http://images.cnitblog.com/blog/700062/201501/121724316512116.png" alt="w8_14" width="750" height="304" border="0" /></a></p>
<p>针对应用最主要的功能进行屏幕截图，推荐在高分辨率下进行截图。早期的商店限制截图必须是 Visual Studio 的模拟器截图，并且不能进行 PS 处理修改，现在貌似是放宽了这一限制。</p>
<p>同样需要注意的是，支持多语言的应用，每种语言都要提供该语言版本的截图。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724328709643.png"><img title="w8_15" src="http://images.cnitblog.com/blog/700062/201501/121724339482215.png" alt="w8_15" width="550" height="270" border="0" /></a></p>
<p>Notes 用来填写每次更新的版本信息。</p>
<p>如果希望更多人是用自己的应用，而且确实没有什么硬件制约，推荐硬件一栏不需填写。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724356043441.png"><img title="w8_16" src="http://images.cnitblog.com/blog/700062/201501/121724371836925.png" alt="w8_16" width="659" height="841" border="0" /></a></p>
<p>这里就是一些其他信息的填写。关键词可以让你的应用更容易被搜索到。其他的版权，联系人信息必须填写。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724387616112.png"><img title="w8_17" src="http://images.cnitblog.com/blog/700062/201501/121724404643325.png" alt="w8_17" width="550" height="450" border="0" /></a></p>
<p>这一栏非常重要。这是写给审核你的应用的微软测试人员看的，他们会对你的应用进行简单试用以确保以下几点。</p>
<p>1. 确认你的应用有价值。这一点很重要，之前我遇到过几个开发者提交的应用由于被测试人员认为无意义而退回的。当然这个审核由于是人进行，所以根据测试人员的不同，通过的概率也不一样，我也见过同一个应用不做修改多提交几次就通过的情况。所以如果你的应用有什么特殊入口和功能，请一定要标注出来，否则测试人员找不到你的功能，可能会认为该应用无意义。</p>
<p>2. 没有不符合应用年龄分级的信息。</p>
<p>3. 没有明显的导致崩溃的大bug。</p>
<p>另外，如果应用需要注册才能使用，请一定提供一个测试账号给测试人员，他们<span>懒得</span>没有时间去注册新用户。</p>
<p>&nbsp;</p>
<p>好啦，经过上面的九九八十一难，Windows App 终于可以进入机器测试和人工审核步骤了。请静候佳音。如果被退回，请仔细阅读错误信息，并予以修改。</p>
<p>&nbsp;</p>
<h4>Windows Phone App 提交：</h4>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724416836151.png"><img title="wp_0" src="http://images.cnitblog.com/blog/700062/201501/121724429489664.png" alt="wp_0" width="538" height="199" border="0" /></a></p>
<p>Windows Phone 商店的提交应用的按钮比 Windows 那边的要醒目多了嘛&hellip;&hellip;这样才对。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724449335091.png"><img title="wp_1" src="http://images.cnitblog.com/blog/700062/201501/121724464951049.png" alt="wp_1" width="766" height="860" border="0" /></a></p>
<p>貌似步骤少多了，可以看出微软还是希望大力推广 WP 应用的，审核步骤都简化了。而且根据笔者经验，同样的应用，WP 版的审核步骤通常要快许多。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724481834032.png"><img title="wp_2" src="http://images.cnitblog.com/blog/700062/201501/121724498548487.png" alt="wp_2" width="630" height="331" border="0" /></a></p>
<p>应用名称。这里值得注意的一点是，如果之前提交过 Windows 版的应用，那么这里再次填写同一个名字的话，后面的保留名称选项会变成关联名称，点击以后会将两个应用关联起来，以后在商店看到的时候会有这么一个标记：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724510113503.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/121724528239214.png" alt="image" width="271" height="34" border="0" /></a></p>
<p>表明该应用同时拥有 WP 和 Windows 两个版本。关于应用关联的具体细节，后文还会专门予以说明。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724540264514.png"><img title="wp_3" src="http://images.cnitblog.com/blog/700062/201501/121724555899470.png" alt="wp_3" width="628" height="239" border="0" /></a></p>
<p>应用种类，可以参考 Windows 版部分。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724568702512.png"><img title="wp_4" src="http://images.cnitblog.com/blog/700062/201501/121724582921511.png" alt="wp_4" width="739" height="272" border="0" /></a></p>
<p>如果应用和 Windows 版关联，那么根据微软的说明：</p>
<blockquote>
<p>已在任一应用商店中购买应用的客户将能够从另一个应用商店下载该应用，而无需再次支付其费用（即使应用价格是不同的）。<br />已在 Windows 上购买耐用应用内购买的客户将能够使用相同的购买，而无需在 Windows Phone 上再次支付其费用（反之亦然）。</p>
<p>&nbsp;</p>
</blockquote>
<p><span>所以大家定价的时候也要考虑到这一点。</span></p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121724598085780.png"><img title="wp_5" src="http://images.cnitblog.com/blog/700062/201501/121725010586065.png" alt="wp_5" width="680" height="215" border="0" /></a></p>
<p>针对中国有特殊的选项&hellip;&hellip;不解释。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121725024339078.png"><img title="wp_6" src="http://images.cnitblog.com/blog/700062/201501/121725040266792.png" alt="wp_6" width="747" height="772" border="0" /></a></p>
<p>发布后是否立即发布或隐藏的选项，不难理解。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121725052921306.png"><img title="wp_7" src="http://images.cnitblog.com/blog/700062/201501/121725066362563.png" alt="wp_7" width="898" height="739" border="0" /></a></p>
<p>同样上传打好的包，如果更新应用的话点击 Replace 选项。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121725076048931.png"><img title="wp_8" src="http://images.cnitblog.com/blog/700062/201501/121725086206989.png" alt="wp_8" width="712" height="658" border="0" /></a></p>
<p>针对不同语言填写不同的介绍内容。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121725096365046.png"><img title="wp_9" src="http://images.cnitblog.com/blog/700062/201501/121725107295144.png" alt="wp_9" width="508" height="253" border="0" /></a></p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121725115897715.png"><img title="wp_10" src="http://images.cnitblog.com/blog/700062/201501/121725131042985.png" alt="wp_10" width="257" height="490" border="0" /></a></p>
<p>以上内容和 Windows 版类似，不再赘述。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121725140898285.png"><img title="wp_11" src="http://images.cnitblog.com/blog/700062/201501/121725152923584.png" alt="wp_11" width="570" height="438" border="0" /></a></p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121725165269639.png"><img title="wp_13" src="http://images.cnitblog.com/blog/700062/201501/121725178701897.png" alt="wp_13" width="573" height="475" border="0" /></a></p>
<p>截图部分，需要注意的是，如果不选中 Automatically create lower resolution screenshots from WXGA 这一选项，那么需要针对每一个支持的分辨率提供相应的截图。所以推荐在选择模拟器的时候，选择下图所示的 WXGA模拟器进行截图，然后让商店自动生成其他分辨率的截图。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121725191365410.png"><img title="wp_14" src="http://images.cnitblog.com/blog/700062/201501/121725204014222.png" alt="wp_14" width="416" height="418" border="0" /></a></p>
<p>选择 WXGA 模拟器进行截图。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121725217143722.png"><img title="wp_15" src="http://images.cnitblog.com/blog/700062/201501/121725228083820.png" alt="wp_15" width="976" height="306" border="0" /></a></p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121725238543634.png"><img title="wp_16" src="http://images.cnitblog.com/blog/700062/201501/121725251831662.png" alt="wp_16" width="710" height="367" border="0" /></a></p>
<p>以上两项不是必选项，只有使用到的时候才需要填写。</p>
<p>&nbsp;</p>
<p>从应用审核的难度看，不难看出微软推广 WP 的意图，当然这也客观为开发者提供了不少便利。</p>
<p>&nbsp;</p>
<h4>应用在两个商店的关联</h4>
<p>最后说一下应用不同版本之间的关联。在推广 Universal App 的同时，微软也允许用户将应用在两个商店进行关联。</p>
<blockquote>
<p>当你针对提交到 Windows 应用商店和 Windows Phone 应用商店的应用使用同一保留名称时，该应用将被视为共享相同的标识。 这允许客户在其所有 Windows 设备上下载该应用，这会提高应用的使用率并提升应用的吸引力。</p>
</blockquote>
<p><span>关联的好处都有啥？谁说对了&hellip;&hellip;</span></p>
<blockquote>
<ul>
<li>已在任一应用商店中购买应用的客户将能够从另一个应用商店下载该应用，而无需再次支付其费用（即使应用价格是不同的）。</li>
<li>已在 Windows 上购买耐用应用内购买的客户将能够使用相同的购买，而无需在 Windows Phone 上再次支付其费用（反之亦然）。</li>
<li>应用可以跨 Windows 和 Windows Phone 漫游数据。</li>
<li>将应用适用于推送通知的相同 WNS 配置设置（以便该应用的通知可以显示在所有设备上）。</li>
<li>对于在这两个应用商店中发布应用所在的市场，将同时在 Windows 应用商店和 Windows Phone 应用商店中显示应用列表图标。这可以让客户知道如果他们可将应用放入 Windows 应用商店，则他们也可以在兼容的 Windows Phone 上下载该应用（反之亦然）。</li>
</ul>
</blockquote>
<p>具体细节，请参考</p>
<p><em>在 Windows 应用商店和 Windows Phone 应用商店中共享你的应用的标识</em></p>
<p><a title="http://msdn.microsoft.com/zh-cn/library/windows/apps/dn646927.aspx" href="http://msdn.microsoft.com/zh-cn/library/windows/apps/dn646927.aspx">http://msdn.microsoft.com/zh-cn/library/windows/apps/dn646927.aspx</a></p>
<p>&nbsp;</p>
<p>好了，看到自己的应用终于出现在应用商店中，是不是开发时遇到的导致想摔电脑的困难都飞到九霄云外了呢？得意过后，是不是又要开始关注下载量，反馈和版本更新了呢？开发无止境，少（diao）年（si）们，继续上路吧！</p>
<p>&nbsp;</p>
<p>哦对了，本文多图<span>杀猫</span>杀流量&hellip;&hellip;</p>
<h6>&nbsp;</h6>
<h6><strong>分享代码，改变世界！</strong></h6>
<p>Windows Phone Store App link:</p>
<p><a href="http://www.windowsphone.com/zh-cn/store/app/">http://www.windowsphone.com/zh-cn/store/app/博客园-uap/500f08f0-5be8-4723-aff9-a397beee52fc</a></p>
<p>Windows Store App link:</p>
<p><a href="http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059">http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059</a></p>
<p>GitHub open source link:</p>
<p><a href="https://github.com/MS-UAP/cnblogs-UAP">https://github.com/MS-UAP/cnblogs-UAP</a></p>
<p>MSDN Sample Code:</p>
<p><a href="https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab">https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab</a></p>]]></content:encoded>
    </item>
    <item>
      <title>博客园客户端UAP开发随笔 – App也需要物流前的打包</title>
      <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/uap-app-2</link>
      <pubDate>Sun, 01 Feb 2015 07:25:57 GMT</pubDate>
      <dc:creator><![CDATA[Windows-China]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows_china_blog/2015/02/01/uap-app-2/</guid>
      <description><![CDATA[想起来一个笑话：唐僧一行千辛万苦来到佛祖面前，准备取经，佛祖轻声问了一句：汝等带U盘了吗？师徒4人立刻昏倒在地。好吧，扯远了，不过是想告诉大家准备工作一定要到位。
Universal App...]]></description>
      <content:encoded><![CDATA[<p>想起来一个笑话：唐僧一行千辛万苦来到佛祖面前，准备取经，佛祖轻声问了一句：汝等带U盘了吗？师徒4人立刻昏倒在地。好吧，扯远了，不过是想告诉大家准备工作一定要到位。</p>
<p>Universal App 的打包发布其实与传统的 Windows Phone / Windows Store App 项目并无太大不同，但是鉴于总有人会在这些步骤中遇到问题，而且即使是发布过几个应用的开发者也不例外，所以对这个看起来比较繁琐的过程做一个小结还是必要的。</p>
<h2>&nbsp;</h2>
<h3>打包前的准备工作</h3>
<p>&nbsp;</p>
<h4>1. 修改编译模式</h4>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241250514685323.png"><img title="w8_00" src="http://images.cnitblog.com/blog/700062/201412/241250530468807.png" alt="w8_00" width="343" height="53" border="0" /></a></p>
<p>在调试程序时,我们通常会选择 debug 模式，但是发布时不要忘记切换到 Release 模式，否则程序打包后连验证程序都不会执行，更不用说上传到应用商店了。为了保证程序在所有设备上都运行，我们选择 Any CPU，这样就可以保证我们的 UAP 运行在所有可以运行的平台上（包括基于 ARM 架构的 Windows RT 平板和基于 x86 架构的平板，例如 Surface Pro）了。</p>
<h4>&nbsp;</h4>
<p>&nbsp;</p>
<h4>2. 修改 Manifest 文件</h4>
<p>&nbsp;</p>
<p>Manifest 文件记录了项目中的一些基础元数据，包括项目名称，申请的权限，项目的 Logo 和发布者信息等等，只有这些信息都填写完整并且准确，打包的文件才能保证通过上传时的自动验证。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241250542182350.png"><img title="w8_8" src="http://images.cnitblog.com/blog/700062/201412/241250558273293.png" alt="w8_8" width="244" height="44" border="0" /></a></p>
<p>在项目中我们可以找到本项目的 appxmanifest 文件。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241250577339976.png"><img title="w8_0" src="http://images.cnitblog.com/blog/700062/201412/241251001712331.png" alt="w8_0" width="418" height="384" border="0" /></a></p>
<p>我们还可以通过菜单中的选项找到修改 Manifest 文件的入口。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>下面我们来逐个标签检查 Manifest 文件的内容是否完整。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251024682430.png"><img title="w8_1" src="http://images.cnitblog.com/blog/700062/201412/241251048127514.png" alt="w8_1" width="645" height="450" border="0" /></a></p>
<p>&nbsp;</p>
<p>在 Application 标签页中，我们需要填写项目的基本信息，并确认是否需要修改对应的屏幕旋转方向和在锁屏时如何通知用户。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251066085698.png"><img title="wp_1" src="http://images.cnitblog.com/blog/700062/201412/241251086717867.png" alt="wp_1" width="449" height="126" border="0" /></a></p>
<p>与 Windows 项目不同的是， Windows Phone 项目还需要用户填写是否允许将 App 安装到 SD 卡的选项。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251105771254.png"><img title="w8_2" src="http://images.cnitblog.com/blog/700062/201412/241251127809379.png" alt="w8_2" width="648" height="460" border="0" /></a></p>
<p>在 Visual Assets 标签页中，我们需要将所有用到的 Logo 图片做好对应，一般来说，如果在 Assets 文件夹中图片的命名规范正确的话，这里可以自动检测并将图片自动载入的。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251150151264.png"><img title="w8_3" src="http://images.cnitblog.com/blog/700062/201412/241251168272677.png" alt="w8_3" width="653" height="274" border="0" /></a></p>
<p>需要注意的是，Badge Logo 的图片要求比较严格，要求只能有白色和透明两种颜色，哪怕有一个像素出现别的颜色，都会在自动验证程序时检测到并且不予通过，所以修改这几个图片的时候要务必小心，确认只包含白色和透明色。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251184997133.png"><img title="w8_4" src="http://images.cnitblog.com/blog/700062/201412/241251210156230.png" alt="w8_4" width="656" height="346" border="0" /></a></p>
<p>在 Capabilities 页面，我们需要填写项目申请的权限，例如本项目必须在网络下运行，所以必须申请 Internet 权限。最关键的注意事项是，任何 Windows App，如果申请了网络权限，就必须在 Setting 菜单中添加隐私声明 （Privacy Statement）的入口，否则会不能通过人工审核阶段。关于如何添加隐私声明，请参考之前的博客：<a href="http://www.cnblogs.com/ms-uap/p/4158082.html">博客园客户端(Universal App)开发随笔 - Setting Page的实现方法与经验</a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251224053473.png"><img title="wp_2" src="http://images.cnitblog.com/blog/700062/201412/241251243274386.png" alt="wp_2" width="583" height="233" border="0" /></a></p>
<p>Windows Phone 的项目还需要额外填写对于设备传感器的申请，如果在 App 中应用到了陀螺仪，磁场传感器，NFC，前/后摄像头等资源，需要在这里予以声明。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251260469126.png"><img title="w8_5" src="http://images.cnitblog.com/blog/700062/201412/241251282964239.png" alt="w8_5" width="659" height="422" border="0" /></a></p>
<p>在 Declarations 标签页中，我们要对 App 使用的其他资源进行声明，例如博客园项目使用到了后台任务，就需要在这里声明后台任务的入口。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251301551639.png"><img title="w8_6" src="http://images.cnitblog.com/blog/700062/201412/241251320931079.png" alt="w8_6" width="1108" height="141" border="0" /></a></p>
<p>如果 App 使用到了特殊的通知事件，可以在 Content URIs 页面进行声明，需要注意的是，Windows 8.1 仅支持 https 协议的安全页面，不再支持 http 协议。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251335778293.png"><img title="w8_7" src="http://images.cnitblog.com/blog/700062/201412/241251352186291.png" alt="w8_7" width="664" height="306" border="0" /></a></p>
<p>Packaging 页面非常关键，这里的任何一项填错都会导致项目通不过上传时的自动审核。不过好在如果我们在下面的步骤中选择了将项目对应到商店中的 App，那么这个页面中的大部分项目都会自动填好。而如果我们选择仅仅打包，委托别人帮忙发布，那么这些信息就一定要填写完整。本页面中需要填写的信息，可以在对应的开发者账户页面找到信息。</p>
<p>另一个注意事项是最后的 Generate app bundle 选项。如果选择了 always，那么如果之前的 Visual Assets 中有对应的多种尺寸的图片，那么打包时就会生成一个对应多种尺寸设备的整包（bundle）。这样以后再更新项目，也必须上传一个 bundle，否则就不能通过上传审核。这也意味着，Assets 文件夹里的图片只能增加，不能再减少。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251375468146.png"><img title="w8_9" src="http://images.cnitblog.com/blog/700062/201412/241251401242160.png" alt="w8_9" width="673" height="520" border="0" /></a></p>
<p>当然以上的所有项目，我们都可以右键点击 manifest 文件，选择 view code 进行修改或更新。貌似这也是一个更适合 geek 的方法。</p>
<p>&nbsp;</p>
<h3>开始打包</h3>
<p>Manifest 文件修改完之后，我们就可以开始正式的打包工作了。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251419833858.png"><img title="w8_0" src="http://images.cnitblog.com/blog/700062/201412/241251442492200.png" alt="w8_0" width="418" height="384" border="0" /></a></p>
<p>这里我们选择 Create App Packages</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251458587441.png"><img title="w8_10" src="http://images.cnitblog.com/blog/700062/201412/241251480779796.png" alt="w8_10" width="578" height="473" border="0" /></a></p>
<p>在这里，有两种选择，选择Yes是直接登陆 Microsoft Dev 账户，将项目和商店中的 App 进行绑定，这样 Manifest 文件中关于开发者的信息会自动更新到 Microsoft Dev 账户的对应信息。这种方式适用于自己发布自己项目的情况。</p>
<p>选择No是不登陆账户，仅仅打包。这种情况适用于委托第三方帮忙发布项目的情况，或者是想先打个包出来给别人共享用作测试，测试完成后，你就可以直接用这个测试包提交应用了，这样更符合一般的工作流程，避免你的测试包和最后提交商店的包不一致。</p>
<p><strong>我们强烈建议选择No，使用第二种方式。</strong>&nbsp;在下一篇随笔中会详细说到如何提交应用。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251500461994.png"><img title="w8_11" src="http://images.cnitblog.com/blog/700062/201412/241251519058393.png" alt="w8_11" width="541" height="440" border="0" /></a></p>
<p>我们先选择第一种，登陆 Microsoft Dev 账户。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251535773850.png"><img title="w8_12" src="http://images.cnitblog.com/blog/700062/201412/241251555628276.png" alt="w8_12" width="544" height="443" border="0" /></a></p>
<p>登陆以后，该开发者之前提交过的项目就都显示出来，我们也可以为新项目重新预留一个名字。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241251569991505.png"><img title="w8_13" src="http://images.cnitblog.com/blog/700062/201412/241251588271446.png" alt="w8_13" width="548" height="446" border="0" /></a></p>
<p>为项目选择版本信息，输出位置，是否打包生成和 CPU 等信息。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241252004832673.png"><img title="w8_14" src="http://images.cnitblog.com/blog/700062/201412/241252028589513.png" alt="w8_14" width="548" height="446" border="0" /></a></p>
<p>都填写完之后，就可以打包项目了。打包完成后，会显示项目位置，并会提醒开发者为项目执行验证程序（Windows App Certification Kit）。由于上传后服务器会首先执行这个程序对项目进行初次自动验证，如果有不合规范的地方就不予通过，所以为了确保上传的成功性，我们通常会在本机先执行一次验证程序。</p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241252047335441.png"><img title="w8_16" src="http://images.cnitblog.com/blog/700062/201412/241252065625382.png" alt="w8_16" width="556" height="402" border="0" /></a></p>
<p><a href="http://images.cnitblog.com/blog/700062/201412/241252081087110.png"><img title="w8_17" src="http://images.cnitblog.com/blog/700062/201412/241252095306109.png" alt="w8_17" width="559" height="405" border="0" /></a></p>
<p>&nbsp;</p>
<p>如果验证程序在本机通过，那么就可以向商店上传应用了。由于篇幅所限，我们会在将来的文章中继续介绍商店上传的注意事项。</p>
<p>&nbsp;</p>
<h3>总结</h3>
<p>本文按照流程介绍了 Universal App 在上传商店前的打包步骤，并分析了 Windows 和 Windows Phone App打包时的细小区别和容易导致上传失败的注意事项。</p>
<p>&nbsp;</p>
<p>我们的已经发布的应用和代码可以在下面找到：</p>
<p>Windows Phone Store App link:</p>
<p><a href="http://www.windowsphone.com/zh-cn/store/app/%E5%8D%9A%E5%AE%A2%E5%9B%AD-uap/500f08f0-5be8-4723-aff9-a397beee52fc">http://www.windowsphone.com/zh-cn/store/app/博客园-uap/500f08f0-5be8-4723-aff9-a397beee52fc</a></p>
<p>&nbsp;</p>
<p>Windows Store App link:</p>
<p><a href="http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059">http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059</a></p>
<p>&nbsp;</p>
<p>GitHub open source link:</p>
<p><a href="https://github.com/MS-UAP/cnblogs-UAP">https://github.com/MS-UAP/cnblogs-UAP</a></p>
<p>&nbsp;</p>
<p>MSDN Sample Code:</p>
<p><a href="https://code.msdn.microsoft.com/CNBlogs-Client-Universal-9c9692d1">https://code.msdn.microsoft.com/CNBlogs-Client-Universal-9c9692d1</a></p>]]></content:encoded>
    </item>
    <item>
      <title>博客园客户端UAP开发随笔 -- 让自己的App连接世界：WinRT中的微博分享</title>
      <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/uap-appwinrt</link>
      <pubDate>Sun, 01 Feb 2015 07:25:07 GMT</pubDate>
      <dc:creator><![CDATA[Windows-China]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows_china_blog/2015/02/01/uap-appwinrt/</guid>
      <description><![CDATA[近年来社交app可谓红红火火，大家每天发微博，分享到朋友圈也是不亦乐乎。我们的Universal应用自然也希望加入社交分享的功能。然而国内主流的社交平台微博和微信还没有推出适用于Universal应用...]]></description>
      <content:encoded><![CDATA[<p>近年来社交app可谓红红火火，大家每天发微博，分享到朋友圈也是不亦乐乎。我们的Universal应用自然也希望加入社交分享的功能。然而国内主流的社交平台微博和微信还没有推出适用于Universal应用的SDK，怎么办呢？当然敲碗等开饭也是办法，另一方面我们也可以自己做一些努力。今天我们就想分享一下我们在Universal应用中实现分享到微博功能上的探索。</p>
<h1>准备</h1>
<p>想要分享到微博，先得注册成为微博开发者。我们在<a href="http://open.weibo.com/">http://open.weibo.com/</a>上注册好开发者账号，建立个测试应用，就可以拿到我们的App key和App secret了，准备工作就是这样。</p>
<h1>做一些努力</h1>
<p>下面就是SDK的问题了，其实微博是有一个官方开源的for Windows 8 SDK的，还是基于Windows RunTime的。这个SDK的下载地址是<a href="http://weibowinrtsdk.codeplex.com/">http://weibowinrtsdk.codeplex.com/</a>。</p>
<p>我们的Universal 应用不也是基于Windows RunTime的吗？是不是通用呢？先把它的代码下载下来吧。在<a href="http://weibowinrtsdk.codeplex.com/SourceControl/latest">http://weibowinrtsdk.codeplex.com/SourceControl/latest</a> 页面点download，下载下来的内容包括说明文档，SDK的源码，还有一个例子程序。</p>
<p>打开WeiboSDKForWinRT.sln，我们可以看到微博SDK原来是for Windows 8的：</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044359791873.png" alt="" /></p>
<p>点击一下 重定目标到Windows 8.1， 确定。好了，我们的SDK已经是for Windows 8.1的了:</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044372618615.png" alt="" /></p>
<p>那我们的Universal应用还有Windows Phone 8.1 怎么办呢？理想的情况是我们在目标里加上Windows Phone 8.1 就可以了，先这么做试试看：</p>
<p>点击 更改&hellip; ，勾选Windows Phone 8.1</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044386986142.png" alt="" /></p>
<p>确定</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044398545455.png" alt="" /> <img src="http://images.cnitblog.com/blog/700062/201501/132044411045740.png" alt="" /></p>
<p>添加好了，SDK项目的后缀也变成了 可移植的。</p>
<p>马上就在 Universal应用里试一试吧。在解决方案里新建个Universal 应用，引用上我们的SDK。</p>
<p>先从Windows 8.1 应用开始吧，调用代码可以从例子程序里copy一些。</p>
<p>我们在空白的<span>MainPage</span>页面上加个button，点击可以调用微博SDK授权并发一条纯文字微博:</p>
<p>MainPage.xaml：</p>
<p><span>&lt;<span>Page</span></span></p>
<p><span><span> x<span>:<span>Class<span>="App1.MainPage"</span></span></span></span></span></p>
<p><span><span> xmlns<span>="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></span></span></p>
<p><span><span> xmlns<span>:<span>x<span>="http://schemas.microsoft.com/winfx/2006/xaml"</span></span></span></span></span></p>
<p><span><span> xmlns<span>:<span>local<span>="using:App1"</span></span></span></span></span></p>
<p><span><span> xmlns<span>:<span>d<span>="http://schemas.microsoft.com/expression/blend/2008"</span></span></span></span></span></p>
<p><span><span> xmlns<span>:<span>mc<span>="http://schemas.openxmlformats.org/markup-compatibility/2006"</span></span></span></span></span></p>
<p><span><span> mc<span>:<span>Ignorable<span>="d"&gt;</span></span></span></span></span></p>
<p>&nbsp;</p>
<p><span><span>&lt;<span>Grid<span> Background<span>="{<span>ThemeResource<span> ApplicationPageBackgroundThemeBrush<span>}"&gt;</span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;<span>Button<span> Content<span>="Button"<span> HorizontalAlignment<span>="Left"<span> Margin<span>="252,140,0,0"<span> VerticalAlignment<span>="Top"<span> Click<span>="Button_Click"/&gt;</span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;<span>TextBlock<span> x<span>:<span>Name<span>="statusRun"<span> HorizontalAlignment<span>="Left"<span> Margin<span>="294,249,0,0"<span> TextWrapping<span>="Wrap"<span> Text<span>="TextBlock"<span> VerticalAlignment<span>="Top"<span> Height<span>="23"<span> RenderTransformOrigin<span>="0.5,0.5"<span> Width<span>="644"&gt;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;/<span>TextBlock<span>&gt;</span></span></span></span></p>
<p><span><span>&lt;<span>TextBlock<span> x<span>:<span>Name<span>="ResultRun"<span> HorizontalAlignment<span>="Left"<span> Margin<span>="280.991,346.281,0,0"<span> TextWrapping<span>="Wrap"<span> Text<span>="TextBlock"<span> VerticalAlignment<span>="Top"<span> RenderTransformOrigin<span>="0.5,0.5"<span> Height<span>="123.454"<span> UseLayoutRounding<span>="False"<span> Width<span>="308.332"<span> d<span>:<span>LayoutRounding<span>="Auto"&gt;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span><span>&lt;/<span>TextBlock<span>&gt;</span></span></span></span></p>
<p><span><span>&lt;/<span>Grid<span>&gt;</span></span></span></span></p>
<p><span>&lt;/<span>Page<span>&gt;</span></span></span></p>
<p>&nbsp;</p>
<p>MainPage.xaml.cs：</p>
<p><span>using<span> System; </span></span></p>
<p><span>using<span> System.Collections.Generic; </span></span></p>
<p><span>using<span> System.IO; </span></span></p>
<p><span>using<span> System.Linq; </span></span></p>
<p><span>using<span> System.Runtime.InteropServices.WindowsRuntime; </span></span></p>
<p><span>using<span> WeiboSDKForWinRT; </span></span></p>
<p><span>using<span> Windows.Foundation; </span></span></p>
<p><span>using<span> Windows.Foundation.Collections; </span></span></p>
<p><span>using<span> Windows.UI.Xaml; </span></span></p>
<p><span>using<span> Windows.UI.Xaml.Controls; </span></span></p>
<p><span>using<span> Windows.UI.Xaml.Controls.Primitives; </span></span></p>
<p><span>using<span> Windows.UI.Xaml.Data; </span></span></p>
<p><span>using<span> Windows.UI.Xaml.Input; </span></span></p>
<p><span>using<span> Windows.UI.Xaml.Media; </span></span></p>
<p><span>using<span> Windows.UI.Xaml.Navigation; </span></span></p>
<p>&nbsp;</p>
<p><span>// "空白页"项模板在 http://go.microsoft.com/fwlink/?LinkId=234238 上提供</span></p>
<p>&nbsp;</p>
<p><span>namespace<span> App2 </span></span></p>
<p><span>{ </span></p>
<p><span><span>///<span> <span>&lt;summary&gt;</span></span></span></span></p>
<p><span><span>///<span> 可独立使用或用于导航至 Frame 内部的空白页。</span></span></span></p>
<p><span><span>///<span> <span>&lt;/summary&gt;</span></span></span></span></p>
<p><span><span>public<span> <span>sealed<span> <span>partial<span> <span>class<span> <span>MainPage<span> : <span>Page</span></span></span></span></span></span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>public<span> MainPage() </span></span></span></p>
<p><span> { </span></p>
<p><span><span>this<span>.InitializeComponent(); </span></span></span></p>
<p><span> InitData(); </span></p>
<p><span> } </span></p>
<p>&nbsp;</p>
<p><span><span>private<span> <span>void<span> InitData() </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>// TODO:编译运行之前需要开放平台参数.</span></span></p>
<p><span><span>SdkData<span>.AppKey = <span>"132125341"<span>; </span></span></span></span></span></p>
<p><span><span>SdkData<span>.AppSecret = <span>"55cee081b74dabb1b53bf3b9a9bfa208"<span>; </span></span></span></span></span></p>
<p><span><span>SdkData<span>.RedirectUri = <span>"https://api.weibo.com/oauth2/default.html"<span>; </span></span></span></span></span></p>
<p>&nbsp;</p>
<p><span><span>// prepare the pic to be shared.</span></span></p>
<p><span> } </span></p>
<p><span><span>///<span> <span>&lt;summary&gt;</span></span></span></span></p>
<p><span><span>///<span> Invoked when this page is about to be displayed in a Frame.</span></span></span></p>
<p><span><span>///<span> <span>&lt;/summary&gt;</span></span></span></span></p>
<p><span><span>///<span> <span>&lt;param name="e"&gt;<span>Event data that describes how this page was reached. The Parameter</span></span></span></span></span></p>
<p><span><span>///<span> property is typically used to configure the page.<span>&lt;/param&gt;</span></span></span></span></p>
<p><span><span>protected<span> <span>override<span> <span>void<span> OnNavigatedTo(<span>NavigationEventArgs<span> e) </span></span></span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>var<span> oauthClient = <span>new<span> <span>ClientOAuth<span>(); </span></span></span></span></span></span></span></p>
<p><span><span>// 判断是否已经授权或者授权是否过期.</span></span></p>
<p><span><span>if<span> (oauthClient.IsAuthorized == <span>false<span>) </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span> oauthClient.LoginCallback += (isSucces, err, response) =&gt; </span></p>
<p><span> { </span></p>
<p><span><span>if<span> (isSucces) </span></span></span></p>
<p><span> { </span></p>
<p><span><span>// TODO: deal the OAuth result.</span></span></p>
<p><span><span>this<span>.statusRun.Text = <span>"Congratulations, Authorized successfully!"<span>; </span></span></span></span></span></p>
<p><span><span>this<span>.ResultRun.Text = <span>string<span>.Format(<span>"AccesssToken:{0}, ExpriesIn:{1}, Uid:{2}"<span>, </span></span></span></span></span></span></span></p>
<p><span> response.AccessToken, response.ExpriesIn, response.Uid); </span></p>
<p><span> } </span></p>
<p><span><span>else</span></span></p>
<p><span> { </span></p>
<p><span><span>// TODO: handle the err.</span></span></p>
<p><span><span>this<span>.statusRun.Text = err.errMessage; </span></span></span></p>
<p><span> } </span></p>
<p><span> }; </span></p>
<p><span> oauthClient.BeginOAuth();<span>//异步方法，如果需要在之后执行代码，请加到上面的LoginCallback中</span></span></p>
<p><span>} </span></p>
<p><span> } </span></p>
<p><span><span>private<span> <span>async<span> <span>void<span> Button_Click(<span>object<span> sender, <span>RoutedEventArgs<span> e) </span></span></span></span></span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>var<span> engine = <span>new<span> <span>SdkNetEngine<span>(); </span></span></span></span></span></span></span></p>
<p><span><span>ISdkCmdBase<span> cmdBase = <span>new<span> <span>CmdPostMessage<span>() </span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span> Status = <span>"test for post message without picture"</span></span></p>
<p><span> }; </span></p>
<p>&nbsp;</p>
<p><span><span>var<span> result = <span>await<span> engine.RequestCmd(<span>SdkRequestType<span>.POST_MESSAGE, cmdBase); </span></span></span></span></span></span></span></p>
<p><span><span>if<span> (result.errCode == <span>SdkErrCode<span>.SUCCESS) </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>this<span>.ResultRun.Text = result.content; </span></span></span></p>
<p><span><span>this<span>.statusRun.Text = <span>"Post a message without picture successed！"<span>; </span></span></span></span></span></p>
<p><span> } </span></p>
<p><span><span>else</span></span></p>
<p><span> { </span></p>
<p><span><span>// TODO: deal the error.</span></span></p>
<p><span><span>this<span>.statusRun.Text = <span>"Post a message without picture failed！"<span>; </span></span></span></span></span></p>
<p><span> } </span></p>
<p><span> } </span></p>
<p><span> } </span></p>
<p><span>} </span></p>
<p>中间这里注意填上我们之前得到的App key和App secret：</p>
<p><span><span>SdkData<span>.AppKey = <span>""<span>; </span></span></span></span></span></p>
<p><span><span>SdkData<span>.AppSecret = <span>""<span>; </span></span></span></span></span></p>
<p><span><span>SdkData<span>.RedirectUri = <span>""<span>; </span></span></span></span></span></p>
<p><span>RedirectUri</span> 也是个比较重要的参数，一般情况下填 <span>https://api.weibo.com/oauth2/default.html</span> ，填错了服务器会返回错误。参见<a href="http://open.weibo.com/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98">http://open.weibo.com/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98</a> 的faq：</p>
<p>&nbsp;</p>
<p><span><strong>Q：获取用户授权是出现 error ：redirect_uri_mismatch 怎么解决？ </strong></span></p>
<p><span>A：这是由于回调地址填写错误造成的，解决办法： </span></p>
<ul>
<li><span>站内应用：redirect_uri等于应用信息中的"站内应用地址"而非"应用实际地址"； </span></li>
<li><span>其他应用：redirect_uri需与http://open.weibo.com/apps/30871*****/info/advanced （30871*****替换成你应用的AppKey）应用高级信息中的"应用回调页"完全匹配或在绑定的域名下。 </span></li>
</ul>
<p><span>注意：修改应用回调页或绑定域名后需要约半小时左右时间生效。 </span></p>
<p>&nbsp;</p>
<p>接下来就可以运行啦：</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044423546025.png" alt="" /></p>
<p>输入微博账号，就可以给我们的Windows 8.1应用授权了:（这里有点要注意的，如果我们的应用没有提交并通过审核的话，只能用自己的账号给应用授权）</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044434645054.png" alt="" /></p>
<p>现在可以点击一下button：</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044444648881.png" alt="" /></p>
<p>哈哈，成功了。看看我们的微博，是不是多了一条：</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044458704652.png" alt="" /></p>
<p>这样子Windows 8.1应用的分享到微博就基本搞定啦，下面我们看看Windows Phone 8.1应用的。</p>
<h1>继续努力</h1>
<p>先尝试一下在Windows Phone 8.1应用中照Windows 8.1应用的方法调用微博SDK:</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044474954122.png" alt="" /></p>
<p>出错咯。原来 <span><span>WebAuthenticationBroker<span>.AuthenticateAsync</span></span> </span>这个方法在Windows Phone 8.1 上没有实现 -_-|||。赶紧查查资料，原来Windows Phone 8.1上要使用 <span><span>WebAuthenticationBroker<span>.AuthenticateAndContinue</span></span> </span>这个方法。参见 <a href="https://code.msdn.microsoft.com/windowsapps/Web-Authentication-d0485122">https://code.msdn.microsoft.com/windowsapps/Web-Authentication-d0485122</a>。</p>
<p>简单的说就是调用 <span><span>WebAuthenticationBroker<span>.AuthenticateAndContinue</span></span> </span>方法以后，会暂时跳出我们的Windows Phone 8.1 应用，在系统提供的一个专门的空间内得到<span>WebAuthenticationResult</span>，再通过我们的Windows Phone 8.1 应用的onActive事件将其传回应用，再根据<span>WebAuthenticationResult</span>的结果继续调用<span lang="EN-US">ContinueWebAuthentication</span>进行下一步的认证工作。</p>
<p>这样一来我们的SDK代码为了适应Universal 应用的Windows 应用和Windows Phone 应用就有了分歧，这正是条件编译派上用场的时候了。</p>
<p>我们将ClientOAuth.cs中的 <span>GetAuthorizeCode</span> 方法替换为如下：</p>
<p><span><span>///<span> <span>&lt;summary&gt;</span></span></span></span></p>
<p><span><span>///<span> 授权获取authorize_code.</span></span></span></p>
<p><span><span>///<span> <span>&lt;/summary&gt;</span></span></span></span></p>
<p><span><span>private<span> <span>async<span> <span>void<span> GetAuthorizeCode() </span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>string<span> oauthUrl = <span>string<span>.Format(<span>"{0}/oauth2/authorize?client_id={1}&amp;response_type=code&amp;redirect_uri={2}&amp;display=mobile"</span></span></span></span></span></span></p>
<p><span> , <span>Constants<span>.ServerUrl2_0, <span>SdkData<span>.AppKey, <span>SdkData<span>.RedirectUri); </span></span></span></span></span></span></span></p>
<p>&nbsp;</p>
<p><span><span>Uri<span> startUri = <span>new<span> <span>Uri<span>(oauthUrl, <span>UriKind<span>.Absolute); </span></span></span></span></span></span></span></span></span></p>
<p><span><span>Uri<span> endUri = <span>new<span> <span>Uri<span>(<span>SdkData<span>.RedirectUri, <span>UriKind<span>.Absolute); </span></span></span></span></span></span></span></span></span></span></span></p>
<p>&nbsp;</p>
<p><span><span>// 调出认证页面.</span></span></p>
<p><span>#if<span> WINDOWS_PHONE_APP </span></span></p>
<p><span> WebAuthenticationBroker.AuthenticateAndContinue(startUri, endUri);</span></p>
<p><span>#else</span></p>
<p><span><span>var<span> authenResult = <span>await<span> <span>WebAuthenticationBroker<span>.AuthenticateAsync(<span>WebAuthenticationOptions<span>.None, startUri, endUri); </span></span></span></span></span></span></span></span></span></p>
<p><span><span>switch<span> (authenResult.ResponseStatus) </span></span></span></p>
<p><span> { </span></p>
<p><span><span>case<span> <span>WebAuthenticationStatus<span>.Success: </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>string<span> authorize_code = <span>string<span>.Empty; </span></span></span></span></span></p>
<p><span><span>var<span> data = authenResult.ResponseData; </span></span></span></p>
<p><span> authorize_code = <span>SdkUility<span>.GetQueryParameter(data, <span>"code"<span>); </span></span></span></span></span></p>
<p><span><span>if<span> (<span>string<span>.IsNullOrEmpty(authorize_code) == <span>false<span>) </span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span> Authorize(authorize_code); </span></p>
<p><span> } </span></p>
<p><span> } </span></p>
<p><span><span>break<span>; </span></span></span></p>
<p><span><span>case<span> <span>WebAuthenticationStatus<span>.UserCancel: </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>SdkAuthError<span> err = <span>new<span> <span>SdkAuthError<span>(); </span></span></span></span></span></span></span></p>
<p><span> err.errCode = <span>SdkErrCode<span>.USER_CANCEL; </span></span></span></p>
<p><span> err.errMessage = <span>Constants<span>.<span>SdkMsg<span>.OAuthUserCanceled; </span></span></span></span></span></p>
<p><span><span>if<span> (<span>null<span> != LoginCallback) </span></span></span></span></span></p>
<p><span> LoginCallback(<span>false<span>, err, <span>null<span>); </span></span></span></span></span></p>
<p><span> } </span></p>
<p><span><span>break<span>; </span></span></span></p>
<p><span><span>case<span> <span>WebAuthenticationStatus<span>.ErrorHttp: </span></span></span></span></span></p>
<p><span><span>default<span>: </span></span></span></p>
<p><span> { </span></p>
<p><span><span>SdkAuthError<span> err = <span>new<span> <span>SdkAuthError<span>(); </span></span></span></span></span></span></span></p>
<p><span> err.errCode = <span>SdkErrCode<span>.NET_UNUSUAL; </span></span></span></p>
<p><span> err.errMessage = <span>Constants<span>.<span>SdkMsg<span>.NetException; </span></span></span></span></span></p>
<p><span><span>if<span> (<span>null<span> != LoginCallback) </span></span></span></span></span></p>
<p><span> LoginCallback(<span>false<span>, err, <span>null<span>); </span></span></span></span></span></p>
<p><span> } </span></p>
<p><span><span>break<span>; </span></span></span></p>
<p><span> } </span></p>
<p><span>#endif</span></p>
<p><span> } </span></p>
<p><span><span>public<span> <span>void<span> continueAuth(<span>WebAuthenticationResult<span> authenResult) </span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>switch<span> (authenResult.ResponseStatus) </span></span></span></p>
<p><span> { </span></p>
<p><span><span>case<span> <span>WebAuthenticationStatus<span>.Success: </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>string<span> authorize_code = <span>string<span>.Empty; </span></span></span></span></span></p>
<p><span><span>var<span> data = authenResult.ResponseData; </span></span></span></p>
<p>&nbsp;</p>
<p><span> authorize_code = <span>SdkUility<span>.GetQueryParameter(data, <span>"code"<span>); </span></span></span></span></span></p>
<p>&nbsp;</p>
<p><span><span>if<span> (<span>string<span>.IsNullOrEmpty(authorize_code) == <span>false<span>) </span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span> Authorize(authorize_code); </span></p>
<p><span> } </span></p>
<p><span> } </span></p>
<p><span><span>break<span>; </span></span></span></p>
<p><span><span>case<span> <span>WebAuthenticationStatus<span>.UserCancel: </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>SdkAuthError<span> err = <span>new<span> <span>SdkAuthError<span>(); </span></span></span></span></span></span></span></p>
<p><span> err.errCode = <span>SdkErrCode<span>.USER_CANCEL; </span></span></span></p>
<p><span> err.errMessage = <span>Constants<span>.<span>SdkMsg<span>.OAuthUserCanceled; </span></span></span></span></span></p>
<p>&nbsp;</p>
<p><span><span>if<span> (<span>null<span> != LoginCallback) </span></span></span></span></span></p>
<p><span> LoginCallback(<span>false<span>, err, <span>null<span>); </span></span></span></span></span></p>
<p><span> } </span></p>
<p><span><span>break<span>; </span></span></span></p>
<p><span><span>case<span> <span>WebAuthenticationStatus<span>.ErrorHttp: </span></span></span></span></span></p>
<p><span><span>default<span>: </span></span></span></p>
<p><span> { </span></p>
<p><span><span>SdkAuthError<span> err = <span>new<span> <span>SdkAuthError<span>(); </span></span></span></span></span></span></span></p>
<p><span> err.errCode = <span>SdkErrCode<span>.NET_UNUSUAL; </span></span></span></p>
<p><span> err.errMessage = <span>Constants<span>.<span>SdkMsg<span>.NetException; </span></span></span></span></span></p>
<p>&nbsp;</p>
<p><span><span>if<span> (<span>null<span> != LoginCallback) </span></span></span></span></span></p>
<p><span> LoginCallback(<span>false<span>, err, <span>null<span>); </span></span></span></span></span></p>
<p><span> } </span></p>
<p><span><span>break<span>; </span></span></span></p>
<p><span> } </span></p>
<p><span> } </span></p>
<p>现在我们的SDK的条件编译还没有生效，我们需要新建一个For Windows Phone的SDK：</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044488707135.png" alt="" /></p>
<p>把我们原有SDK的文件添加为链接：</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044503703877.png" alt="" /></p>
<p>注意CmdModel 下的文件，以及RestSharp.winmd 的引用也要加进来。还有我们的程序集名称因为新建项目的原因变化了，也得改回去。</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044512766733.png" alt="" /></p>
<p>改为</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044524955261.png" alt="" /></p>
<p>现在把Windows Phone 8.1应用的引用替换成WeiboSDKForWinRTPhone的。</p>
<p>接下来就可以果断地借鉴例子程序Web authentication broker sample 了，把它的ContinuationManager.cs拷贝过来。参见 <a href="https://code.msdn.microsoft.com/windowsapps/Web-Authentication-d0485122">https://code.msdn.microsoft.com/windowsapps/Web-Authentication-d0485122</a>。</p>
<p>让 <span>MainPage</span> 实现 <span>IWebAuthenticationContinuable</span> 的接口：</p>
<p><span><span>public<span> <span>sealed<span> <span>partial<span> <span>class<span> <span>MainPage<span> : <span>Page<span>, <span>IWebAuthenticationContinuable</span></span></span></span></span></span></span></span></span></span></span></span></span> </span></p>
<p>再给 <span>MainPage</span> 加上个实现 <span>IWebAuthenticationContinuable</span> 接口中 <span>ContinueWebAuthentication</span>进行下一步的方法：</p>
<p><span><span>public<span> <span>void<span> ContinueWebAuthentication (<span>WebAuthenticationBrokerContinuationEventArgs<span> ex) </span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>var<span> oauthClient = <span>new<span> <span>ClientOAuth<span>(); </span></span></span></span></span></span></span></p>
<p><span> oauthClient.LoginCallback += (isSucces, err, response) =&gt; </span></p>
<p><span> { </span></p>
<p><span><span>if<span> (isSucces) </span></span></span></p>
<p><span> { </span></p>
<p><span><span>// TODO: deal the OAuth result.</span></span></p>
<p><span><span>this<span>.statusRun.Text = <span>"Congratulations, Authorized successfully!"<span>; </span></span></span></span></span></p>
<p><span><span>this<span>.ResultRun.Text = <span>string<span>.Format(<span>"AccesssToken:{0}, ExpriesIn:{1}, Uid:{2}"<span>, </span></span></span></span></span></span></span></p>
<p><span> response.AccessToken, response.ExpriesIn, response.Uid); </span></p>
<p><span> } </span></p>
<p><span><span>else</span></span></p>
<p><span> { </span></p>
<p><span><span>// TODO: handle the err.</span></span></p>
<p><span><span>this<span>.statusRun.Text = <span>" Authorized Failed!"<span>; </span></span></span></span></span></p>
<p><span><span>this<span>.ResultRun.Text = err.errMessage; </span></span></span></p>
<p><span> } </span></p>
<p><span> }; </span></p>
<p><span> oauthClient.continueAuth(ex.WebAuthenticationResult); </span></p>
<p><span> } </span></p>
<p>最后处理一下App.xaml.cs中的 事件：</p>
<p><span>#if<span> WINDOWS_PHONE_APP </span></span></p>
<p><span><span>ContinuationManager<span> continuationManager; </span></span></span></p>
<p><span><span>///<span> <span>&lt;summary&gt;</span></span></span></span></p>
<p><span><span>///<span> Handle OnActivated event to deal with File Open/Save continuation activation kinds</span></span></span></p>
<p><span><span>///<span> <span>&lt;/summary&gt;</span></span></span></span></p>
<p><span><span>///<span> <span>&lt;param name="e"&gt;<span>Application activated event arguments, it can be casted to proper sub-type based on ActivationKind<span>&lt;/param&gt;</span></span></span></span></span></span></p>
<p><span><span>protected<span> <span>override<span> <span>void<span> OnActivated(<span>IActivatedEventArgs<span> e) </span></span></span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>base<span>.OnActivated(e); </span></span></span></p>
<p>&nbsp;</p>
<p><span> continuationManager = <span>new<span> <span>ContinuationManager<span>(); </span></span></span></span></span></p>
<p>&nbsp;</p>
<p><span><span>Frame<span> rootFrame = <span>Window<span>.Current.Content <span>as<span> <span>Frame<span>; </span></span></span></span></span></span></span></span></span></p>
<p>&nbsp;</p>
<p><span><span>// Do not repeat app initialization when the Window already has content,</span></span></p>
<p><span><span>// just ensure that the window is active</span></span></p>
<p><span><span>if<span> (rootFrame == <span>null<span>) </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>// Create a Frame to act as the navigation context and navigate to the first page</span></span></p>
<p><span> rootFrame = <span>new<span> <span>Frame<span>(); </span></span></span></span></span></p>
<p><span><span>// Place the frame in the current Window</span></span></p>
<p><span><span>Window<span>.Current.Content = rootFrame; </span></span></span></p>
<p><span> } </span></p>
<p>&nbsp;</p>
<p><span><span>if<span>(rootFrame.Content == <span>null<span>) </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span> rootFrame.Navigate(<span>typeof<span>(<span>MainPage<span>)); </span></span></span></span></span></p>
<p><span> } </span></p>
<p>&nbsp;</p>
<p><span><span>var<span> continuationEventArgs = e <span>as<span> <span>IContinuationActivatedEventArgs<span>; </span></span></span></span></span></span></span></p>
<p><span><span>if<span> (continuationEventArgs != <span>null<span>) </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>// Call ContinuationManager to handle continuation activation</span></span></p>
<p><span> continuationManager.Continue(continuationEventArgs, rootFrame); </span></p>
<p><span> } </span></p>
<p>&nbsp;</p>
<p><span><span>Window<span>.Current.Activate(); </span></span></span></p>
<p><span> } </span></p>
<p><span>#endif</span></p>
<p>赶紧运行看看：</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044540426988.png" alt="" /></p>
<p>好吧，又出错了。看起来是跳转到应用外失败了，是不是我们太早跳转了呢？把<span>OnNavigatedTo</span>中的授权的过程放到 Page 的 <span>Loaded </span>事件里试试吧：</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044562619344.png" alt="" /></p>
<p>仍然不行，那只有采用延迟的办法了：</p>
<p><span>private<span> <span>async<span> <span>void<span> Page_Loaded(<span>object<span> sender, <span>RoutedEventArgs<span> e) </span></span></span></span></span></span></span></span></span></span></p>
<p><span> { </span></p>
<p><span><span>await<span> <span>Task<span>.Delay(1000); </span></span></span></span></span></p>
<p><span><span>var<span> oauthClient = <span>new<span> <span>ClientOAuth<span>(); </span></span></span></span></span></span></span></p>
<p><span><span>// 判断是否已经授权或者授权是否过期.</span></span></p>
<p><span><span>if<span> (oauthClient.IsAuthorized == <span>false<span>) </span></span></span></span></span></p>
<p><span> { </span></p>
<p><span> oauthClient.LoginCallback += (isSucces, err, response) =&gt; </span></p>
<p><span> { </span></p>
<p><span><span>if<span> (isSucces) </span></span></span></p>
<p><span> { </span></p>
<p><span><span>// TODO: deal the OAuth result.</span></span></p>
<p><span><span>this<span>.statusRun.Text = <span>"Congratulations, Authorized successfully!"<span>; </span></span></span></span></span></p>
<p><span><span>this<span>.ResultRun.Text = <span>string<span>.Format(<span>"AccesssToken:{0}, ExpriesIn:{1}, Uid:{2}"<span>, </span></span></span></span></span></span></span></p>
<p><span> response.AccessToken, response.ExpriesIn, response.Uid); </span></p>
<p><span> } </span></p>
<p><span><span>else</span></span></p>
<p><span> { </span></p>
<p><span><span>// TODO: handle the err.</span></span></p>
<p><span><span>this<span>.statusRun.Text = err.errMessage; </span></span></span></p>
<p><span> } </span></p>
<p><span> }; </span></p>
<p><span> oauthClient.BeginOAuth(); </span></p>
<p><span> } </span></p>
<p><span> } </span></p>
<p>再看看行不行？</p>
<p><img src="http://images.cnitblog.com/blog/700062/201501/132044579646557.png" alt="" /> <img src="http://images.cnitblog.com/blog/700062/201501/132044589175399.png" alt="" /> <img src="http://images.cnitblog.com/blog/700062/201501/132045000734712.png" alt="" /></p>
<p>好了，终于大功告成。</p>
<h1>结尾</h1>
<p>我们这个修改过的微博SDK可以在<a href="https://code.msdn.microsoft.com/windowsapps/Share-To-Weibo-in-c99da5fa">https://code.msdn.microsoft.com/windowsapps/Share-To-Weibo-in-c99da5fa</a> 找到。其中难免会有一些Bug，欢迎大家指正。</p>
<p><span><span><strong>分享代码，改变世界！</strong></span></span></p>
<p><span>Windows Phone Store App link: </span></p>
<p><a href="http://www.windowsphone.com/zh-cn/store/app/%E5%8D%9A%E5%AE%A2%E5%9B%AD-uap/500f08f0-5be8-4723-aff9-a397beee52fc"><span><span>http://www.windowsphone.com/zh-cn/store/app/</span><span>博客园</span><span>-uap/500f08f0-5be8-4723-aff9-a397beee52fc</span></span></a></p>
<p><span>Windows Store App link: </span></p>
<p><a href="http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059"><span>http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059</span></a></p>
<p><span>GitHub open source link: </span></p>
<p><a href="https://github.com/MS-UAP/cnblogs-UAP"><span>https://github.com/MS-UAP/cnblogs-UAP</span></a></p>
<p><span>MSDN Sample Code: </span></p>
<p><a href="https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab"><span>https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab</span></a></p>]]></content:encoded>
    </item>
    <item>
      <title>博客园客户端UAP开发随笔 -- 让你自己和你的App有国际范儿</title>
      <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/uap-app-3</link>
      <pubDate>Sun, 01 Feb 2015 07:24:06 GMT</pubDate>
      <dc:creator><![CDATA[Windows-China]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows_china_blog/2015/02/01/uap-app-3/</guid>
      <description><![CDATA[大家是不是发现，在商店中看到的高大上的应用都有着多语言支持，可以根据操作系统的语言自动适配；或者可以通过用户的选择，显示对应的语言界面，确实很高大上呢。不过这个可不是什么难事，通过简单的几个步骤，让你...]]></description>
      <content:encoded><![CDATA[<p>大家是不是发现，在商店中看到的高大上的应用都有着多语言支持，可以根据操作系统的语言自动适配；或者可以通过用户的选择，显示对应的语言界面，确实很高大上呢。不过这个可不是什么难事，通过简单的几个步骤，让你的应用也高大上起来，支持多语言。这样在你以后的简历里，也可以写上：面向国际市场开发过多语言应用。听上去相当有底气！</p>
<p>&nbsp;</p>
<h4>0. 准备工作</h4>
<p>在建立多语言支持前，首先要看一下 Manifest 文件中的默认语言选项，将它设置为你希望的默认显示语言。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131053514642906.png"><img title="0" src="http://images.cnitblog.com/blog/700062/201501/131053522141277.png" alt="0" width="731" height="167" border="0" /></a></p>
<p>&nbsp;</p>
<p>接下来建立存放语言字符串的文件夹。如果是Universal App，就如下图所示，在 Shared 文件夹下建立 Strings 子文件夹，并在其中根据自己 App 希望支持的语言，再建立子文件夹，子文件夹的名称要和语言的编码一致。关于具体语言的编码，可以查询 Language Codes 页面：</p>
<p><a title="http://msdn.microsoft.com/en-us/library/ms533052%28v=vs.85%29.aspx" href="http://msdn.microsoft.com/en-us/library/ms533052%28v=vs.85%29.aspx">http://msdn.microsoft.com/en-us/library/ms533052%28v=vs.85%29.aspx</a></p>
<p>如果不是 Universal App，那么 Strings 文件夹应该放在项目的根目录下。</p>
<p>建立好文件夹以后，在每个文件夹中添加 "Resources File (.resw)"。微软推荐使用默认文件名，以便在项目中进行调用。如果有特殊命名需求，请参考 How to load string resources (XAML) 页面：</p>
<p><a title="http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh965323.aspx" href="http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh965323.aspx">http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh965323.aspx</a></p>
<p>&nbsp;</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131053530584918.png"><img title="1" src="http://images.cnitblog.com/blog/700062/201501/131053540118461.png" alt="1" width="272" height="258" border="0" /></a></p>
<p>这些做完以后，多语言支持的框架就算是搭起来了，剩下的就是往里填写内容了。</p>
<p>&nbsp;</p>
<h4>1. 填写字符串</h4>
<p>以 en-US 举例，我们打开 en-US 的 Resources.resw 文件，会发现其中分为三列，分别是 Name，Value 和 Comment。顾名思义，分别是字符串引用的名称，字符串的内容和字符串的备注或评论。那么我们就开始根据自己的需求填写字符串。其中 Name 和 Value 较为重要，必须填写，Comment 主要是增强可读性，不是必填项。</p>
<p>如果是需要对界面，也就是 XAML 语言定义的部分进行多语言支持，那么 Name 的部分就要像 XAML 语言定义一样，针对控件的每个单元进行定义。例如：</p>
<p>需要对文本框的内容，也就是 Text 进行多语言支持，那么 Name 部分就必须是 NameofTextbox.Text 的格式。比如下图中，我们要对&ldquo;精华栏标题&rdquo;进行多语言支持，那么我们首先为精华栏标题命名为 BestTitle，并且针对 BestTitle.Text 这一 Name 填写内容 Best。那么这一工作就做完了。</p>
<p>对于Button控件来说，其文本部分叫做Label（为什么就不能统一叫Text呢？好奇怪啊），所以要给AppButton_Zoom这个button填写一个AppButton_Zoom.Label项。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131053547928589.png"><img title="2" src="http://images.cnitblog.com/blog/700062/201501/131053554485988.png" alt="2" width="560" height="102" border="0" /></a></p>
<p>&nbsp;</p>
<h4>2. 界面引用字符串</h4>
<p>有了这个命名，我们如何在界面中进行调用呢？</p>
<p>很简单，通过 Uid 实现。</p>
<p>找到 XAML 中对应的部分，添加 <span>x:Uid</span><span>="BestTitle" <span>这一属性，这样系统就会自动在多语言支持中找到对应的内容，并将 Text 的内容对应赋予该 TextBlock 的 Text 属性。这样，我们就无需在 XAML 文件中将现实的内容硬编码进去，只需要修改对应的资源文件就可以，是不是很方便呢。</span></span></p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>&lt;</span><span>Button </span><span>Style</span><span>="</span><span>{StaticResource Win8TopAppBarButton}</span><span>"</span><span> Tag</span><span>="CNBlogs.Pages.BestPostsPage"</span><span> Click</span><span>="NavButton_Click"</span><span> Padding</span><span>="30"</span><span>&gt;</span>
                <span>&lt;</span><span>Button.Content</span><span>&gt;</span>
                    <span>&lt;</span><span>TextBlock</span><span>&gt;</span>
                    <span>&lt;</span><span>Run </span><span>Text</span><span>=""</span><span> FontFamily</span><span>="Segoe UI Symbol"</span><span>/&gt;</span>
                    <span>&lt;</span><span>Run </span><span>x:Uid</span><span>="BestTitle"</span><span> Text</span><span>=""</span><span>/&gt;</span>
                    <span>&lt;/</span><span>TextBlock</span><span>&gt;</span>
                <span>&lt;/</span><span>Button.Content</span><span>&gt;</span>
            <span>&lt;/</span><span>Button</span><span>&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>运行一下看看效果，如果系统语言默认是英文的话，那么显示的内容就已经如我们所愿，变成英文的了。如果不是英文也没有关系，我们可以通过切换系统语言，或者在程序中设置应用语言来实现这一点，设置语言的方法，会在后文讲述。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131053563237087.png"><img title="5" src="http://images.cnitblog.com/blog/700062/201501/131053571364674.png" alt="5" width="1165" height="121" border="0" /></a></p>
<p>&nbsp;</p>
<p>对应的，我们也要添加上中文的内容，这样才能保证两种语言的对应性。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131053578233829.png"><img title="4" src="http://images.cnitblog.com/blog/700062/201501/131053584488471.png" alt="4" width="490" height="88" border="0" /></a></p>
<p>眼尖的读者一定发现了，不光 Text，连 FontSize 也可以定义么？对的，对于 Width，字体等简单属性，我们都可以根据不同语言的特性，对控件进行根据语言分类的设定，这样才可以使界面更加符合不同语言的特性及使用习惯。</p>
<p>&nbsp;</p>
<h4>3. 后台代码引用字符串</h4>
<p>虽然前台设计主要由 XAML 实现，但是还是会有部分漏网的字符，是在后台的 C# 代码中实现的。对于这些部分的显示，如何调用资源文件中的内容呢？答案也是非常简单的。</p>
<p>首先，在资源文件中定义要调用的字符串。值得注意的是，这里不能像定义 XAML 中使用的字符串一样，使用类似 NameofTextbox.Text 的格式，而是要使用类似于变量命名的命名规则，不能再用&rdquo;.&rdquo;等分隔符隔开。否则系统调用会失败。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131053591511857.png"><img title="3" src="http://images.cnitblog.com/blog/700062/201501/131053597929728.png" alt="3" width="547" height="100" border="0" /></a></p>
<p>&nbsp;</p>
<p>填写完成以后，我们打开后台 C# 代码，首先添加这一句：</p>
<div class="cnblogs_code">
<pre>Windows.ApplicationModel.Resources.ResourceLoader loader = <span>new</span> Windows.ApplicationModel.Resources.ResourceLoader();</pre>
</div>
<p>这样就定义了一个 loader，由他负责从资源文件中找寻对应的语句。</p>
<p>当我们需要字符串的时候，就将字符串的部分替换为 loader.GetString("STRING_NAME")即可，其中 STRING_NAME对应的就是在资源文件中定义的 Name。例如，我们需要调用 "CommentTextblockText_Status1" 和 "CommentTextblockText_Status2" 字符串，那么我们就使用语句：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre>CommentButton.Content = isCommentTemperarorilyShown ? loader.GetString(<span>"</span><span>CommentTextblockText_Status2</span><span>"</span>) : loader.GetString(<span>"</span><span>CommentTextblockText_Status1</span><span>"</span>);</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>就可以了。</p>
<p>&nbsp;</p>
<h4>4. 设置程序语言</h4>
<p>如果在 Windows Store App 中希望无视系统语言，强制设置程序语言，也是可以的。我们只需要在页面中添加一句：</p>
<div class="cnblogs_code">
<pre>Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = <span>"</span><span>zh-CN</span><span>"</span>;</pre>
</div>
<p>就可以了。不过需要注意，这一句代码执行完了以后，只会对之后打开的页面生效，之前加载的页面的语言并不会发生变化。若希望全局生效，最好的办法是重新启动一下应用程序。</p>
<p>&nbsp;</p>
<p>一个更好的办法是建立一个如图的下拉菜单：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131054005116342.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/131054013392456.png" alt="image" width="244" height="128" border="0" /></a></p>
<p>这样可以方便用户自己选择界面语言。</p>
<p>遗憾的是，在 Windows Phone 中并没有这么好的全局设定方案，界面语言只能跟随系统显示语言。如果想要重设界面语言，就只能使用另外的黑科技了。</p>
<p>&nbsp;</p>
<h4>5. 其他</h4>
<p>在中文和英文资源文件之间来回切换是个很痛苦的事情，尤其是界面字符串数目比较多的时候。笔者推荐一个插件，可以比较方便的进行语言之间的比较和翻译。</p>
<p>在 Visual Studio 中选择 TOOLS &ndash; Extensions and Updates，搜索 ResXManager 这一插件，安装重启以后，在 TOOLS 菜单中就可以打开它，界面如下图所示：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131054022455312.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/131054033866097.png" alt="image" width="551" height="410" border="0" /></a></p>
<p>&nbsp;</p>
<p>这样的对照界面比原来单一语言界面方便多了，如果有某种语言条目的空缺，他还会标红提醒，实在是多语言及本地化支持的利器。</p>
<p>&nbsp;</p>
<h4>小结</h4>
<p>本地化及多语言支持的技术并无难点，困难之处往往在于多语言特点的兼顾，翻译的准确性及维护上。本文只是万里长征的第一步，后面的路还要开发者们一个字符串一个字符串去铺成&hellip;&hellip;</p>
<p>&nbsp;</p>
<p><strong>分享代码，改变世界！</strong></p>
<p>Windows Phone Store App link:</p>
<p><a href="http://www.windowsphone.com/zh-cn/store/app/%E5%8D%9A%E5%AE%A2%E5%9B%AD-uap/500f08f0-5be8-4723-aff9-a397beee52fc">http://www.windowsphone.com/zh-cn/store/app/博客园-uap/500f08f0-5be8-4723-aff9-a397beee52fc</a></p>
<p>Windows Store App link:</p>
<p><a href="http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059">http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059</a></p>
<p>GitHub open source link:</p>
<p><a href="https://github.com/MS-UAP/cnblogs-UAP">https://github.com/MS-UAP/cnblogs-UAP</a></p>
<p>MSDN Sample Code:</p>
<p><a href="https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab">https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab</a></p>]]></content:encoded>
    </item>
    <item>
      <title>博客园客户端UAP开发随笔 -- App UI设计的三大纪律八项注意</title>
      <link>https://docs.microsoft.com/archive/blogs/windows_china_blog/uap-app-ui</link>
      <pubDate>Sun, 01 Feb 2015 07:23:13 GMT</pubDate>
      <dc:creator><![CDATA[Windows-China]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows_china_blog/2015/02/01/uap-app-ui/</guid>
      <description><![CDATA[前言
每一个页面都是这个App的门面，尤其是主页面，看上去干净整洁清爽宜人容易操作，那么你的App就成功了一半。这也反映出了你这个开发团队的基本审美素质和设计理念。如果你不是一个团队，而是一个个人开...]]></description>
      <content:encoded><![CDATA[<h2>前言</h2>
<p>每一个页面都是这个App的门面，尤其是主页面，看上去干净整洁清爽宜人容易操作，那么你的App就成功了一半。这也反映出了你这个开发团队的基本审美素质和设计理念。如果你不是一个团队，而是一个个人开发者，建议你好好读读以下心得体会，相信会帮助你做出好看而实用的App。用一堆拥有丑陋UI的App充斥Window Store，不是我们高大上的程序员所为，被其他手机开发平台的开发者们耻笑。</p>
<p>三大纪律：</p>
<p>1）不乱用颜色。一个页面内不要超过3种颜色</p>
<p>2）不乱用大图片当背景。你是想让用户看你的背景图片呢，还是看你的内容？</p>
<p>3）不乱填充内容。页面元素如果太满，给读者压抑感，无所适从。</p>
<p>八项注意：我们从字号，字体，颜色，导航栏，标题栏，内容区，菜单栏，间距与对齐等八个方面介绍了我们开发App的心得体会。</p>
<h2>字体</h2>
<p>推荐一律使用Segoe WP字体。在特殊的显示符号的地方，可以使用其它字体，如：Segoe UI Symbol。有些字体在设计时可以呈现，但是在deploy到手机上后毫无效果，原因是手机上没有你指定的字体。</p>
<h2>文字大小</h2>
<p>在WP的设置中，有一项文字大小设置：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121718390423308.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/121718401982621.png" alt="image" width="357" height="345" border="0" /></a></p>
<p>缺省时，文字最小，slider处于最左侧的位置。但是看邮件时太费劲啦，尤其是英文邮件，再加上喜欢坐城铁，基本上看几分钟我的K金狗眼就瞎了。所以我一般会把这个文字调到上图的大小。这时，WP内置的&ldquo;节电模式&rdquo;应用会这样：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121718413868391.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/121718426671434.png" alt="image" width="359" height="227" border="0" /></a></p>
<p>看那个&ldquo;节电模式&rdquo;四个字，比上面的&ldquo;设置&rdquo;两个字大一些吧，这个页面的其它所有文字也都比正常要大。我不知道这是by design呢，还是bug呢？反正其它的内置App不这样。 这一点会被大多数人遗忘，以至于一些很有名头的App，或者是上述WP自带的App本身都掉入此坑。这个如何避免呢？</p>
<p>在Page中加入这么一句话即可：</p>
<div class="cnblogs_code">
<pre><span>&lt;</span><span>Page </span><span>...... IsTextScaleFactorEabbled</span><span>="False"</span><span>&gt;</span></pre>
</div>
<p>这个定义是告诉WP：我的App忽略那个文字大小调整的影响。否则，你所有的文字相关的控件，都会变得巨丑无比，整个UI就毁了。</p>
<p>在Windows 8.1中没有这个设置，因此以上代码只能在Windows Phone Project中编译通过，因此这句话要写在Page中，而不能写在任何Shared Project的XAML中。</p>
<h2>主题色</h2>
<p>看到应用商店中的很多简单的App都使用了黑色作为主题色，无非是以下几个原因之一：</p>
<p>1）是一个简单的App，没有designer，没仔细设计过，干脆用黑色的</p>
<p>2）看到Windows Phone自带的App都是黑色，以为黑色就是官方指定的</p>
<p>3）黑色上显示白色的字，天经地义，不用做特殊设置</p>
<p>4）黑色是万能搭配色</p>
<p>以上这些都可以理解。但是一个纯正的第三方App绝不可以用黑色，一个是避免和WP自带的App混淆，一个是避免别人以为你偷懒用个黑色在这里充数。反正我个人没见过哪个口碑好的App是用黑色的。如果是自己用黑色做个App随便玩玩也就罢了，一旦上传到应用商店去，就只能说明又多了一个屌丝了，注意素质。</p>
<p>最简单的避免成为屌丝的方法很简单:</p>
<p>1）定义一个主题色（比如就用红色怎么啦，和IT之家似的），用于标题栏，可点击文字（带link）等场合</p>
<p>2）定义一个浅主题色（可选），用于菜单栏</p>
<p>3）用一个白色或浅灰色（假设主题色是深色）做大字体颜色（比如标题栏之内的文字）</p>
<p>4）用一个深灰色做大量文本的颜色（在白色背景下）</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131501239013502.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/131501264177300.png" alt="image" width="486" height="544" border="0" /></a></p>
<p>反正一共就4种颜色就够了，足以展示程序员的素质了。如果要精益求精，还需要更多一些的颜色，比如作者/发布时间的颜色，摘要的颜色，以及下方attribution的颜色（推荐/阅读/评论）。</p>
<p>主题色也应该在Page中这样定义：</p>
<div class="cnblogs_code">
<pre><span>&lt;</span><span>Page </span><span>...... RequestedTheme</span><span>="Light"</span><span> ......</span><span>&gt;</span></pre>
</div>
<p>这样你就省去了在code中写this.RequestedTheme = Light的麻烦，这是为了做日间模式和夜间模式的切换。</p>
<h2>状态栏</h2>
<p>状态栏，就是Windows Phone顶部的那个大概有25像素高的横条，平时显示网络状态，时间，电池状态等等。下图中黑色的部分就是状态栏。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/151134252144465.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/151134263705152.png" alt="image" width="547" height="119" border="0" /></a></p>
<p>原则：不要轻易决定隐藏状态栏，除非你是在做一个游戏。因为在大多数情况下，用户是希望能随时看到自己的WIFI网络状态、电池状态和当前时间的。节省25个像素而用于显示更多的应用内容的想法有点儿小气。</p>
<p>如何隐藏状态栏呢？在Silverlight中，是在Page的XAML设置一个属性（忘记是什么了），但是在Win RT SDK中，目前知道的必须用code做这件事：</p>
<div class="cnblogs_code">
<pre><span>await</span> Windows.UI.ViewManagement.StatusBar.GetForCurrentView().HideAsync();</pre>
</div>
<p>一旦在一个页面内调用了上述语句，那么在该App本次的以后使用过程中，顶部状态条都不会再显示了，除非你再调用ShowAsync()来显示它。</p>
<p>如何让状态栏和你的App的色调搭配和谐呢？你应该在Page里这样定义：</p>
<div class="cnblogs_code">
<pre><span>&lt;</span><span>Page </span><span>...... Background</span><span>="</span><span>{ThemeResource MyAppThemeColor}</span><span>"</span><span>&gt;</span></pre>
</div>
<p>这里假设你在StyleDictionary.xaml里设置了MyAppThemeColor的值。这样的话，这个页面的状态栏也会被刷成应用主题色，一般来说会和你的这个页面的顶部标题栏颜色一致，看上去比较顺眼的啦。</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/151134274336811.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/151134282141982.png" alt="image" width="549" height="120" border="0" /></a></p>
<p>但是这导致了一个问题：如果你的App有下方的命令栏（Command Bar）而且是淡蓝色背景，在页面切换动画时，能看到命令栏后面的深蓝色背景一闪而过，不太协调，原因是上面那个设置把整个页面都设置成了深蓝色，包括底部命令栏的后背景。这个虽然不是大问题，但作为程序员的我们一定要知道当有人Challenge这件事时，我们如何解决。</p>
<p>为了避免这个问题，我们可以只设置状态栏的背景色，而不设置页面背景，用code做：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre>Windows.UI.ViewManagement.StatusBar statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView();
statusBar.ForegroundColor = CNBlogsThemeColor;</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>但是别忘了去掉上面Page里的Background设置。</p>
<h2>标题栏</h2>
<p>博客园的标题栏设计如下：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121718436209275.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/121718446981846.png" alt="image" width="564" height="223" border="0" /></a></p>
<p>特简单。注意了吗，页面上没有&ldquo;博客园&rdquo;或&ldquo;CNBlogs&rdquo;字样。同学们一般习惯把&ldquo;博客园&rdquo;字样作为Pivot的Title放在本页的最上方，但是仔细想想那有什么意义呢？人家用你这个App的人，知道你这是博客园，为何一定要占据宝贵的空间来展示自己的自恋情结呢？</p>
<p>另一个页的标题栏设计如下：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121718458867617.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/121718467767243.png" alt="image" width="575" height="221" border="0" /></a></p>
<p>高度/颜色/字体等和其他页完全一致，切换页面时无跳跃感。和Android的App的最大区别是：由于Windows Phone有特定的底部Command Bar来放置命令按钮和菜单，所以顶部的标题栏一定不要再放任何可以操作的东西啦，而只能用于信息展示。比如上图，告诉你当前页面显示了热门博客的前20条。那个&ldquo;2日内阅读排行&rdquo;是一个辅助手段，告诉你当前页的具体展示类别。这么多字在标题栏里放不下，所以放在这里会随着ListView的滚动而上移从而隐藏。</p>
<h2>内容区</h2>
<p>内容区不要太杂，最好只放一类东西，除非你是在做那个叫做&ldquo;找你妹&rdquo;的游戏。如果只有一类内容，那么我们一般用ListView就搞定了。如果有两类以上的内容要显示，最好放在两个页面内；如果非要在一个页面内，就用这种方式：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121747107298876.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/121747116049975.png" alt="image" width="566" height="491" border="0" /></a></p>
<p>用一个蓝条分开了不同种类的内容，而且每类内容可以单独展开或收起。这里你还可以选择用ListView的分组方式展示数据，第一个分组标题是&ldquo;分类&rdquo;，第二个分组标题是&ldquo;博主&rdquo;等等，但是不是最佳选择，因为两类内容的模板不一致，需要写很多code来实现。</p>
<h2>菜单栏</h2>
<p>菜单栏也有几个小技巧可以分享，看下图：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/121747122924833.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/121747131834460.png" alt="image" width="567" height="227" border="0" /></a></p>
<p>1）我们使用了主题色来显示菜单项和按钮(Foreground = CNBlogsThemeColor)</p>
<p>2）用淡雅主题色来作为菜单背景（在Flyout Menu的弹出式菜单中也是如此）(Background = CNBLogsThemeLightColor)</p>
<p>3）使用标准ICON做按钮，如果不够用，在Segoe UI Symbol中基本上可以找到你要的东西，就不要麻烦designer再去画了。如果非要自定义的话，就画一个25x25 png，放在40x40的png内。你可以试试其它尺寸，很难看的。</p>
<p>4）重要操作放在上面的按钮中（最多4个），不重要的放在菜单中，这个你自己定吧。</p>
<p>这个菜单栏的样式定义如下：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
<pre><span>&lt;</span><span>Style </span><span>TargetType</span><span>="CommandBar"</span><span>&gt;</span>
    <span>&lt;</span><span>Setter </span><span>Property</span><span>="Background"</span><span> Value</span><span>="</span><span>{ThemeResource CNBlogsThemeLightColor}</span><span>"</span><span>/&gt;</span>
    <span>&lt;</span><span>Setter </span><span>Property</span><span>="Foreground"</span><span> Value</span><span>="</span><span>{ThemeResource CNBlogsThemeColor}</span><span>"</span><span>/&gt;</span>
<span>&lt;/</span><span>Style</span><span>&gt;</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></span></div>
</div>
<p>这个定义放在了StyleDictionary.xaml中，这样所有页面的菜单项都会是同一个样式了。</p>
<h2>间距与对齐</h2>
<p>间距是屌丝程序员经常忽视的问题，但其实它是隐藏最深的能影响用户体验的关键元素之一。我们举例说明吧，看下图：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131501302921884.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/131501329011953.png" alt="image" width="438" height="728" border="0" /></a></p>
<p>每个红色的圆形都表示一个间距（人家Designer给的设计叫做Redline，用红色直线表示），对称位置的两个间距要保持一致，整个界面才能好看。比如1和2，3和4，5和6，7和8，都要保证数值一样。</p>
<p>从对齐上看，标题区的WinRT/Metro的左边距，ListViewHeader的左边距，以及每篇博客的左边距都是一致的。</p>
<p>再比如设置页面，也是丝毫不能马虎，看那些红色的线条的长度，必须保证一样长：</p>
<p><a href="http://images.cnitblog.com/blog/700062/201501/131501345736408.png"><img title="image" src="http://images.cnitblog.com/blog/700062/201501/131501360421394.png" alt="image" width="443" height="236" border="0" /></a></p>
<h2>小结</h2>
<p>Windows 8.1上的App对审美的要求其实更高，因为它的显示面积大，不像Windows Phone上可以随便用点儿什么手段就能填满屏幕。我们会有专门一篇Blog介绍博客园 UAP的Windows 8.1版本的界面设计。</p>
<p>作为同样屌丝的我，实在是写不出什么更好的东西，只是在和designer接触过程中学了些皮毛，让大家见笑了。总之几句话概括一下：注意颜色，注意字体，注意间距，注意内容。让我想起了解放军的三大纪律八项注意，违纪者扣6分罚200！把自己的脸整容成雷锋也不行！呵呵，又扯远了&hellip;</p>
<p>&nbsp;</p>
<h3>分享代码，改变世界！</h3>
<p>Windows Phone Store App link:</p>
<p><a href="http://www.windowsphone.com/zh-cn/store/app/%E5%8D%9A%E5%AE%A2%E5%9B%AD-uap/500f08f0-5be8-4723-aff9-a397beee52fc">http://www.windowsphone.com/zh-cn/store/app/博客园-uap/500f08f0-5be8-4723-aff9-a397beee52fc</a></p>
<p>Windows Store App link:</p>
<p><a href="http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059">http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059</a></p>
<p>GitHub open source link:</p>
<p><a href="https://github.com/MS-UAP/cnblogs-UAP">https://github.com/MS-UAP/cnblogs-UAP</a></p>
<p>MSDN Sample Code:</p>
<p><a href="https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab">https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab</a></p>]]></content:encoded>
    </item>
  </channel>
</rss>