<?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>MSDN Forums Support - Windows Store apps development</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/windows8devsupport/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/feed.xml</link>
    <description>Epicenter of creative ideas, common tips, best practice for Windows Store app</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:27:33 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>如何在Windows Store和Windows Phone应用之间传送文件</title>
      <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/windows-storewindows-phone</link>
      <pubDate>Tue, 28 Oct 2014 22:42:00 GMT</pubDate>
      <dc:creator><![CDATA[MingXu-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows8devsupport/2014/10/28/windows-storewindows-phone/</guid>
      <description><![CDATA[首先要知道的事：它是如何工作的
&nbsp;
如果我们曾有一些应用同时运行于Windows Phone和Win 8...]]></description>
      <content:encoded><![CDATA[<p>首先要知道的事：它是如何工作的<strong></strong></p>
<p><strong>&nbsp;</strong></p>
<p>如果我们曾有一些应用同时运行于Windows Phone和Win 8 Store中，我们可能会考虑使用一些版本之间的数据同步的机制。然而，由于两种程序之间无法直接访问对方的数据，这就要求它们之间能有某种方式可以进行文件传输。可行的方案的好几种，最流行的一种是使用Web Server（放置在某个地方作为中间介质）。然而，这种方式也有一些弊端，假如用户的万维网访问因为各种环境因素而被限制了，你的应用可能就没办法正常地和用户进行交互了。虽然在一般情况下的万维网访问是不会受到限制的，但实际情况并不总是这样乐观。另外，这种方式可能会产生一定金额的维护费用，你需要从你应用的收益中拿出一部分来支付这些费用。</p>
<p>&nbsp;</p>
<p>通常情况下，用户都会拥有自己的网络连接，如：局域网，Ad-Hoc网络。很多时候，甚至连用户自己都没有意识到这一点。例如，假设用户有一个路由或者接入点，然后有一些设备（不管无线有线）连接在路由或者接入点上，这些处于当前网络中的设备形成了某种意义上的 &ldquo;互联网&rdquo;。此时，不管有没有万维网访问，与互联网相关的网络协议都能正常工作。<strong></strong></p>
<p><strong>&nbsp;</strong></p>
<p>所以，我们可以跳过中间服务器，通过TCP协议实现同一网络实现设备间的直接通信。<strong></strong></p>
<p><strong>&nbsp;</strong></p>
<p>TCP协议是互联网的基石。几乎所有访问互联网的程序都会使用TCP协议从远端服务器获取数据（大多数情况下，网络请求要经过几个服务器的路由，这里暂时不做讨论）。TCP 协议包含一个服务器（监听者）和一个客户端，这两个实体通过&ldquo;请求&rdquo;的阶段变化进行数据交互。&ldquo;请求&rdquo;必须进行初始化，客户端根据服务器的IP地址和指定端口打开一个连接即可完成。而服务器不能简单的去连接客户端。TCP协议的主要好处是任一方发送的数据包都能确保被另一方接收到。如果在传送过程中丢失了某个数据包，发送方就会重新发送丢失的数据包，直到接收方确认传送过程完成。</p>
<p>&nbsp;</p>
<p>TCP协议基本上表现得像数据流一样，因此所有TCP套接字又称&ldquo;流式套接字&rdquo;。套接字是设备间互连所使用的底层基础对象。如果在数据队列中排队等待传输的数据太大，不适合放在一个单独的数据包里时，LAN驱动会把它拆分成多个包，挨个进行传送，直到所有包发送完成。但对于好奇的开发人员来说，上述过程已经被抽象化了。</p>
<p>&nbsp;</p>
<p>TCP 套接字可以通过多种连接的方式打开：RFCOMM Bluetooth，共享同一接入点的设备（一个设备通过无线方式连接而其他设备通过以太网口连接时仍然适用），即便手机是通过USB连接到平板或者电脑上时，也依然可行。只要知道端口名称和IP地址，你就可以用TCP去连接这个星球上的任何电脑（或许地球之外的也可以）。</p>
<p>&nbsp;</p>
<p>本文中，电脑将扮演服务器的角色，而手机将作为客户端。这里，电脑是指任何可以运行Windows Runtime程序的设备，包括ARM架构和X86架构的平板以及可以运行Windows 8的电脑。在Windows Phone 8发布之前，手机只能作为客户端。但是现在，手机也可以作为服务器来使用。有趣的是，服务器和客户端之间的界限并不明晰。任一方都可以作为服务器或者客户端，但是一个设备同时扮演这两种角色可能会导致一些不稳定的情况发生。</p>
<p>&nbsp;</p>
<p>通过参照MSDN文档，让我们把这些将要使用的类熟悉一下。<a href="http://msdn.microsoft.com/library/windows/apps/br226882" target="_blank">Stream Socket </a>, <a href="http://msdn.microsoft.com/library/windows/apps/br226906" target="_blank">Stream Socket Listener</a><strong></strong></p>
<p><strong>&nbsp;</strong></p>
<p>文档非常详细，甚至都已经涵盖把事情做好的每一个步骤。</p>
<p>&nbsp;</p>
<p>好了，让我们跳过文档，开始切入正题。我们需要启动一个监听者: 创建一个win 8 应用程序，然后创建一个看起来还过得去的界面。</p>
<p>&nbsp;</p>
<p>这里建议创建一个新的类来存储所有东西，便于稍后使用。</p>
<p>&nbsp;</p>
<p>我们所想发送的文件中包含了一些关于应用程序状态的随机数据。假设我们要在Windows Phone应用中继续做我们之前在Windows App上做的工作。那么我们就需要把重建的数据存储在这个要发送的的文件里。</p>
<p>&nbsp;</p>
<p>我们把这个文件隐藏在Roaming文件夹中</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">string fileName = "MyFileName.txt";</code></pre>
<p><code>&nbsp;</code></p>
<p>你可以用以下代码创建这个文件（你可能会好奇为什么我们不await这个异步调用， 因为我们不需要这样做：该调用会在后台线程上创建。除非你想要在接下来的方法中使用这个文件，否则你不需要await它）<strong></strong></p>
<p><strong>&nbsp;</strong></p>
<pre class="scroll"><code class="csharp">ApplicationData.Current.RoamingFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);</code></pre>
<p><strong>&nbsp;</strong></p>
<p>使用以下代码你可以获得这个文件：<strong></strong></p>
<pre class="scroll"><code class="csharp">Var myfile =await ApplicationData.Current.RoamingFolder.GetFileAsync(fileName);</code></pre>
<p>&nbsp;</p>
<p>你可以使用<a href="http://msdn.microsoft.com/library/windows/apps/hh701440">FileIO </a>类的方法在这个文件里面写一些东西。请确保你真的在文件里写了东西，这样它的大小才会大于0。如果你想要观察当一个文件不能被放在一个数据包里时，流套接字的所产生行为，那么，你可以把写文件的那些代码放在while或者for循环中，这样你就可以人为的增加文件的大小。</p>
<p>&nbsp;</p>
<p>此时，你已经准备了这个文件，那就该设置监听者了。由于我们不能在这个类的构造器中使用async调用，我们必须要创建一个任务，并在使用类构造器之后调用它：</p>
<p>&nbsp;</p>
<p>这里是一些起作用的变量。</p>
<pre class="scroll"><code class="csharp">public StreamSocketListener ServerListener = new StreamSocketListener();<br /> <br /> StreamSocket socket;<br /> <br /> public async Task InitStuff()<br /> <br /> {<br /> var f = ServerListener.Control;<br /> <br /> f.QualityOfService = SocketQualityOfService.LowLatency;<br /> <br /> ServerListener.ConnectionReceived += ServerListener_ConnectionReceived;<br /> <br /> await ServerListener.BindEndpointAsync(null, "13001");<br /> <br /> }<br /> </code></pre>
<p><code>&nbsp;</code></p>
<p><strong>变量</strong><strong>&ldquo;f&rdquo;</strong><strong>用来为流套接字监听者设置</strong><code>QualityOfService的属性。我们把它设为低延迟是为了确保传送能够尽可能的快。我们也必须要确保数据包能被尽可能快的处理，以避免超时（事实上这也是我们要做的工作）。</code></p>
<p><code>&nbsp;</code></p>
<p><code>在为接收的连接设置完事件处理方法之后，我们就可以开始监听了。</code><code></code></p>
<pre class="scroll"><code class="cplusplus">await ServerListener.BindEndpointAsync(null, "13001");</code></pre>
<p><code></code>&nbsp;</p>
<p><code>上面这行代码就是做这个的。它定义了用于监听连接的主机名和端口号。因为我们的手机没有主机名，我们只是简单的把它定义为</code><code>null</code><code>来接受来自其他主机的连接。</code><code></code></p>
<p><code>&nbsp;</code></p>
<p><code>来看一下接收连接的事件处理程序：</code><code></code></p>
<pre class="scroll"><code class="csharp">async void ServerListener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)</code></pre>
<p><code></code>&nbsp;</p>
<p><code>字段</code><code>args</code><code>包含了用在请求中的套接字。我们应该把该套接字赋予给事先声明过的流套接字。</code><code></code></p>
<pre class="scroll"><code class="csharp">socket = args.Socket;</code></pre>
<p><code>流套接字公开了两个流，一个输入流一个输出流。输入流是由远程套接字发送进来的数据流。</code><code></code></p>
<p><code>输出流是发给远程套接字的数据流。因为这是一个相当简单的请求和服务通信，我们并不是很关心从手机发过来的是什么。由于文件通常都以相同的方式传输，所以这里我们只看输出流：</code><code></code></p>
<pre class="scroll"><code class="csharp">var outputstream = socket.OutputStream; <br /> DataWriter writer = new DataWriter(outputstream);<br /> </code></pre>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code></p>
<p><code>我们将用</code><code>writer</code><code>对象往输出流写数据。</code><code></code></p>
<p><code>现在，我们打开文件，读取它的内容，然后使用</code>data writer<code>把这些字节写到输出流。</code><code></code></p>
<pre class="scroll"><code class="csharp">var myfile =await ApplicationData.Current.RoamingFolder.GetFileAsync(fileName);<br /> var streamdata = await myfile.OpenStreamForReadAsync();<br /> </code></pre>
<p align="left"><code>&nbsp;</code></p>
<p><code>传输的第一阶段是以字节的方式发送文件的长度</code><code></code></p>
<pre class="scroll"><code class="csharp">if(stage==0)<br /> {<br /> stage++;<br /> <br /> writer.WriteBytes(UTF8Encoding.UTF8.GetBytes((awaitstreamdata.Length.ToString()))<br /> await writer.StoreAsync();<br /> }<br /> </code></pre>
<p><code>第二个阶段的代码如下。使用一个变量来计算阶段的索引。如果需要，也可以去读取客户端发送给你的数据。大家可以去了解一下</code><code>Windows 8.1</code><code>的流套接字示例，它是一个关于如何读写数据详细的例子。</code><code></code></p>
<pre class="scroll"><code class="csharp">if(stage==1)<br /> {<br /> byte[] bb = new byte[streamdata.Length];<br /> <br /> streamdata.Read(bb, 0, (int)streamdata.Length);<br /> <br /> writer.WriteBytes(bb);<br /> <br /> await writer.StoreAsync();<br /> <br /> stage=0; <br /> }<br /> </code></pre>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code></p>
<p align="left"><code>注意</code><code>StoreAsync()</code>方法的<code>调用</code>。这个调用清空了data writer的缓存并把所有数据注入到输出流中。我们所要做的几乎就这么多，系统会帮我们完成剩下的事情。另外一个需要注意的是我们如何发送数据。首先写这个文件的长度，然后写文件本身的内容。牢记这些，我们后面将要用到。</p>
<p align="left"><code>&nbsp;</code></p>
<p align="left">现在，这段代码呈现出一个大问题：整段代码并不是类型安全的。我们发送原始字节到客户端，客户端也向我们发回原始字节。其实，仅就设备之间的单个文件传送而言，我们没必要去过多的考虑类型安全。但是值得注意的是：如果你想发送复杂的数据，如基于通信的消息，你就需要考虑到你只是得到了字节这一事实，并且你需要自己来构建解析系统。</p>
<p align="left">&nbsp;</p>
<p align="left">现在来看一下客户端代码。</p>
<p align="left">这次我们将用到Silverlight 运行时。这种代码在Windows Phone 7和Windows Phone 8上都可以使用。</p>
<p align="left">&nbsp;</p>
<p align="left">套接字类包含在System.Net.Sockets命名空间中。</p>
<p align="left">&nbsp;</p>
<p align="left">创建一个新类，添加下面的字段：</p>
<pre class="scroll"><code class="cplusplus">MemoryStream ArrayOfDataTransfered; <br /> string _serverName = string.Empty; <br /> private int _port = 13001; <br /> long FileLength = 0; <br /> int PositionInStream = 0; <br /> int Stage = 0;<br /> </code></pre>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>用户需要输入服务器名称和端口号。因为这个连接是在家庭或私有网络中建立的，服务器的具体</code><code>IP</code><code>地址是可变的。直接使用电脑的名称可以解决这个问题。提供给用户一个设置页面来设置连接的话，也是一个不错的主意。下面这些行的代码应该放在初始化的方法中，比如类的构造函数。流程是这样的：</code>连接 &gt; 发送 &gt; 接收。如果你想要传送的文件不止一个，你就需要重新开始整个过程。</p>
<pre class="scroll"><code class="csharp">if (String.IsNullOrWhiteSpace(serverName))<br /> <br /> {<br /> throw new ArgumentNullException("serverName");<br /> }<br /> <br /> if (portNumber &lt; 0 || portNumber &gt; 65535)<br /> <br /> {<br /> throw new ArgumentNullException("portNumber");<br /> <br /> }<br /> _serverName = serverName;<br /> <br /> _port = portNumber;<br /> <br /> public void SendData(string data);<br /> </code></pre>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>这个方法只是发送数据到远程服务器。下面来详细说明</code><code>:</code></p>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>首先我们需要</code><code>SocketAsyncEventArgs</code><code>这个对象，我们稍后将使用它。</code><code>SocketAsyncEventArgs</code><code>表示一个套接字操作。它的操作可以是发送，接收或者连接。</code><code></code></p>
<pre class="scroll"><code class="csharp">SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();</code></pre>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>然后，我们需要一个服务器端，使用服务器名称和端口号来构建这个对象。</code><code></code></p>
<pre class="scroll"><code class="csharp">DnsEndPoint hostEntry = new DnsEndPoint(_serverName, _port);</code></pre>
<p align="left"><code>下一步是创建套接字并设置各种属性，然后去连接远程服务器。</code><code></code></p>
<pre class="scroll"><code class="csharp">Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);<br /> <br /> socketEventArg.Completed += new EventHandler&lt;SocketAsyncEventArgs&gt;(SocketEventArg_Completed);<br /> <br /> socketEventArg.RemoteEndPoint = hostEntry;<br /> <br /> socketEventArg.UserToken = sock;<br /> </code></pre>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>再然后就是连接</code><code></code></p>
<p align="left"><code>sock.ConnectAsync(socketEventArg);</code></p>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>SocketEventArgs的事件处理方法如下：</code></p>
<pre class="scroll"><code class="csharp">void SocketEventArg_Completed(object sender, SocketAsyncEventArgs e)<br /> {<br /> switch (e.LastOperation)<br /> <br /> {<br /> case SocketAsyncOperation.Connect:<br /> <br /> ProcessConnect(e);<br /> <br /> break;<br /> <br /> case SocketAsyncOperation.Receive:<br /> <br /> ProcessReceive(e);<br /> <br /> break;<br /> <br /> case SocketAsyncOperation.Send:<br /> <br /> ProcessSend(e);<br /> <br /> break;<br /> <br /> default:<br /> <br /> throw new Exception("Invalid operation completed");<br /> }<br /> }<br /> </code></pre>
<p align="left"><code>当操作是一个连接请求的时候，我们只需使用上面定义过的</code><code>SendData</code><code>方法发送数据到服务器就可以了，相关的代码：</code><code></code></p>
<pre class="scroll"><code class="csharp">byte[] buffer = Encoding.UTF8.GetBytes(dataIn);<br /> <br /> e.SetBuffer(buffer, 0, buffer.Length);<br /> <br /> Socket sock = e.UserToken as Socket;<br /> <br /> sock.SendAsync(e);<br /> </code></pre>
<p align="left"><code>dataIn </code><code>是我们想发送到服务器的一个随机字符串。如果你想要从服务器请求多个文件，或者传输是在多个阶段完成，这个会很有用。</code><code>SendAsync</code><code>方法发送数据的原始字节到已连接的远程套接字。</code><code></code></p>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>ProcessSend</code><code>方法：</code><code></code></p>
<pre class="scroll"><code class="csharp">if (e.SocketError == SocketError.Success)<br /> <br /> {<br /> //Read data sent from the server<br /> <br /> Socket sock = e.UserToken as Socket;<br /> <br /> sock.ReceiveAsync(e);<br /> <br /> }<br /> <br /> else<br /> <br /> {<br /> ResponseReceivedEventArgs args = new ResponseReceivedEventArgs();<br /> <br /> args.response = e.SocketError.ToString();<br /> <br /> args.isError = true;<br /> <br /> OnResponseReceived(args);<br /> <br /> } <br /> </code></pre>
<p align="left"><code>这里唯一有意思的事情是调用</code><code>ReceiveAsync(e).</code><code>这个方法基本上是文件传输的核心。</code><code></code></p>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>我们想要得到两个阶段的数据。第一个阶段是文件大小。 如果没有得到文件的大小，有一个可能是它太小，小到几乎不存在（把可能的最大的</code><code>64</code><code>字节的数据转化为以兆为单位，你就可以看到结果）。第二个阶段就是文件本身。</code><code></code></p>
<pre class="scroll"><code class="csharp">var dataFromServer = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);<br /> <br /> Stage++;<br /> <br /> FileLength = long.Parse(dataFromServer);<br /> <br /> </code></pre>
<p align="left"><code>有意思的部分在第二阶段。基本上，它是整个流程中最重要的部分。</code><code></code></p>
<p align="left"><code>首先，我们将读取缓存区中的字节。</code><code></code></p>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>ArrayOfDataTransfered.Write(e.Buffer,<br />0, e.BytesTransferred);</code></p>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>PositionInStream字段只计算到目前为止我们获取的字节数。如果它的值小于文件长度，则意味着文件还没有完全在这边。反之，则表示文件已经传输完成。</code></p>
<pre class="scroll"><code class="csharp">if (PositionInStream &lt; FileLength)<br /> <br /> {<br /> Socket socks = e.UserToken as Socket;<br /> <br /> socks.ReceiveAsync(e);<br /> <br /> }<br /> <br /> else<br /> <br /> {<br /> Stage = 0;<br /> //save the file<br /> }<br /> </code></pre>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>如果文件还不在这里，意味着这个文件太大不适合放在一个数据包里面。也就是说，还有更多其它的包需要传送，我们需要再次调用</code><code>ReceiveAsync(e)</code><code>方法去读网络适配器的缓存区。</code><code></code></p>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>现在你要做的就是把内存流复制到一个单独的存储文件流中，传输即可完成。因为我们只用了一个内存流，你可能需要防止用户传送超过</code><code>100MB</code><code>大小的文件，否则就可能会触发一个内存溢出异常。如果你实在很想要传输超过</code><code>100MB</code><code>的文件，你可以直接把数据写入单独存储文件流中。如果要发送敏感数据的话，你还需要考虑套接字连接的安全问题。</code><code></code></p>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>附言： 可以通过以下方法提高程序的性能</code><code>:</code><code>在</code><code>Windows phone</code><code>程序中使用</code>ID_CAP_NETWORKING，在Windows Store程序使用Private Networks。</p>
<p align="left"><code><strong>&nbsp;</strong></code></p>
<p align="left"><code><strong>参见：</strong></code><code><strong></strong></code></p>
<p align="left"><code>&nbsp;</code></p>
<p align="left"><code>另外一个可以找到大量</code>Windows Phone 相关文章的地方是TechNet Wiki，最佳的入口是<a href="http://social.technet.microsoft.com/wiki/contents/articles/24690.windows-phone-resources-on-the-technet-wiki.aspx" target="_blank">Windows Phone<br />Resources on the TechNet Wiki</a>.</p>
<p align="left">&nbsp;</p>
<p><strong>本文翻译自：</strong><a href="http://social.technet.microsoft.com/wiki/contents/articles/20495.how-to-transfer-files-between-a-windows-store-app-and-any-windows-phone-app.aspx">http://social.technet.microsoft.com/wiki/contents/articles/20495.how-to-transfer-files-between-a-windows-store-app-and-any-windows-phone-app.aspx</a><br /><strong></strong></p>]]></content:encoded>
    </item>
    <item>
      <title>如何使用BehaviorSDK</title>
      <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/behaviorsdk</link>
      <pubDate>Thu, 23 Oct 2014 21:48:00 GMT</pubDate>
      <dc:creator><![CDATA[MingXu-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows8devsupport/2014/10/23/behaviorsdk/</guid>
      <description><![CDATA[前言
在开发过程中，程序员一般通过代码的方式处理后台逻辑，与前台UI分开设计，这也就是为什么MVVM设计模式会产生。在前台设计的过程中，难免会涉及到一些最简单的用户交互逻辑，比如说页面的导航，播放音...]]></description>
      <content:encoded><![CDATA[<h1>前言</h1>
<p>在开发过程中，程序员一般通过代码的方式处理后台逻辑，与前台UI分开设计，这也就是为什么MVVM设计模式会产生。在前台设计的过程中，难免会涉及到一些最简单的用户交互逻辑，比如说页面的导航，播放音乐，执行一个动画。</p>
<p>这里我介绍一个BehaviorSDK，可以帮助我们在前台设计时候快速的添加一些简单的逻辑。</p>
<h1>如何添加BehaviorSDK的引用</h1>
<p>BehaviorSDK会随Visual Studio 2013&nbsp;一起安装，使用时，开发人员只需要在引用管理器里面添加对BehaviorSDK的引用。</p>
<div>
<div>
<div>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4774.1.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4774.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4774.1.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4774.1.png" alt="" border="0" /></a></p>
<p>在XAML中使用时，，开发人员还需要在XAML中做好引用 (详见如下代码的加粗部分)。</p>
<p>&lt;Page</p>
<p>&nbsp;&nbsp;&nbsp; x:Class="BehaviorSDK.SamplePage"</p>
<p>&nbsp;&nbsp;&nbsp; xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</p>
<p>&nbsp;&nbsp;&nbsp; xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"</p>
<p>&nbsp;&nbsp;&nbsp; xmlns:local="using:BehaviorSDK"</p>
<p>&nbsp;&nbsp;&nbsp; xmlns:d="http://schemas.microsoft.com/expression/blend/2008"</p>
<p>&nbsp;&nbsp;&nbsp; xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"</p>
<p>&nbsp;&nbsp;&nbsp; mc:Ignorable="d"</p>
<p>&nbsp;&nbsp;&nbsp;</p>
<p><strong>&nbsp;&nbsp;&nbsp; xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"</strong></p>
<p><strong>&nbsp;&nbsp;&nbsp; xmlns:Core="using:Microsoft.Xaml.Interactions.Core"</strong></p>
<p><strong>&nbsp;&nbsp;&nbsp; xmlns:Media="using:Microsoft.Xaml.Interactions.Media"</strong></p>
<p>&nbsp;&nbsp;&nbsp; &gt;</p>
<p>&nbsp;</p>
<h1>BehaviorSDK的官方文档</h1>
<p>文档入口：<a href="http://msdn.microsoft.com/zh-cn/library/windows/apps/dn457340.aspx">http://msdn.microsoft.com/zh-cn/library/windows/apps/dn457340.aspx</a>&nbsp;</p>
<p>想要了解更多详细信息，建议大家看原版的英文文档。下文将为大家介绍一下BehaviorSDK的几个简单用法，文末会附上示例代码。</p>
<p>&nbsp;</p>
<h1>功能: 互交</h1>
<p><a title="Microsoft.Xaml.Interactions.Core" href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.core.aspx">Microsoft.Xaml.Interactions.Core</a> 这个类帮助我们实现互交功能:</p>
<table style="width: 623px;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td nowrap="nowrap" width="315">
<p align="center"><strong>API</strong></p>
</td>
<td nowrap="nowrap" width="308">
<p align="center"><strong>解</strong><strong>释</strong><strong></strong></p>
</td>
</tr>
<tr>
<td width="315">
<p align="center"><strong><a href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.core.callmethodaction.aspx">CallMethodAction</a></strong></p>
</td>
<td nowrap="nowrap" width="308">
<p align="center">当一个方法被调用时候的动作</p>
</td>
</tr>
<tr>
<td nowrap="nowrap" width="315">
<p align="center">&nbsp;</p>
<table style="width: 298px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="298">
<p align="center"><a href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.core.changepropertyaction.aspx">ChangePropertyAction</a></p>
</td>
</tr>
</tbody>
</table>
</td>
<td nowrap="nowrap" width="308">
<p align="center">当一个属性改变时候的动作</p>
</td>
</tr>
<tr>
<td nowrap="nowrap" width="315">
<p align="center">&nbsp;</p>
<table style="width: 298px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="298">
<p align="center"><a href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.core.datatriggerbehavior.aspx">DataTriggerBehavior</a></p>
</td>
</tr>
</tbody>
</table>
</td>
<td nowrap="nowrap" width="308">
<p align="center">当绑定的数据满足某一个特定条件时候的行为</p>
</td>
</tr>
<tr>
<td nowrap="nowrap" width="315">
<p align="center">&nbsp;</p>
<table style="width: 298px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="298">
<p align="center"><a href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.core.eventtriggerbehavior.aspx">EventTriggerBehavior</a></p>
</td>
</tr>
</tbody>
</table>
</td>
<td nowrap="nowrap" width="308">
<p align="center">当一个事件被触发时候的行为</p>
</td>
</tr>
<tr>
<td nowrap="nowrap" width="315">
<p align="center">&nbsp;</p>
<table style="width: 298px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="298">
<p align="center"><a href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.core.gotostateaction.aspx">GoToStateAction</a></p>
</td>
</tr>
</tbody>
</table>
</td>
<td nowrap="nowrap" width="308">
<p align="center">用来进入控件的某种可视化状态的动作</p>
</td>
</tr>
<tr>
<td nowrap="nowrap" width="315">
<p align="center">&nbsp;</p>
<table style="width: 298px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="298">
<p align="center"><a href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.core.incrementalupdatebehavior.aspx">IncrementalUpdateBehavior</a></p>
</td>
</tr>
</tbody>
</table>
</td>
<td nowrap="nowrap" width="308">
<p align="center">当数据有Lazy Loading更新时候的行为</p>
</td>
</tr>
<tr>
<td nowrap="nowrap" width="315">
<p align="center">&nbsp;</p>
<table style="width: 298px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="298">
<p align="center"><a href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.core.invokecommandaction.aspx">InvokeCommandAction</a></p>
</td>
</tr>
</tbody>
</table>
</td>
<td nowrap="nowrap" width="308">
<p align="center">执行一个指定命令的动作</p>
</td>
</tr>
<tr>
<td nowrap="nowrap" width="315">
<p align="center">&nbsp;</p>
<table style="width: 298px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="298">
<p align="center"><a href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.core.navigatetopageaction.aspx">NavigateToPageAction</a></p>
</td>
</tr>
</tbody>
</table>
</td>
<td nowrap="nowrap" width="308">
<p align="center">可以用来导航到另外一个页面的动作</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<h2>如何导航到另外一个页面</h2>
<p>这里举个简单的例子来说明下，假设我们需要点击某个Button来导航到另外一个页面，使用传统的实现方式，我们需要在后台cs中添加如下代码：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private void Button_Click(object sender, RoutedEventArgs e)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Frame.Navigate(typeof(BasicPage1),"我是通过后台代码Button Click Event导航到此页面的");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>但是通过BehaviorSDK，只要在XAML中就可以处理完成。办法如下：</p>
<p>1， 首先通过EventTrigger的方式捕获Click事件</p>
<p>2， 通过NavigateToPageAction来导航到另外一个页面</p>
<p>具体实现的XAML代码如下：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Button Content="点击我使用BehaviorSDK的方式导航到另外一个页面" HorizontalAlignment="Left" Height="209" Margin="647,161,0,0" VerticalAlignment="Top" Width="421"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Interactivity:Interaction.Behaviors&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Core:EventTriggerBehavior EventName="Click"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Core:NavigateToPageAction TargetPage="BehaviorSDK.BasicPage1" Parameter="我是通过BehaviorSDK的方式导航到此页面的"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Core:EventTriggerBehavior&gt;</p>
<p>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Interactivity:Interaction.Behaviors&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Button&gt;</p>
<p>请注意两点:</p>
<p>1，&nbsp; Target Page必须是要全称，包括项目的NameSpace，接受的是String类型。</p>
<p>2，&nbsp; Parameter可以是一个Object类型，示例中简单的放了一个String，实际使用时也可以根据需要绑定成其它的控件。</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/5710.2.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/5710.2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/5710.2.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/5710.2.png" alt="" border="0" /></a></p>
<h2>如何调用一个Command</h2>
<p>同样还是要通过EventTrigger的方式来监测Click事件是否被触发，不同的是这个示例中调用的是一个Command:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Button Content="点击我调用一个Command" HorizontalAlignment="Left" Height="212" Margin="121,440,0,0" VerticalAlignment="Top" Width="415"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Interactivity:Interaction.Behaviors&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Core:EventTriggerBehavior EventName="Click"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Core:InvokeCommandAction Command="{Binding Source={StaticResource command}}" CommandParameter="我是被传递的参数"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Core:EventTriggerBehavior&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Interactivity:Interaction.Behaviors&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Button&gt;</p>
<p>效果如下：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7532.3.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7532.3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7532.3.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7532.3.png" alt="" border="0" /></a></p>
<h2>如何触发一个视觉效果</h2>
<p>此处用按钮作为例子，一个按钮会有很多不同视觉效果，比如说鼠标移近来的时候会有灰色背景，鼠标点击的时候背景会变成白色，这个就是通过不同的视觉效果来实现的。</p>
<p>设想如下场景：，当我们鼠标进入到按钮1的时候，按钮2的背景色做对应的变化，如果我们在写C#代码，我们会用GoToState的方式来实现，这里BehaviorSDK提供了一种更为直接的方式：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Button Content="当鼠标移入/移出的时候，左边的Button会显示不同的状态" HorizontalAlignment="Left" Height="206" Margin="650,443,0,0" VerticalAlignment="Top" Width="415"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Interactivity:Interaction.Behaviors&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Core:EventTriggerBehavior EventName="PointerEntered"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Core:GoToStateAction StateName="PointerOver" TargetObject="{Binding ElementName=button}"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Core:EventTriggerBehavior&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Core:EventTriggerBehavior EventName="PointerExited"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Core:GoToStateAction StateName="Normal" TargetObject="{Binding ElementName=button}"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Core:EventTriggerBehavior&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Interactivity:Interaction.Behaviors&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Button&gt;</p>
<p>当我们鼠标移入/移出右边的按钮时，左边的按钮也会随之变化：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7558.4.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7558.4.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7558.4.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7558.4.png" alt="" border="0" /></a></p>
<h2>其他</h2>
<p>我们还可以实现很多其它的功能，这个需要大家自己在使用过程中不断发掘。比如说调用一个方法，比如说改变某一个属性，因文章篇幅有限，这里就不详细展开去了。</p>
<p>&nbsp;</p>
<h1>功能：多媒体</h1>
<p><a title="Microsoft.Xaml.Interactions.Media" href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.media.aspx">Microsoft.Xaml.Interactions.Media</a> 这个类可以帮我们实现这一点，这个类里面方法很少，就两个，1，如何控制一个StoryBoard，2，如何播放一个多媒体文件。功能不多，但是都非常实用，下面我们一个个来说一下：</p>
<h2>如何控制一个StoryBoard</h2>
<p>我们这里还是用按钮点击事件来触发一个动画效果来作为示例，使用Media:ControlStoryboardAction 可以控制动画的播放，动画的内容，我们可以通过<a title="ControlStoryboardOption Enumeration" href="http://msdn.microsoft.com/en-us/library/windows/apps/microsoft.xaml.interactions.media.controlstoryboardoption.aspx">ControlStoryboardOption Enumeration</a> 这个文档来查看具体的情况。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Button Content="点击我执行一个动画" HorizontalAlignment="Left" Height="124" Margin="124,472,0,0" VerticalAlignment="Top" Width="412"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Interactivity:Interaction.Behaviors&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Core:EventTriggerBehavior EventName="Click"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Media:ControlStoryboardAction ControlStoryboardOption="Play" Storyboard="{Binding ElementName=mystoryboard}"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Core:EventTriggerBehavior&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Interactivity:Interaction.Behaviors&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Button&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Rectangle x:Name="rectangle" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="49" Margin="653,504,0,0" Stroke="Black" VerticalAlignment="Top" Width="49" RenderTransformOrigin="0.5,0.5"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Rectangle.Resources&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Storyboard x:Name="mystoryboard"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&lt;DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="rectangle"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;EasingDoubleKeyFrame KeyTime="0" Value="1"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;EasingDoubleKeyFrame KeyTime="0:0:1" Value="3"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/DoubleAnimationUsingKeyFrames&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="rectangle"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;EasingDoubleKeyFrame KeyTime="0" Value="1"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;EasingDoubleKeyFrame KeyTime="0:0:1" Value="3"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/DoubleAnimationUsingKeyFrames&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Storyboard&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Rectangle.Resources&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Rectangle.RenderTransform&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;CompositeTransform/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Rectangle.RenderTransform&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Rectangle&gt;</p>
<p>&nbsp;</p>
<h2>如何播放一个音频文件</h2>
<p>背景音乐可以带来良好的用户体验，恰当的使用可以极大地提升用户满意度，所以这里我们具体讲述一下如何播放一个音频文件。</p>
<p>注意：音乐是我从一个开源音乐库中下载的，如果音乐的作者发现并未授权给此网站，我们会进行修改，如有带来不便，深表歉意。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Button Content="点击我来播放背景音乐" HorizontalAlignment="Left" Height="118" Margin="653,475,0,0" VerticalAlignment="Top" Width="409"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Interactivity:Interaction.Behaviors&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Core:EventTriggerBehavior EventName="Click"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Media:PlaySoundAction Source="Sound/mp3.mp3" Volume="0.5"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Core:EventTriggerBehavior&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Interactivity:Interaction.Behaviors&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Button&gt;</p>
<p>&nbsp;</p>
<h1>总结</h1>
<p>上述的所有功能均可以在Blend中轻松实现，Blend会为我们自动添加这些代码，使编程过程更加简单，具体请看以下截图：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/1055.5.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/1055.5.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/1055.5.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/1055.5.png" alt="" border="0" /></a></p>
<p>上述示例代码分享在OneDrive：<a href="http://1drv.ms/1yvrtgG">http://1drv.ms/1yvrtgG</a>&nbsp;供大家参考。</p>
</div>
</div>
</div>]]></content:encoded>
    </item>
    <item>
      <title>如何处理WinJS程序崩溃</title>
      <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/winjs</link>
      <pubDate>Wed, 20 Aug 2014 23:44:31 GMT</pubDate>
      <dc:creator><![CDATA[MingXu-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows8devsupport/2014/08/20/winjs/</guid>
      <description><![CDATA[我们开发程序的时候经常会遇到这样的问题，如何在WinJS程序崩溃的时候及时记录下来我们需要的错误信息, 以便我们修复程序,...]]></description>
      <content:encoded><![CDATA[<p>我们开发程序的时候经常会遇到这样的问题，如何在WinJS程序崩溃的时候及时记录下来我们需要的错误信息, 以便我们修复程序, 发布下一个更好的版本.&nbsp;</p>
<p>第一反应是WinJS.Log()或者普通的console.log()方法，当然, 这两个办法非常实用，具体用法网上教程很多，我们可以简单的把WinJS程序理解成一个HTML页面的调试，这里不再赘述。但不足之处在于这两个方法仅仅用于本地调试，一旦用户安装了应用之后出现了什么问题，这两个方法只能在用户本地记录错误信息，不能及时的发送给开发人员。&nbsp;</p>
<p>我在论坛上遇到很多类似的提问, 比如开发者提到用户反映App出现了一些异常，开发者有什么办法及时获取这些异常信息？微软有考虑过这样的情况，有一个叫CEIP的计划，全称为Customer Experience Improvement Program，可以让开发者在DashBoard上获取用户运行App崩溃时候的一些异常信息，这是一个极好的工具，生成的Dump文件可以帮助分析各种出错的地方。&nbsp;</p>
<p>但是开发者们也想自己搭建一个Server用于接收用户的错误信息，这样可以及时收集到第一手且全面的错误信息, 以便快速修复这些问题, 提高App用户的体验？通过参考WinJS大神的<a href="http://kraigbrockschmidt.com/blog/?p=334,">Blog</a>，我们可以得出以下结论：WinJS.Application.onerror并不是导致程序立即关闭的重要因素, 而<em>MSApp.terminateApp()</em>才是关闭程序的根本原因，所以我们可以在这之间抽出一段时间用于保存我们的错误信息并且发送，当然我们还可以通过改变return值来阻止程序关闭。&nbsp;</p>
<p>Windows.Application.onerror = function (e) {</p>
<p>showErrorPage(e);&nbsp;</p>
<p>return<br />true; //<br />telling WinJS that the exception was handled, don't terminate</p>
<p>}</p>
<p>&nbsp;在上面这段代码中，我使用了 showErrorPage()这个办法来显示一个错误信息的页面，并且把返回值改成了Ture，这样WinJS程序就不会退出，从而给了我们收集错误信息的时间，也带给用户更好的体验。&nbsp;</p>
<p>下面我们要谈谈什么样的错误信息数据才是我们需要的数据。很多时候论坛上大家会问如何处理bug，但是似乎又缺少了点什么东西来做处理的判断，或合理的让错误信息指引我们修复程序. 我认为一个好的机制应该是反馈一些包括：</p>
<ul>
<li><br />操作系统版本以及补丁信息</li>
<li><br />语言版本</li>
<li><br />哪个页面出问题</li>
<li><br />第几行代码出问题</li>
<li><br />具体问题的异常信息</li>
<li><br />设备信息（曾经有一个问题是跟设备的显示屏大小有关）</li>
</ul>
<p>仅仅当我们获取了一个完整的信息的时候，我们才可以重现用户提到的问题，或许下次用户发邮件来询问这个问题的时候，你已经能提供一个完美的解决方案了。&nbsp;</p>
<p>最后，我们还得考虑如何把错误信息发送出去，一般来说，我会在ShowErrorPage里面把错误信息发送出去，但有可能用户是在没有网络的情况下遇到这样的问题，所以我会检查一个网络连接是否正常，仅仅当有网络的时候发送错误信息，所以错误信息会预先记录在本地。或者还有一个思路就是程序开启的时候发送错误信息，不过请注意一点：我们应当优先考虑用户流畅使用度。&nbsp;</p>
<p>另外，建议大家使用StackTraceJS(http://stacktracejs.com/) 这个工具来收集具体的错误信息，它是一个非常有用的JS扩展库。</p>]]></content:encoded>
    </item>
    <item>
      <title>关于Blend的这些, 您知道吗?</title>
      <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/blend</link>
      <pubDate>Wed, 20 Aug 2014 00:09:00 GMT</pubDate>
      <dc:creator><![CDATA[MingXu-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows8devsupport/2014/08/20/blend/</guid>
      <description><![CDATA[最近很多人会提到如何在商店应用里面画图，虽然通过XAML并不是那么容易可以把某个图形画出来, 但是在XAML里面我们可以利用万能的Path, 添加数据描述来形容某个图形....]]></description>
      <content:encoded><![CDATA[<p>最近很多人会提到如何在商店应用里面画图，虽然通过XAML并不是那么容易可以把某个图形画出来, 但是在XAML里面我们可以利用万能的Path, 添加数据描述来形容某个图形. 硬编码这些数据确实有难度，我们建议借助Blend的帮助来画出复杂的图形。&nbsp;</p>
<p>本文章选取几个比较常用的图形来讲解下如何使用Blend画图。&nbsp;</p>
<h2>如何画十字架（图形相加）</h2>
<p>&nbsp;经过分析，十字架图形其实就是两个长方形拼接而成，所以我们先画出两个长方形, 再将其合并。</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7167.1.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7167.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7167.1.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7167.1.png" alt="" border="0" /></a>&nbsp;</p>
<p>接下来，我们合并这两个图形：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/5277.2.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/5277.2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/5277.2.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/5277.2.png" alt="" border="0" /></a>&nbsp;</p>
<p>我们可以看到生成十字架图形的同时，XAML也生成了对应的Path：</p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/5076.3.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/5076.3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/5076.3.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/5076.3.png" alt="" border="0" /></a>&nbsp;</p>
<h2>如何画扇形（图形相减）</h2>
<p>首先在Blend里面画出如下图形:一个圆和一个长方形，同时选中他们之后合并-&gt;相减，就可以出一个半圆：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7607.4.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7607.4.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7607.4.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7607.4.png" alt="" border="0" /></a>&nbsp;</p>
<p>选择合并-&gt;相减，得到一个半圆。然后重复相同的动作，同时把长方形做一个旋转，再进行相减，就可以得到你想要的扇形。</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7115.5.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7115.5.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7115.5.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7115.5.png" alt="" border="0" /></a></p>
<p>这样可以得出一个用XAML Path来表示的扇形：</p>
<div>
<p>&nbsp;&nbsp; &lt;Path Data="M100,0<br />C136.243,-1E-05 167.984,19.2815 185.523,48.1463 L186.592,50.0061 L100,100<br />L0,100 C3E-06,44.7715 44.7715,-1.1E-05 100,0 z" Fill="#FFF4F4F5" Margin="583,284,596.408,384" Stretch="Fill" UseLayoutRounding="False"/&gt;&nbsp;</p>
</div>
<p>&nbsp;效果如下：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/2664.6.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/2664.6.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/2664.6.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/2664.6.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<h2>如何画圆环（删除图形重叠）</h2>
<p>&nbsp;类似之前的做法,首先画两个使用同样圆心的圆，按Shift键可以画出如下圆形：</p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/8420.7.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/8420.7.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/8420.7.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/8420.7.png" alt="" border="0" /></a>&nbsp;</p>
<p>&nbsp;</p>
<p>选择 Exclude Overlap&nbsp; 来把交集的地方删除，就可以画出一个圆环啦。当然我们也可以给他上色：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/2134.8.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/2134.8.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/2134.8.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/2134.8.png" alt="" border="0" /></a></p>
<p>&nbsp;具体生成的XAML代码：</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;Path Data="M175.5,23.5 C91.5527,23.5 23.5,91.3289 23.5,175<br />C23.5,258.671 91.5527,326.5 175.5,326.5 C259.447,326.5 327.5,258.671 327.5,175 C327.5,91.3289<br />259.447,23.5 175.5,23.5 z M175.5,0.5 C272.15,0.5 350.5,78.8502 350.5,175.5<br />C350.5,272.15 272.15,350.5 175.5,350.5 C78.8502,350.5 0.5,272.15 0.5,175.5<br />C0.5,78.8502 78.8502,0.5 175.5,0.5 z" HorizontalAlignment="Left" Height="351" Margin="524,237,0,0" Stretch="Fill" Stroke="Black" UseLayoutRounding="False" VerticalAlignment="Top" Width="351"&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Path.Fill&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;GradientStop Color="#FFFF0707"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;GradientStop Color="#FF319104" Offset="1"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/LinearGradientBrush&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Path.Fill&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;/Path&gt;</p>
<p>&nbsp;&nbsp;</p>
<h2>如何画个大O（图像变形）</h2>
<p>假如现在我们又有一个新的需求，老板觉得圆环似乎太过于呆板，需要一个大O的形状，XAML不是PhotoShop，怎么才能完成这样的要求呢？&nbsp;</p>
<p>我们需要一个变形工具，截图上白色的鼠标可以帮助我们对图像进行变形，图像中白色的点是可以拖动的顶点，会根据拖动来自动调整两个顶点之间的曲线：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/3060.11.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/3060.11.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/3060.11.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/3060.11.png" alt="" width="34" height="275" border="0" /></a><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/6406.9.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/6406.9.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/6406.9.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/6406.9.png" alt="" width="137" height="279" border="0" /></a>&nbsp;</p>
<p>最后的最后，留给大家一个问题，如何将我们刚刚画的两个图形组合起来？&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/5807.10.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/5807.10.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/5807.10.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/5807.10.png" alt="" width="213" height="246" border="0" /></a>&nbsp;</p>
<p>答案：</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="300" Margin="599,404,0,-39" Stroke="Black" VerticalAlignment="Top" Width="43"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;Path Data="M175.5,23.5 C91.5527,23.5 115.678,82.5532 115.678,166.224<br />C115.678,249.895 91.5527,326.5 175.5,326.5 C259.447,326.5 239.972,252.381<br />239.972,168.71 C239.972,85.0392 259.447,23.5 175.5,23.5 z M175.5,0.5<br />C272.15,0.5 350.5,78.8502 350.5,175.5 C350.5,272.15 272.15,350.5 175.5,350.5<br />C78.8502,350.5 0.5,272.15 0.5,175.5 C0.5,78.8502 78.8502,0.5 175.5,0.5 z" HorizontalAlignment="Left" Height="212.194" Margin="515,355.5,0,0" Stretch="Fill" Stroke="Black" UseLayoutRounding="False" VerticalAlignment="Top" Width="212.194"&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Path.Fill&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;GradientStop Color="#FFFF0707"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;GradientStop Color="#FF319104" Offset="1"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/LinearGradientBrush&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Path.Fill&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;/Path&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &lt;Path Data="M90.5,0.5 L132.5,0.5 L132.5,73.5 L223.5,73.5 L223.5,107.5<br />L132.5,107.5 L128.528,162.962 L95.4799,164.462 L90.5,107.5 L0.5,107.5 L0.5,73.5<br />L90.5,73.5 z" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="164.962" Margin="509,332.038,0,0" Stretch="Fill"&nbsp; UseLayoutRounding="False" VerticalAlignment="Top" Width="224"/&gt;</p>]]></content:encoded>
    </item>
    <item>
      <title>如何在Win8下通过C#+XAML创建一个自定义控件</title>
      <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/win8cxaml</link>
      <pubDate>Fri, 30 May 2014 01:01:00 GMT</pubDate>
      <dc:creator><![CDATA[MingXu-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows8devsupport/2014/05/30/win8cxaml/</guid>
      <description><![CDATA[我们知道在Win8下可以很轻松的通过系统自带的控件来开发一些新的自定义控件，当然语言不限于XAML+C#或者VB.NET。这些控件可以让我们的UI更加丰富多彩。
今天，我向大家介绍一下如何创建这样的...]]></description>
      <content:encoded><![CDATA[<p>我们知道在Win8下可以很轻松的通过系统自带的控件来开发一些新的自定义控件，当然语言不限于XAML+C#或者VB.NET。这些控件可以让我们的UI更加丰富多彩。</p>
<p>今天，我向大家介绍一下如何创建这样的自定义控件，我将会以XAML Carousel为例子。</p>
<p>[View:http://www.dotmim.com/sitefiles/Carousel.mp4:550:0]</p>
<p>大家可以从视频中看到，这是一个3D的旋转相册，可以用来展示不同的图片，同时这些图片还包括了一些镜像特效。</p>
<p>或许现在的您想知道怎么才能开发一个如此美观的控件，答案分为以下六步:&nbsp;</p>
<p>1， 如何设置控件外观</p>
<p>2， 声明以及实例化</p>
<p>3， 使用模板</p>
<p>4， 使用数据绑定</p>
<p>5， 整合用户操作以及动画效果</p>
<p>6， 优化处理</p>
<p>&nbsp;</p>
<h1>如何设置控件外观</h1>
<p>&nbsp;</p>
<p>这个控件是基于Canvas开发的，叫做Carousel，其中我们为该控件的ItemTemplate 定义了一个DataTemplate，该DataTemplate是用于描述每一个图片项目由哪些控件组成的。&nbsp;</p>
<p>在这个例子中，你可以看到我使用了一个镜像的特效，我通过翻转X轴（RotationX），缩放Y轴（ScaleY）来实现这样的效果。</p>
<p>我在控件中定义了一个黑框区域来显示这些不同角度的镜像。</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4300.4.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4300.4.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4300.4.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4300.4.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p>有了DataTemplate和依赖属性的帮助，我们可以通过仅仅在模板中设置某些属性值来随意定义不同区域的控件样式。</p>
<p>举个例子，我们这里有两种不同的风格：第一种是没有镜像，没有旋转的效果。另一种是有旋转的效果，如下图所示：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7558.5.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7558.5.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7558.5.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7558.5.png" alt="" border="0" /></a>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4201.6.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4201.6.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4201.6.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4201.6.png" alt="" border="0" /></a></p>
<h1>声明以及实例化控件<span style="font-size: 12px;">&nbsp;</span></h1>
<p>很简单， 在XAML中写如下的语句： &lt;Ctrl:LightStone /&gt;。 不过您需要设置以下的属性才能让控件正常工作。&nbsp;</p>
<h2>数据源(ItemsSource)</h2>
<p>&nbsp;</p>
<p>类似于ListBox或者ListView的数据源，我们也应该为这个控件做一些数据源的配置。我比较推荐的是用ObservableCollection&lt;T&gt;这个集合类型，通过这个我们可以很方便得在运行程序的时候为控件添加或删除数据。&nbsp;</p>
<h2>依赖属性</h2>
<p>&nbsp;</p>
<ul>
<li><br />TransitionDuration：动画时长，以ms为单位</li>
<li><br />Depth：未选中项目的深度</li>
<li><br />Rotation：未选中项目的旋转</li>
<li><br />TranslateX：未选中项目的X轴位移</li>
<li><br />TranslateY：对所有项目的Y轴位移</li>
</ul>
<p>&nbsp;</p>
<h2>缓动函数的配置</h2>
<p>&nbsp;</p>
<p>你可以配置一些函数来控制图像的动画效果，具体可以参考<a href="http://msdn.microsoft.com/en-us/library/ee308751.aspx">http://msdn.microsoft.com/en-us/library/ee308751.aspx</a></p>
<p>&nbsp;</p>
<p>我使用下面的函数来完成动画效果：</p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/2352.7.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/2352.7.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/2352.7.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/2352.7.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<h1>使用模板</h1>
<p>&nbsp;</p>
<p>XAML提供了一个非常简单的方式来实现ItemTemplate，下面的代码可以把数据绑定到控件上。在这个模板里面，我定义了一个图片并且设置了图片相对的镜像以及透明度。&nbsp;</p>
<pre class="scroll"><code class="csharp">&lt;ctrl:LightStone.ItemTemplate&gt;<br /> &lt;DataTemplate&gt;<br /> &lt;Grid&gt;<br /> &lt;Grid.RowDefinitions&gt;<br /> &lt;RowDefinition Height="Auto"/&gt;<br /> &lt;RowDefinition Height="Auto"/&gt;<br /> &lt;/Grid.RowDefinitions&gt;<br /> &lt;Image Source="{Binding BitmapImage}" Width="600" VerticalAlignment="Bottom" <br /> Stretch="Uniform"&gt;&lt;/Image&gt;<br /> <br /> &lt;Rectangle Grid.Row="1" Fill="Black" Margin="0,10" &gt;&lt;/Rectangle&gt;<br /> <br /> &lt;Image Grid.Row="1" VerticalAlignment="Top" Width="600" Margin="0,10" <br /> Source="{Binding BitmapImage}" Stretch="Uniform" <br /> Opacity="0.1" &gt;<br /> &lt;Image.RenderTransform&gt;<br /> &lt;CompositeTransform ScaleY="1" /&gt;<br /> &lt;/Image.RenderTransform&gt;<br /> &lt;Image.Projection&gt;<br /> &lt;PlaneProjection RotationX="180"&gt;&lt;/PlaneProjection&gt;<br /> &lt;/Image.Projection&gt;<br /> &lt;/Image&gt;<br /> <br /> &lt;/Grid&gt;<br /> &lt;/DataTemplate&gt;<br /> &lt;/ctrl:LightStone.ItemTemplate&gt;<br /> </code></pre>
<p>&nbsp;</p>
<h2><span style="font-family: 宋体; mso-ascii-font-family: 'Calibri Light'; mso-ascii-theme-font: major-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: major-fareast; mso-hansi-font-family: 'Calibri Light'; mso-hansi-theme-font: major-latin;" lang="ZH-CN">具体实现</span></h2>
<p>ItemTemplate实则为DataTemplate，下面是代码：</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">/// &lt;summary&gt;<br /> /// Item Template <br /> /// &lt;/summary&gt;<br /> public DataTemplate ItemTemplate<br /> {<br /> get<br /> {<br /> return itemTemplate;<br /> }<br /> set<br /> {<br /> itemTemplate = value;<br /> }<br /> }<br /> </code></pre>
<p>&nbsp;</p>
<p>在绑定的时候，LoadContent() 这个方法可以帮助我们创建UIElement</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">/// &lt;summary&gt;<br /> /// Bind all Items<br /> /// &lt;/summary&gt;<br /> private void Bind()<br /> {<br /> if (ItemsSource == null)<br /> return;<br /> <br /> this.Children.Clear();<br /> this.internalList.Clear();<br /> <br /> foreach (object item in ItemsSource)<br /> this.CreateItem(item);<br /> <br /> this.Children.Add(rectangle);<br /> }<br /> <br /> /// &lt;summary&gt;<br /> /// Create an item (Load data template and bind)<br /> /// &lt;/summary&gt;<br /> private FrameworkElement CreateItem(object item, Double opacity = 1)<br /> {<br /> FrameworkElement element = ItemTemplate.LoadContent() as FrameworkElement;<br /> if (element == null)<br /> return null;<br /> <br /> element.DataContext = item;<br /> element.Opacity = opacity;<br /> element.RenderTransformOrigin = new Point(0.5, 0.5);<br /> <br /> PlaneProjection planeProjection = new PlaneProjection();<br /> planeProjection.CenterOfRotationX = 0.5;<br /> planeProjection.CenterOfRotationY = 0.5;<br /> element.Projection = planeProjection;<br /> <br /> this.internalList.Add(element);<br /> this.Children.Add(element);<br /> <br /> return element;<br /> }<br /> </code></pre>
<p>&nbsp;</p>
<h1>数据绑定</h1>
<p>ItemsSource提供了数据绑定的功能。</p>
<p>不过我们需要自己的数据集合，可以通过如下的方式定义一个数据类型</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp"> public class Data<br /> {<br /> public BitmapImage BitmapImage { get; set; }<br /> public String Title { get; set; }<br /> }<br /> </code></pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>下面这段代码用来实例化：</p>
<pre class="scroll"><code class="csharp">public ObservableCollection&lt;Data&gt; Datas { get; set; }<br /> <br /> public MainPageViewModel()<br /> {<br /> this.Datas = new ObservableCollection&lt;Data&gt;();<br /> this.Datas.Add(new Data { BitmapImage = new BitmapImage(new Uri("ms-appx:///Assets/pic01.jpg", UriKind.Absolute)), Title = "Wall 05" });<br /> this.Datas.Add(new Data { BitmapImage = new BitmapImage(new Uri("ms-appx:///Assets/pic02.jpg", UriKind.Absolute)), Title = "Wall 06" });<br /> this.Datas.Add(new Data { BitmapImage = new BitmapImage(new Uri("ms-appx:///Assets/pic03.jpg", UriKind.Absolute)), Title = "Wall 07" });<br /> }<br /> </code></pre>
<p>&nbsp;</p>
<h2>实现方法</h2>
<p>&nbsp;</p>
<p>当数据源发生变化的时候，我使用依赖属性里面的一个回调方法来重新建立绑定。请参考我定义的ItemSourceChangedCallback函数：</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">/// &lt;summary&gt;<br /> /// Items source : Better if ObservableCollection :)<br /> /// &lt;/summary&gt;<br /> public IEnumerable&lt;Object&gt; ItemsSource<br /> {<br /> get { return (IEnumerable&lt;Object&gt;)GetValue(ItemsSourceProperty); }<br /> set { SetValue(ItemsSourceProperty, value); }<br /> }<br /> <br /> // Using a DependencyProperty as the backing store for ItemsSource. <br /> //This enables animation, styling, binding, etc...<br /> public static readonly DependencyProperty ItemsSourceProperty =<br /> DependencyProperty.Register("ItemsSource",<br /> typeof(IEnumerable&lt;Object&gt;),<br /> typeof(LightStone),<br /> new PropertyMetadata(0, ItemsSourceChangedCallback));<br /> </code></pre>
<p>&nbsp;</p>
<p>这个函数允许我可以用自己的逻辑来添加或者删除一个或者多个列表项目</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">private static void ItemsSourceChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)<br /> {<br /> if (args.NewValue == null)<br /> return;<br /> <br /> if (args.NewValue == args.OldValue)<br /> return;<br /> <br /> LightStone lightStone = dependencyObject as LightStone;<br /> <br /> if (lightStone == null)<br /> return;<br /> <br /> var obsList = args.NewValue as INotifyCollectionChanged;<br /> <br /> if (obsList != null)<br /> {<br /> obsList.CollectionChanged += (sender, eventArgs) =&gt;<br /> {<br /> switch (eventArgs.Action)<br /> {<br /> case NotifyCollectionChangedAction.Remove:<br /> foreach (var oldItem in eventArgs.OldItems)<br /> {<br /> for (int i = 0; i &lt; lightStone.internalList.Count; i++)<br /> {<br /> var fxElement = lightStone.internalList[i] as FrameworkElement;<br /> if (fxElement == null || fxElement.DataContext != oldItem) continue;<br /> lightStone.RemoveAt(i);<br /> }<br /> }<br /> <br /> break;<br /> case NotifyCollectionChangedAction.Add:<br /> foreach (var newItem in eventArgs.NewItems)<br /> lightStone.CreateItem(newItem, 0);<br /> break;<br /> }<br /> };<br /> }<br /> <br /> lightStone.Bind();<br /> }<br /> </code></pre>
<p>&nbsp;</p>
<h1>整合用户操作以及动画效果</h1>
<p>&nbsp;</p>
<h2>用户输入</h2>
<p>&nbsp;</p>
<p>为了能响应用户的输入，我们需要处理Point的各种事件。当然我们可以用GestureRecognizer这个方法，不过在我们的例子中尽量做到简化。</p>
<p>&nbsp;</p>
<p>目的很简单：如果用户用他的手指，鼠标或者触摸笔移动超过40px的时候，我们可以定义为用户想要去切换图片。</p>
<p>&nbsp;</p>
<p>下面是代码：</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">/// &lt;summary&gt;<br /> /// Initial pressed position<br /> /// &lt;/summary&gt;<br /> private void OnPointerPressed(object sender, PointerRoutedEventArgs args)<br /> {<br /> initialOffset = args.GetCurrentPoint(this).Position.X;<br /> }<br /> <br /> /// &lt;summary&gt;<br /> /// Calculate Behavior<br /> /// &lt;/summary&gt;<br /> private void OnPointerReleased(object sender, PointerRoutedEventArgs pointerRoutedEventArgs)<br /> {<br /> // Minimum amount to declare as a manipulation<br /> const int moveThreshold = 40;<br /> <br /> // last position<br /> var clientX = pointerRoutedEventArgs.GetCurrentPoint(this).Position.X;<br /> <br /> // Here is a "Tap on Item"<br /> if (!(Math.Abs(clientX - initialOffset) &gt; moveThreshold))<br /> return;<br /> <br /> isIncrementing = (clientX &lt; initialOffset);<br /> <br /> // Here is a manipulation<br /> if (clientX &lt; initialOffset)<br /> {<br /> this.SelectedIndex = (this.SelectedIndex &lt; (this.internalList.Count - 1))<br /> ? this.SelectedIndex + 1<br /> : this.SelectedIndex;<br /> <br /> }<br /> else if (this.SelectedIndex &gt; 0)<br /> {<br /> this.SelectedIndex--;<br /> }<br /> <br /> initialOffset = clientX;<br /> }<br /> </code></pre>
<p>&nbsp;</p>
<p>我没有使用Guesture来响应用户的触摸事件，而是使用了Tap事件。</p>
<p>&nbsp;</p>
<p>为了能获取到被Tap的项，我使用了UIElement.TranformToVisual这个方法：</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">var rect = child.TransformToVisual(this).TransformBounds(new Rect(0, 0, child.DesiredSize.Width, child.DesiredSize.Height));</code></pre>
<p>&nbsp;</p>
<p>这里是完整的代码：</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">/// &lt;summary&gt;<br /> /// Tap an element<br /> /// &lt;/summary&gt;<br /> private void OnTapped(object sender, TappedRoutedEventArgs args)<br /> {<br /> var positionX = args.GetPosition(this).X;<br /> for (int i = 0; i &lt; this.internalList.Count; i++)<br /> {<br /> var child = internalList[i];<br /> var rect = child.TransformToVisual(this).TransformBounds(new Rect(0, 0, child.DesiredSize.Width, child.DesiredSize.Height));<br /> <br /> if (!(positionX &gt;= rect.Left) || !(positionX &lt;= (rect.Left + rect.Width))) continue;<br /> <br /> isIncrementing = (i &gt; this.SelectedIndex);<br /> <br /> this.SelectedIndex = i;<br /> return;<br /> }<br /> }<br /> </code></pre>
<p>&nbsp;</p>
<h2>动画效果</h2>
<p>&nbsp;</p>
<p>UIElement.Projection给我们提供了一个非常好的特效。</p>
<p>&nbsp;</p>
<p>当我们需要做投影效果设置的时候，我们可以考虑是否是3D效果的投影，或者是平板投影的效果。在这里，我使用了平板投影的特效。</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/0358.8.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/0358.8.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/0358.8.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/0358.8.png" alt="" border="0" /></a></p>
<p>&nbsp;我们可以仅通过一个StoryBoard来完成XAML的一个动画特效：</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">/// &lt;summary&gt;<br /> /// Update all positions. Launch every animations on all items with a unique StoryBoard<br /> /// &lt;/summary&gt;<br /> private void UpdatePosition()<br /> {<br /> if (storyboard.GetCurrentState() != ClockState.Stopped)<br /> {<br /> storyboard.SkipToFill();<br /> storyboard.Stop();<br /> storyboard = new Storyboard();<br /> }<br /> <br /> <br /> isUpdatingPosition = true;<br /> <br /> for (int i = 0; i &lt; this.internalList.Count; i++)<br /> {<br /> var item = internalList[i];<br /> <br /> PlaneProjection planeProjection = item.Projection as PlaneProjection;<br /> <br /> if (planeProjection == null)<br /> continue;<br /> <br /> // Get properties<br /> var depth = (i == this.SelectedIndex) ? 0 : -(this.Depth);<br /> var rotation = (i == this.SelectedIndex) ? 0 : ((i &lt; this.SelectedIndex) ? Rotation : -Rotation);<br /> var offsetX = (i == this.SelectedIndex) ? 0 : (i - this.SelectedIndex) * desiredWidth;<br /> var translateY = TranslateY;<br /> var translateX = (i == this.SelectedIndex) ? 0 : ((i &lt; this.SelectedIndex) ? -TranslateX : TranslateX);<br /> <br /> // CenterOfRotationX<br /> // to Get good center of rotation for SelectedIndex, must know the animation behavior<br /> int centerOfRotationSelectedIndex = isIncrementing ? 1 : 0;<br /> var centerOfRotationX = (i == this.SelectedIndex) ? centerOfRotationSelectedIndex : ((i &gt; this.SelectedIndex) ? 1 : 0);<br /> planeProjection.CenterOfRotationX = centerOfRotationX;<br /> <br /> // Dont animate all items<br /> var inf = this.SelectedIndex - (MaxVisibleItems * 2);<br /> var sup = this.SelectedIndex + (MaxVisibleItems * 2);<br /> <br /> if (i &lt; inf || i &gt; sup)<br /> continue;<br /> <br /> // Zindex and Opacity<br /> var deltaFromSelectedIndex = Math.Abs(this.SelectedIndex - i);<br /> int zindex = (this.internalList.Count * 100) - deltaFromSelectedIndex;<br /> Canvas.SetZIndex(item, zindex);<br /> Double opacity = 1d - (Math.Abs((Double)(i - this.SelectedIndex) / (MaxVisibleItems + 1)));<br /> <br /> var newVisibility = deltaFromSelectedIndex &gt; MaxVisibleItems<br /> ? Visibility.Collapsed<br /> : Visibility.Visible;<br /> <br /> // Item already present<br /> if (item.Visibility == newVisibility)<br /> {<br /> storyboard.AddAnimation(item, TransitionDuration, rotation, "(UIElement.Projection).(PlaneProjection.RotationY)", this.EasingFunction);<br /> storyboard.AddAnimation(item, TransitionDuration, depth, "(UIElement.Projection).(PlaneProjection.GlobalOffsetZ)", this.EasingFunction);<br /> storyboard.AddAnimation(item, TransitionDuration, translateX, "(UIElement.Projection).(PlaneProjection.GlobalOffsetX)", this.EasingFunction);<br /> storyboard.AddAnimation(item, TransitionDuration, offsetX, "(UIElement.Projection).(PlaneProjection.LocalOffsetX)", this.EasingFunction);<br /> storyboard.AddAnimation(item, TransitionDuration, translateY, "(UIElement.Projection).(PlaneProjection.GlobalOffsetY)", this.EasingFunction);<br /> storyboard.AddAnimation(item, TransitionDuration, opacity, "Opacity", this.EasingFunction);<br /> }<br /> else if (newVisibility == Visibility.Visible)<br /> {<br /> // This animation will occur in the ArrangeOverride() method<br /> item.Visibility = newVisibility;<br /> item.Opacity = 0d;<br /> }<br /> else if (newVisibility == Visibility.Collapsed)<br /> {<br /> storyboard.AddAnimation(item, TransitionDuration, rotation, "(UIElement.Projection).(PlaneProjection.RotationY)", this.EasingFunction);<br /> storyboard.AddAnimation(item, TransitionDuration, depth, "(UIElement.Projection).(PlaneProjection.GlobalOffsetZ)", this.EasingFunction);<br /> storyboard.AddAnimation(item, TransitionDuration, translateX, "(UIElement.Projection).(PlaneProjection.GlobalOffsetX)", this.EasingFunction);<br /> storyboard.AddAnimation(item, TransitionDuration, offsetX, "(UIElement.Projection).(PlaneProjection.LocalOffsetX)", this.EasingFunction);<br /> storyboard.AddAnimation(item, TransitionDuration, translateY, "(UIElement.Projection).(PlaneProjection.GlobalOffsetY)", this.EasingFunction);<br /> storyboard.AddAnimation(item, TransitionDuration, 0d, "Opacity", this.EasingFunction);<br /> storyboard.Completed += (sender, o) =&gt;<br /> item.Visibility = Visibility.Collapsed;<br /> }<br /> }<br /> <br /> // When storyboard completed, Invalidate<br /> storyboard.Completed += (sender, o) =&gt;<br /> {<br /> this.isUpdatingPosition = false;<br /> this.InvalidateArrange();<br /> };<br /> <br /> storyboard.Begin();<br /> }<br /> </code></pre>
<p><span style="font-size: small;"><span style="line-height: 107%; font-family: 宋体;" lang="ZH-CN">为了让动画效果更加便捷地被使用，我们可以设置一个</span><span style="line-height: 107%; font-family: Calibri, sans-serif;">DoubleAnimation</span><span style="line-height: 107%; font-family: 宋体;" lang="ZH-CN">：</span></span></p>
<pre class="scroll"><code class="csharp">public static void AddAnimation(this Storyboard storyboard, DependencyObject element,<br /> int duration,double fromValue, double toValue, String propertyPath,<br /> EasingFunctionBase easingFunction = null)<br /> {<br /> DoubleAnimation timeline = new DoubleAnimation();<br /> timeline.From = fromValue;<br /> timeline.To = toValue;<br /> timeline.Duration = TimeSpan.FromMilliseconds(duration);<br /> if (easingFunction != null)<br /> timeline.EasingFunction = easingFunction;<br /> <br /> storyboard.Children.Add(timeline);<br /> <br /> Storyboard.SetTarget(timeline, element);<br /> Storyboard.SetTargetProperty(timeline, propertyPath);<br /> }<br /> </code></pre>
<h1>优化处理</h1>
<p>为了保证我们的控件可以在配置较低的机器上运行无阻，我们必须保证只处理那些可见的图片，并且仅仅对那些图片使用动画效果。</p>
<p>为了实现这个目标，我们把不可见的图片（Opacity为0）从控件中删除，当然，有需要的时候再显示出现。</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">// Dont animate all items<br /> var inf = this.SelectedIndex - (MaxVisibleItems * 2);<br /> var sup = this.SelectedIndex + (MaxVisibleItems * 2);<br /> <br /> if (i &lt; inf || i &gt; sup)<br /> continue;<br /> <br /> // Get if item is visible or not<br /> var newVisibility = deltaFromSelectedIndex &gt; MaxVisibleItems<br /> ? Visibility.Collapsed<br /> : Visibility.Visible;<br /> </code></pre>
<p>&nbsp;</p>
<p>同时，使用ArrangOverride方法，我们可以来检查一个图片是否出现。</p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">// Items appears<br /> if (container.Visibility == Visibility.Visible &amp;&amp; container.Opacity == 0d)<br /> {<br /> localStoryboard.AddAnimation(container, TransitionDuration, rotation, "(UIElement.Projection).(PlaneProjection.RotationY)", this.EasingFunction);<br /> localStoryboard.AddAnimation(container, TransitionDuration, depth, "(UIElement.Projection).(PlaneProjection.GlobalOffsetZ)", this.EasingFunction);<br /> localStoryboard.AddAnimation(container, TransitionDuration, translateX, "(UIElement.Projection).(PlaneProjection.GlobalOffsetX)", this.EasingFunction);<br /> localStoryboard.AddAnimation(container, TransitionDuration, offsetX, "(UIElement.Projection).(PlaneProjection.LocalOffsetX)", this.EasingFunction);<br /> localStoryboard.AddAnimation(container, TransitionDuration, translateY, "(UIElement.Projection).(PlaneProjection.GlobalOffsetY)", this.EasingFunction);<br /> localStoryboard.AddAnimation(container, TransitionDuration, 0, opacity, "Opacity", this.EasingFunction);<br /> }<br /> else<br /> {<br /> container.Opacity = opacity<br /> }<br /> </code></pre>
<p>大家可以在这里找到对应的例子：<a title="LightStone.zip" href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/40/34/52/LightStone.zip" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-40-34-52/LightStone.zip">LightStone.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>向windows 8.1 store app中添加语音朗读</title>
      <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/windows-8-1-store-app</link>
      <pubDate>Fri, 30 May 2014 00:02:00 GMT</pubDate>
      <dc:creator><![CDATA[MingXu-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows8devsupport/2014/05/30/windows-8-1-store-app/</guid>
      <description><![CDATA[在Windows8.1 没有发布之前，也就是在Windows 8版本的时代，很多人会问到这样一个问题即如何在windows store app程序中将文本转换成语音形式。很遗憾的是在Windows...]]></description>
      <content:encoded><![CDATA[<p>在Windows8.1 没有发布之前，也就是在Windows 8版本的时代，很多人会问到这样一个问题即如何在windows store app程序中将文本转换成语音形式。很遗憾的是在Windows 8版本中，并没有提供一个直接实现此功能的API，且.Net 里面的System.Speech 类等一系列的API在windows 8 store app中并不被支持。我们会建议在程序中使用Bing Translator Service或者寻求第三方的API如Google TTS。无论是以上任何一种方式，实现都会显得过于复杂，且需要开发者花费一段时间来熟悉和掌握第三方的API。</p>
<p>&nbsp;&nbsp;&nbsp; 随着windows 8.1 版本的发布，这个问题已经迎刃而解了，您仅仅需要几行代码就可以使您的程序开口说话。</p>
<p>&nbsp;&nbsp;&nbsp; 您需要一个新的API：<a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.aspx">Windows.Media.SpeechSynthesis namespace</a>。在这个命名空间下有三个类，即<a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.speechsynthesisstream.aspx"><strong>SpeechSynthesisStream</strong></a>，<a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.speechsynthesizer.aspx"><strong>SpeechSynthesizer</strong></a>和<a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.voiceinformation.aspx"><strong>VoiceInformation</strong></a>。其中<a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.speechsynthesizer.aspx"><strong>SpeechSynthesizer</strong></a>提供了对已安装的语音合成引擎的功能的访问。<a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.speechsynthesisstream.aspx"><strong>SpeechSynthesisStream</strong></a>可以对音频流数据进行读写操作。<a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.voiceinformation.aspx"><strong>VoiceInformation</strong></a>可以获得已安装的语音的信息。 利用这三个类, 您就可以在windows store app中来让您的程序开口说话。</p>
<p>&nbsp;&nbsp;&nbsp; 下面有一个简单的例子,该例子可以朗读指定的文本以及朗读SSML文档。</p>
<p>&nbsp;&nbsp;&nbsp; 以下是示例项目的界面：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/8551.1.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/8551.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/8551.1.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/8551.1.png" alt="" border="0" /></a></p>
<p>&nbsp;其中在该页面添加了一个MediaElement控件，用它来播放语音流：&nbsp;</p>
<pre class="scroll"><code class="html">&lt;MediaElement Name="media" Grid.Row="0"/&gt;</code></pre>
<p>&nbsp;点击LoadText按钮可以打开一个存储在电脑里面的Text文件：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4722.2.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4722.2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4722.2.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4722.2.png" alt="" border="0" /></a></p>
<p>点击SpeakText按钮即可以朗读该文本文件里面的文字内容，实现代码如下：</p>
<pre class="scroll"><code class="csharp">private async void Button_Click_1(object sender, RoutedEventArgs e)<br /> {<br /> SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync(textbox.Text.ToString());<br /> this.media.AutoPlay = true;<br /> this.media.SetSource(stream, stream.ContentType);<br /> this.media.Play(); <br /> }<br /> </code></pre>
<p>其中synth是指已经定义的<a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.speechsynthesizer.aspx"><strong>SpeechSynthesizer</strong></a>类:</p>
<pre class="scroll"><code class="csharp">SpeechSynthesizer synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();</code></pre>
<p><a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.speechsynthesizer.synthesizetexttostreamasync.aspx">SynthesizeTextToStreamAsync</a>方法是将文本内容转化为音频流。</p>
<p align="left">界面中Combobox的列表显示的是本地已安装的语音列表，即通过<a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.voiceinformation.aspx"><strong>VoiceInformation</strong></a>可以获得该列表：</p>
<pre class="scroll"><code class="csharp">private void VoiceChooser_Initialize()<br /> {<br /> // get all of the installed voices<br /> var voices = Windows.Media.SpeechSynthesis.SpeechSynthesizer.AllVoices;<br /> <br /> // get the currently selected voice<br /> VoiceInformation currentVoice = this.synth.Voice;<br /> <br /> foreach (VoiceInformation voice in voices)<br /> {<br /> ComboBoxItem item = new ComboBoxItem();<br /> item.Name = voice.DisplayName;<br /> item.Tag = voice;<br /> item.Content = voice.DisplayName;<br /> this.VoiceChooser.Items.Add(item);<br /> <br /> // check to see if this is the current voice, so that we can set it to be selected<br /> if (currentVoice.Id == voice.Id)<br /> {<br /> item.IsSelected = true;<br /> this.VoiceChooser.SelectedItem = item;<br /> }<br /> }<br /> }<br /> </code></pre>
<p>用户通过选择不同的Combobox Item，可以用不同的语音形式来朗读该文本：</p>
<pre class="scroll"><code class="csharp">private void VoiceChooser_SelectionChanged(object sender, SelectionChangedEventArgs e)<br /> {<br /> ComboBoxItem item = (ComboBoxItem)this.VoiceChooser.SelectedItem;<br /> VoiceInformation voice = (VoiceInformation)item.Tag;<br /> this.synth.Voice = voice;<br /> }<br /> </code></pre>
<p>点击LoadSSML按钮可以显示一个SSML文件的内容：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/3482.3.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/3482.3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/3482.3.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/3482.3.png" alt="" border="0" /></a></p>
<p>点击SpeakSSML文件可以朗读SSML文件：</p>
<pre class="scroll"><code class="csharp">private async void speakssml_Click(object sender, RoutedEventArgs e)<br /> {<br /> SpeechSynthesisStream stream = await synth.SynthesizeSsmlToStreamAsync(textbox.Text.ToString());<br /> this.media.AutoPlay = true;<br /> this.media.SetSource(stream, stream.ContentType);<br /> this.media.Play();<br /> <br /> }<br /> </code></pre>
<p>&nbsp;SSML文件如下：&nbsp;</p>
<pre class="scroll"><code class="html">&lt;?xml version="1.0"?&gt;<br /> &lt;speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis"<br /> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br /> xsi:schemaLocation="http://www.w3.org/2001/10/synthesis<br /> http://www.w3.org/TR/speech-synthesis/synthesis.xsd"<br /> xml:lang="en-US"&gt; <br /> &lt;voice gender="female" age="6"&gt;Mary had a little lamb,<br /> &lt;/voice&gt;<br /> &lt;voice gender="female"&gt;<br /> Its fleece was white as snow.<br /> &lt;/voice&gt;<br /> &lt;!-- processor-specific voice selection --&gt;<br /> &lt;voice name="Mike"&gt;I want to be like Mike.&lt;/voice&gt;<br /> &lt;voice gender="female"&gt; <br /> Any female voice here.<br /> &lt;p xml:lang="zh-cn"&gt;我是中国人。&lt;/p&gt;<br /> &lt;/voice&gt;<br /> <br /> &lt;/speak&gt;<br /> </code></pre>
<p>&nbsp;其中<a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.speechsynthesis.speechsynthesizer.synthesizessmltostreamasync.aspx"><strong>SynthesizeSsmlToStreamAsync</strong></a>方法是将SSML内容转化为可以播放的音频流。</p>
<p align="left">&nbsp;&nbsp;&nbsp; 需要注意的是一般的windows 8.1系统中默认只安装了Microsoft David Desktop - English (United States), Microsoft Hazel Desktop - English (United States),Microsoft Zira Desktop - English (United States) 这三种语音，如果您想朗读上面SSML文件里面的中文，那么您需要另外在您的系统中安装Microsoft Huihui Desktop - Chinese (Simplified) 这个语音。</p>
<p align="left">&nbsp;&nbsp;&nbsp; 以下链接可以下载该示例项目的完整代码：</p>
<p align="left">&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://1drv.ms/1jPYjjx">http://1drv.ms/1jPYjjx</a>&nbsp;&nbsp;&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>如何制作一个Photo应用</title>
      <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/photo</link>
      <pubDate>Sun, 11 May 2014 09:03:00 GMT</pubDate>
      <dc:creator><![CDATA[MingXu-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows8devsupport/2014/05/11/photo/</guid>
      <description><![CDATA[在Windows 8.0版本的时代，很多人会问，系统自带的Photo是不是有特权？比如说在打开一张图片的同时，可以有权限访问整个文件夹，而我们自己写的程序没有办法实现这个功能。
在Windows...]]></description>
      <content:encoded><![CDATA[<p>在Windows 8.0版本的时代，很多人会问，系统自带的Photo是不是有特权？比如说在打开一张图片的同时，可以有权限访问整个文件夹，而我们自己写的程序没有办法实现这个功能。</p>
<p>在Windows 8.1 版本，我们可以通过自己的代码来实现这个功能了。</p>
<p>您需要一个新的API，在Windows 8.1中，从文件启动的选项中新增了一个API叫做：<a title="NeighboringFilesQuery property" href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.applicationmodel.activation.fileactivatedeventargs.neighboringfilesquery.aspx">NeighboringFilesQuery property</a>，通过这个方式可以获得同文件夹下所有的文件。</p>
<p>注意：您需要开启Appmanifest里面Capabilities中的Picture Library以获得对图片库的支持。</p>
<p>举个例子,您可以做一个媒体播放器，比如说播放不同的音乐文件，当然这个得看您应用的需求。</p>
<p>这里我做了一个简单的浏览图片的Demo供大家参考，通过右键选择使用我们的应用打开图片：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4667.photoSample1.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4667.photoSample1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4667.photoSample1.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4667.photoSample1.png" alt="" border="0" /></a></p>
<p>第一张图：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7573.PhotoSample2.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7573.PhotoSample2.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7573.PhotoSample2.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7573.PhotoSample2.jpg" alt="" border="0" /></a></p>
<p>第二张图片：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4263.PhotoSample3.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4263.PhotoSample3.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/4263.PhotoSample3.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/4263.PhotoSample3.jpg" alt="" border="0" /></a>&nbsp;</p>
<p>相关的代码如下：</p>
<p>App.xaml.cs中定义一个以文件访问的入口</p>
<pre class="scroll"><code class="csharp">protected override void OnFileActivated(FileActivatedEventArgs e)<br /> {<br /> Frame rootFrame = Window.Current.Content as Frame;<br /> if (rootFrame == null)<br /> {<br /> rootFrame = new Frame();<br /> Window.Current.Content = rootFrame;<br /> }<br /> <br /> if (rootFrame.Content == null)<br /> {<br /> if (!rootFrame.Navigate(typeof(MainPage)))<br /> {<br /> throw new Exception("Failed to create initial page");<br /> }<br /> }<br /> <br /> var page = rootFrame.Content as MainPage;<br /> if (page != null)<br /> {<br /> page.FileEvent = e;<br /> }<br /> <br /> // Ensure the current window is active<br /> Window.Current.Activate();<br /> }<br /> </code></pre>
<p>在MainPage.xaml.cs中的页面加载完成(Loaded)事件中做一些处理</p>
<pre class="scroll"><code class="cplusplus">public async void Page_Loaded(object sender, RoutedEventArgs e)<br /> {<br /> try<br /> {<br /> var fileList = await _fileEventArgs.NeighboringFilesQuery.GetFilesAsync();<br /> foreach (StorageFile file in fileList)<br /> {<br /> IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read);<br /> BitmapImage bitmapImage = new BitmapImage();<br /> bitmapImage.SetSource(fileStream);<br /> Image displayImage = new Image();<br /> displayImage.Source = bitmapImage;<br /> imagegallery.Items.Add(displayImage);<br /> }<br /> }<br /> catch (Exception k)<br /> {<br /> txt.Text = "需要通过右键图片选择以ImageGallery打开的方式来运行程序。";<br /> }<br /> }<br /> </code></pre>
<p>我把代码上传到了Skydrive中，大家可以下载参考一下：<a href="http://1drv.ms/1nuFiDs">http://1drv.ms/1nuFiDs</a></p>]]></content:encoded>
    </item>
    <item>
      <title>用Windows JavaScript 库创建自定义控件</title>
      <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/windows-javascript</link>
      <pubDate>Sun, 11 May 2014 08:22:00 GMT</pubDate>
      <dc:creator><![CDATA[MingXu-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows8devsupport/2014/05/11/windows-javascript/</guid>
      <description><![CDATA[如果您已经用Javascript开发过windows store app程序，那么您肯定使用过Windows Javascript...]]></description>
      <content:encoded><![CDATA[<p>如果您已经用Javascript开发过windows store app程序，那么您肯定使用过Windows Javascript 库（WinJS）。这个库提供了一组CSS样式、Javascript控件以及工具, 可以帮助您快速地创建符合UX准则的windows store app。 这里工具是一组函数，您可以使用这组函数来创建自定义控件。</p>
<p>您可以使用任何您喜欢的模式或者库来编写JavaScript控件，WinJS提供的库函数仅仅是您的选择之一。使用WinJS库创建自定义控件的一个最大的好处是该自定义控件与其他的控件能够协同工作。且这种模式与WinJS命名空间的任何控件的创建模式是一致的。</p>
<p>在这篇文章中，我将会介绍如何使用winJS库构建自定义的控件。如果您对XAML控件的开发同样感兴趣的话您可以关注后续的博客。</p>
<p>首先，让我们来了解一下如何在页面里包含WinJS控件。有两种不同的方式：第一种是命令式的（即单独使用JavaScript）；另一种是声明式的（即使用HTML元素附加的属性添加控件到HTML页面）。后一种方式提供了设计时的体检，如可以直接从工具箱拖动控件到页面，具体您可以参考MSDN的文档：<a href="http://msdn.microsoft.com/en-US/library/windows/apps/hh465493" target="_blank">MSDN quick start for<br />adding WinJS controls and styles</a></p>
<p>在本节中，我将会详细向您介绍如何在一个页面生成JavaScript控件，具体包含以下几个步骤：</p>
<p>1. 在您的HTML页面添加WinJS引用，因为您的控件需要用到这些文件中的API</p>
<p>Microsoft.WinJS.1.0/js/base.js</p>
<p>Microsoft.WinJS.1.0/js/ui.js</p>
<p>2. 在上述代码后，添加包含您定义的控件的脚本文件的引用：</p>
<pre class="scroll"><code class="html">&lt;script src="js/hello-world-control.js"&gt;&lt;/script&gt;</code></pre>
<ol>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</ol>
<p>3.在您的应用程序的JavaScript代码中调用<a href="http://msdn.microsoft.com/en-US/library/windows/apps/hh440975">WinJS.UI.processAll()</a>函数。该函数可以解析HTML和对页面上控件进行声明和实例化。如果您在创建windows store app的时候用的是Visual studio上所提供的模版，您会发现该函数已经在Default.js内自动调用。</p>
<p>4.以下列方式在页面使用控件：</p>
<pre class="scroll"><code class="html">&lt;div data-win-control="Contoso.UI.HelloWorld" data-win-options="{blink: true}"&gt;&lt;/div&gt;</code></pre>
<p><strong>一个简单的</strong><strong>JavaScript</strong><strong>控件</strong><strong></strong></p>
<p>现在我们来创建一个非常简单的控件：Hello World控件。首先在您的项目中添加一个hello-world-control.js文件并将下面的JavaScript代码添加到该文件：</p>
<pre class="scroll"><code class="csharp">function HelloWorld(element) {<br /> <br /> if (element) {<br /> <br /> element.textContent = "Hello, World!";<br /> <br /> }<br /> <br /> };<br /> <br /> WinJS.Utilities.markSupportedForProcessing(HelloWorld);</code></pre>
<p>然后在您的主页面以如下方式将该控件添加到页面：</p>
<pre class="scroll"><code class="html">&lt;div data-win-control="HelloWorld"&gt;&lt;/div&gt;</code></pre>
<p>当您运行这段程序的时候，您会在主页面看到该控件已经被加载并且在页面呈现&ldquo;Hello,World!&rdquo;文本</p>
<p align="left">这段代码的特殊之处是调用了WinJS里面的<a href="http://msdn.microsoft.com/en-us/library/windows/apps/Hh967819.aspx" target="_blank">WinJS.Utilities.markSupportedForProcessing</a>函数，您可以在HTML元素中直接调用这个函数。即相当于告诉WinJS您向页面添加了可信任的内容。更多信息请参考MSDN文档的介绍：<a href="http://msdn.microsoft.com/en-us/library/windows/apps/Hh967819.aspx" target="_blank">WinJS.Utilities.markSupportedForProcessing</a></p>
<p><strong>为什么使用</strong><strong>WinJS</strong><strong>工具、库来创建控件</strong><strong></strong></p>
<p>上面代码只是向您介绍怎么来创建JavaScript控件，但是并没有使用到WinJS. 现在请看下面的代码段，该代码段声明了一个复杂的控件，其中包括事件、可配置的选项以及公共方法等：</p>
<pre class="scroll"><code class="csharp">(function (Contoso) {<br /> Contoso.UI = Contoso.UI || {};<br /> <br /> Contoso.UI.HelloWorld = function (element, options) {<br /> this.element = element;<br /> this.element.winControl = this;<br /> <br /> this.blink = (options &amp;&amp; options.blink) ? true : false;<br /> this._onblink = null;<br /> this._blinking = 0;<br /> <br /> element.textContent = "Hello, World!";<br /> };<br /> <br /> var proto = Contoso.UI.HelloWorld.prototype;<br /> <br /> proto.doBlink = function () {<br /> var customEvent = document.createEvent("Event");<br /> customEvent.initEvent("blink", false, false);<br /> <br /> if (this.element.style.display === "none") {<br /> this.element.style.display = "block";<br /> } else {<br /> this.element.style.display = "none";<br /> }<br /> <br /> this.element.dispatchEvent(customEvent);<br /> };<br /> <br /> proto.addEventListener = function (type, listener, useCapture) {<br /> this.element.addEventListener(type, listener, useCapture);<br /> };<br /> <br /> proto.removeEventListener = function (type, listener, useCapture) {<br /> this.element.removeEventListener(type, listener, useCapture);<br /> };<br /> <br /> Object.defineProperties(proto, {<br /> blink: {<br /> get: function () {<br /> return this._blink;<br /> },<br /> <br /> set: function (value) {<br /> if (this._blinking) {<br /> clearInterval(this._blinking);<br /> this._blinking = 0;<br /> }<br /> this._blink = value;<br /> if (this._blink) {<br /> this._blinking = setInterval(this.doBlink.bind(this), 500);<br /> }<br /> },<br /> enumerable: true,<br /> configurable: true<br /> },<br /> <br /> onblink: {<br /> get: function () {<br /> return this._onblink;<br /> },<br /> set: function (eventHandler) {<br /> if (this._onblink) {<br /> this.removeEventListener("blink", this._onblink);<br /> this._onblink = null;<br /> }<br /> this._onblink = eventHandler;<br /> this.addEventListener("blink", this._onblink);<br /> }<br /> }<br /> });<br /> <br /> WinJS.Utilities.markSupportedForProcessing(Contoso.UI.HelloWorld);<br /> })(window.Contoso = window.Contoso || {});<br /> </code></pre>
<p>许多开发者是通过上述方式来创建控件（即使用匿名函数、构造函数、属性、自定义事件），如果您的开发团队觉得使用这种方式很得心应手的话，那么您可以继续使用这个方法。但是对于大多数的开发人员来说，这些代码显得过于复杂。且许多的Web开发者并不熟悉此项技术。使用库，可以简化此类代码的编写。</p>
<p>除了提高程序的可读性，WinJS和其他的库也注意到了许多微妙的问题（如有效利用原型、属性和自定义事件）。通过这些库的使用，可以优化内存的使用率并帮您避免一些常见的错误。WinJS库就是这样的一个例子，但是使不使用的选择权在您。有关库给您创建控件带来的简便，建议您在看完这篇博客后重新来审视本节中的代码并且与使用WinJS后的代码来进行比较。</p>
<p><strong>基于</strong><strong>WinJS</strong><strong>的</strong><strong>JavaScript</strong><strong>控件</strong><strong></strong></p>
<p>下面是一个用WinJS来创建JavaScript控件的一个小的例子：</p>
<pre class="scroll"><code class="html">(function () {<br /> "use strict";<br /> <br /> var controlClass = WinJS.Class.define(<br /> function Control_ctor(element) {<br /> this.element = element || document.createElement("div");<br /> this.element.winControl = this;<br /> <br /> this.element.textContent = "Hello, World!"<br /> });<br /> WinJS.Namespace.define("Contoso.UI", {<br /> HelloWorld: controlClass<br /> });<br /> })();<br /> </code></pre>
<p>并在页面中以如下方式声明控件：</p>
<pre class="scroll"><code class="html">&lt;div data-win-control="Contoso.UI.HelloWorld"&gt;&lt;/div&gt;</code></pre>
<p>也许您并不熟悉这些，尤其是第一次接触WinJS，下面来我们来做下详细的解释。</p>
<p>1. 将代码包含在一个立即执行的函数中，这是JavaScript常见的模式：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<pre class="scroll"><code class="js">(function () {<br /> <br /> &hellip;<br /> <br /> })();</code></pre>
<p>这样做的目的是确保我们的代码是自包含的，并且不会创建任何无意义的全局变量，这是一个最佳的模式。</p>
<p>2. 函数起始处的&ldquo;use strict&rdquo;声明意味着使用<a href="http://msdn.microsoft.com/en-us/library/ie/hh673540(v=vs.85).aspx" target="_blank">ECMAScript 5 strict mode</a>这个模式。这种做法是windows store app 的一个最佳的模式，它可以提高错误的检查效率以及与JavaScript的下一个版本的兼容性。</p>
<p>3. 现在我们来解释一些WinJS独有的代码。<strong>WinJS.Class.define()</strong>用来创建一个类，这个类可以帮助我们调用<strong>markSupportedForProcessing()</strong>函数，也可以简化对属性的创建。</p>
<p>4. 定义了一个名为<strong>Control_ctor</strong>的构造函数。<strong>WinJS.UI.processAll</strong><strong>（）</strong>是在Default.js中调用的，它会扫描页面上所有<strong>data-win-control</strong>属性中的内容, 找到我们的控件, 调用构造函数。</p>
<p>5. 在构造函数中，对页面元素的引用被存储在element这个参数中。然后把当前这个对象的实例（this）存储在element的winControl属性中。</p>
<ul>
<li>&middot;element || document.createElement("div") 用来支持命令式模型, 允许用户之后将一个控件附加在页面的某个元素上</li>
<li>&middot;这样维护页面元素的引用以及通过设置<strong>element.winControl</strong>来将该元素作为控件的一个引用来说是一个很好的方式。您不必担心对DOM对象循环引用会造成内存泄露，因为Internet Explorer 10会帮您关注这些。</li>
<li>&middot;该构造函数可以定义该控件的文本并将其设置为&rdquo;Hello,World!&rdquo;。</li>
</ul>
<p>6.<strong> WinJS.Namespace.define()</strong>函数能使该控件是公共的且能被您项目中任何代码访问到。如果您不使用该函数，那么您需要在内联函数之外使用全局命名空间。</p>
<p><strong>定义控件的</strong><strong>options</strong></p>
<p>将可配置的选项添加到自定义控件中会使我们的例子显得更有趣。下面的例子中会添加一个选项来控制内容以闪烁的形式出现。</p>
<pre class="scroll"><code class="js">var controlClass = WinJS.Class.define(<br /> function Control_ctor(element, options) {<br /> this.element = element || document.createElement("div");<br /> this.element.winControl = this;<br /> <br /> // Set option defaults<br /> this._blink = false;<br /> <br /> // Set user-defined options<br /> WinJS.UI.setOptions(this, options);<br /> <br /> element.textContent = "Hello, World!"<br /> },<br /> {<br /> _blinking: 0,<br /> <br /> blink: {<br /> get: function () {<br /> return this._blink;<br /> },<br /> <br /> set: function (value) {<br /> if (this._blinking) {<br /> clearInterval(this._blinking);<br /> this._blinking = 0;<br /> }<br /> this._blink = value;<br /> if (this._blink) {<br /> this._blinking = setInterval(this._doBlink.bind(this), 500);<br /> }<br /> }<br /> },<br /> <br /> _doBlink: function () {<br /> if (this.element.style.display === "none") {<br /> this.element.style.display = "block";<br /> } else {<br /> this.element.style.display = "none";<br /> }<br /> },<br /> });<br /> <br /> WinJS.Namespace.define("Contoso.UI", {<br /> HelloWorld: controlClass<br /> });<br /> </code></pre>
<p>接下来，我们将这个控件添加到页面，您可以在data-with-option属性里面配置以上选项：</p>
<pre class="scroll"><code class="html">&lt;div data-win-control="Contoso.UI.HelloWorld" data-win-options="{blink: true}"&gt;<br /> &lt;/div&gt;</code></pre>
<p>为了使控件支持可配置选项，我们对代码作了如下更改：</p>
<p>1. 该选项是作为构造函数的参数来传递给控件的</p>
<p>2. 该选项的默认值是该类的私有属性的值</p>
<p>3. 调用WinJs.UI.SetOptions()函数可以重写该选项的默认配置</p>
<p>4. 添加一个公共属性（名为blink）作为新的选项</p>
<p>5. 通过添加一个函数来将控件的文本与blink选项相关联，从而控制文本以闪烁的形式出现。</p>
<p>在此示例中担当重任的部分是对<a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh440978.aspx" target="_blank">WinJS.UI.setOptions()</a>函数的调用。该函数能将选项中每个字段的值赋值到目标对象，目标对象是该函数的第一个参数。</p>
<p>在上述例子中，我们通过data-with-options来将控件的blink选项值设置为&rdquo;true&rdquo;。通过在构造函数中对setOptions()函数的调用就可以将该值传递给控件。即我们定义了一个名为blink的属性并定义了setter函数。该setter函数会被setOptions()调用并且将blink属性值赋值到控件。</p>
<p><strong>为控件添加事件</strong><strong></strong></p>
<p>我们已将为控件添加了一个blink选项，现在我们来为控件添加一个事件，该事件在blink的属性值改变时触发。</p>
<pre class="scroll"><code class="js">var controlClass = WinJS.Class.define(<br /> function Control_ctor(element, options) {<br /> this.element = element || document.createElement("div");<br /> this.element.winControl = this;<br /> <br /> // Set option defaults<br /> this._blink = false;<br /> <br /> // Set user-defined options<br /> WinJS.UI.setOptions(this, options);<br /> <br /> element.textContent = "Hello, World!"<br /> },<br /> {<br /> _blinking: 0,<br /> _blinkCount: 0,<br /> <br /> blink: {<br /> get: function () {<br /> return this._blink;<br /> },<br /> <br /> set: function (value) {<br /> if (this._blinking) {<br /> clearInterval(this._blinking);<br /> this._blinking = 0;<br /> }<br /> this._blink = value;<br /> if (this._blink) {<br /> this._blinking = setInterval(this._doBlink.bind(this), 500);<br /> }<br /> }<br /> },<br /> <br /> _doBlink: function () {<br /> if (this.element.style.display === "none") {<br /> this.element.style.display = "block";<br /> } else {<br /> this.element.style.display = "none";<br /> }<br /> this._blinkCount++;<br /> this.dispatchEvent("blink", {<br /> count: this._blinkCount<br /> });<br /> },<br /> });<br /> <br /> WinJS.Namespace.define("Contoso.UI", {<br /> HelloWorld: controlClass<br /> });<br /> <br /> // Set up event handlers for the control<br /> WinJS.Class.mix(Contoso.UI.HelloWorld,<br /> WinJS.Utilities.createEventProperties("blink"),<br /> WinJS.UI.DOMEventMixin);<br /> </code></pre>
<p>现在我们给元素添加一个id，这样我们可以通过该id访问该元素。</p>
<pre class="scroll"><code class="html">&lt;div id="hello-world-with-events"<br /> data-win-control="Contoso.UI.HelloWorld"<br /> data-win-options="{blink: true}"&gt;<br /> &lt;/div&gt;</code></pre>
<p>添加一个事件监听器来监听&ldquo;blink&rdquo;事件：</p>
<pre class="scroll"><code class="js">$("hello-world-with-events").addEventListener("blink",<br /> function (event) {<br /> console.log("blinked element this many times: " + event.count);<br /> });<br /> </code></pre>
<p>&nbsp;当您运行这段代码的时候，您会在visual studio 的JS控制台窗口看到一条每隔500毫秒输出的消息。</p>
<p>以下四个更改使得控件支持这个行为：</p>
<p>1. 调用了<strong>WinJS.Class.mix</strong>(Contoso.UI.HelloWorld,WinJS.Utilities.createEventProperties("blink"));创建了一个&rdquo;onblink&rdquo;属性，用户可以通过后台代码改变它或者可以在html页面的声明中绑定它。</p>
<p>2. 对<strong>WinJS.Class.mix(Contoso.UI.HelloWorld, WinJS.UI.DOMEventMixin)</strong>的调用将addEventListener, removeEventListener, 与dispatchEvent函数添加到了控件。</p>
<p>3. 通过对that.dispatchEvent("blink", {element: that.element})的调用blink事件就会被触发。并且该自定义事件是由元素的某个字段创建的。</p>
<p>4. 附加事件处理程序以监听blink事件。且对dispatchEvent（）的调用仅仅在您已经在控件的构造函数中设置this.element时才会有效。</p>
<p><strong>创建公共事件</strong><strong></strong></p>
<p>下面我们来创建一个公共的函数即doBlink()函数来改变blink的值：</p>
<pre class="scroll"><code class="js">var controlClass = WinJS.Class.define(<br /> function Control_ctor(element, options) {<br /> this.element = element || document.createElement("div");<br /> this.element.winControl = this;<br /> <br /> // Set option defaults<br /> this._blink = false;<br /> <br /> // Set user-defined options<br /> WinJS.UI.setOptions(this, options);<br /> <br /> element.textContent = "Hello, World!"<br /> },<br /> {<br /> _blinking: 0,<br /> _blinkCount: 0,<br /> <br /> blink: {<br /> get: function () {<br /> return this._blink;<br /> },<br /> <br /> set: function (value) {<br /> if (this._blinking) {<br /> clearInterval(this._blinking);<br /> this._blinking = 0;<br /> }<br /> this._blink = value;<br /> if (this._blink) {<br /> this._blinking = setInterval(this.doBlink.bind(this), 500);<br /> }<br /> }<br /> },<br /> <br /> doBlink: function () {<br /> if (this.element.style.display === "none") {<br /> this.element.style.display = "block";<br /> } else {<br /> this.element.style.display = "none";<br /> }<br /> this._blinkCount++;<br /> this.dispatchEvent("blink", {<br /> count: this._blinkCount<br /> });<br /> },<br /> });<br /> WinJS.Namespace.define("Contoso.UI", {<br /> HelloWorld: controlClass<br /> });<br /> <br /> // Set up event handlers for the control<br /> WinJS.Class.mix(Contoso.UI.HelloWorld,<br /> WinJS.Utilities.createEventProperties("blink"),<br /> WinJS.UI.DOMEventMixin);<br /> </code></pre>
<p>如果您需要通过javascript来调用doBlink()函数，那么您需要引用该控件。如果您是命令式的创建该控件，那么您可能已经添加了该控件的引用。如果您是以声明性的方式来进行的，那么您可以通过html元素的winControl属性访问该控件。例如，你可以通过以下代码访问：</p>
<p>$("hello-world-with-events").winControl.doBlink();</p>
<p><strong>总结与回顾</strong><strong></strong></p>
<p>通过上面的讨论我们为建立自定义控件做了以下工作：</p>
<ol>
<li>将控件包含到页面</li>
<li>为控件创建options</li>
<li>为控件创建事件并响应该事件</li>
<li>为控件创建公共方法</li>
</ol>
<p>希望上述内容为您在windows store app创建基于JavaScript控件有一定的帮助。如果您有问题请到<a href="http://social.msdn.microsoft.com/Forums/windowsapps/zh-CN/home?forum=winstoreappzhcn">论坛</a>提问。</p>]]></content:encoded>
    </item>
    <item>
      <title>如何获取Windows Store App屏幕分辨率</title>
      <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/windows-store-app</link>
      <pubDate>Thu, 17 Apr 2014 02:47:00 GMT</pubDate>
      <dc:creator><![CDATA[MingXu-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows8devsupport/2014/04/17/windows-store-app/</guid>
      <description><![CDATA[论坛上有很多贴子在讨论Windows Store...]]></description>
      <content:encoded><![CDATA[<p>论坛上有很多贴子在讨论Windows Store App屏幕分辨率的问题，一般的想法是通过获取当前控制窗口的长宽，这样的做法的确可以在全屏模式下获取屏幕分辨率，但如果是处于非全屏状态，则获取不到当前屏幕的分辨率，只能获取当前窗口的长宽。</p>
<p>下图所示为获取的窗口长宽。</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/1882.WindowsStoreAppResolution.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/1882.WindowsStoreAppResolution.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/1882.WindowsStoreAppResolution.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/1882.WindowsStoreAppResolution.png" alt="" border="0" /></a></p>
<p>不过我们还有一种更为可靠的方式获取当前屏幕的大小： 通过使用DX获取当前设备的长宽</p>
<p>下图为所获取的桌面长宽：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/1018.WindowsStoreAppResolution2.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/1018.WindowsStoreAppResolution2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/1018.WindowsStoreAppResolution2.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/1018.WindowsStoreAppResolution2.png" alt="" border="0" /></a></p>
<p>&nbsp;通过以下代码来实现：</p>
<pre class="scroll"><code class="cplusplus">MyLib::MyLib()<br /> {<br /> // This flag adds support for surfaces with a different color channel ordering than the API default.<br /> // It is recommended usage, and is required for compatibility with Direct2D.<br /> UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;<br /> <br /> #if defined(_DEBUG)<br /> // If the project is in a debug build, enable debugging via SDK Layers with this flag.<br /> creationFlags |= D3D11_CREATE_DEVICE_DEBUG;<br /> #endif<br /> <br /> // This array defines the set of DirectX hardware feature levels this app will support.<br /> // Note the ordering should be preserved.<br /> // Don't forget to declare your application's minimum required feature level in its<br /> // description. All applications are assumed to support 9.1 unless otherwise stated.<br /> D3D_FEATURE_LEVEL featureLevels[] =<br /> {<br /> D3D_FEATURE_LEVEL_11_1,<br /> D3D_FEATURE_LEVEL_11_0,<br /> D3D_FEATURE_LEVEL_10_1,<br /> D3D_FEATURE_LEVEL_10_0,<br /> D3D_FEATURE_LEVEL_9_3,<br /> D3D_FEATURE_LEVEL_9_2,<br /> D3D_FEATURE_LEVEL_9_1<br /> };<br /> <br /> // Create the DX11 API device object, and get a corresponding context.<br /> ComPtr&lt;ID3D11Device&gt; device;<br /> ComPtr&lt;ID3D11DeviceContext&gt; context;<br /> DX::ThrowIfFailed(<br /> D3D11CreateDevice(<br /> nullptr, // specify null to use the default adapter<br /> D3D_DRIVER_TYPE_HARDWARE,<br /> 0, // leave as 0 unless software device<br /> creationFlags, // optionally set debug and Direct2D compatibility flags<br /> featureLevels, // list of feature levels this app can support<br /> ARRAYSIZE(featureLevels), // number of entries in above list<br /> D3D11_SDK_VERSION, // always set this to D3D11_SDK_VERSION for Metro style apps<br /> &amp;device, // returns the Direct3D device created<br /> &amp;m_featureLevel, // returns feature level of device created<br /> &amp;context // returns the device immediate context<br /> )<br /> );<br /> <br /> // Get the DirectX11.1 device by QI off the DirectX11 one.<br /> DX::ThrowIfFailed(<br /> device.As(&amp;m_d3dDevice)<br /> );<br /> }<br /> <br /> <br /> Point MyLib::ScreenResolution::get()<br /> {<br /> // Obtain the underlying DXGI device of the Direct3D11.1 device.<br /> ComPtr&lt;IDXGIDevice&gt; dxgiDevice;<br /> DX::ThrowIfFailed(<br /> m_d3dDevice.As(&amp;dxgiDevice)<br /> );<br /> <br /> // Identify the physical adapter (GPU or card) this device is running on.<br /> ComPtr&lt;IDXGIAdapter&gt; dxgiAdapter;<br /> DX::ThrowIfFailed(<br /> dxgiDevice-&gt;GetAdapter(&amp;dxgiAdapter)<br /> );<br /> <br /> IDXGIOutput * pOutput;<br /> if (dxgiAdapter-&gt;EnumOutputs(0, &amp;pOutput) != DXGI_ERROR_NOT_FOUND)<br /> {<br /> DXGI_OUTPUT_DESC desc;<br /> pOutput-&gt;GetDesc(&amp;desc);<br /> return Point(desc.DesktopCoordinates.right, desc.DesktopCoordinates.bottom);<br /> }<br /> <br /> return Point(0, 0);<br /> }<br /> </code></pre>
<p>&nbsp;另外，我将示例上传到OneDrive中方便大家查看：<a href="http://1drv.ms/1gKw9Fa">http://1drv.ms/1gKw9Fa</a></p>]]></content:encoded>
    </item>
    <item>
      <title>使用UI control创建动态的live tile (Windows 8.1 XAML/VB.net)</title>
      <link>https://docs.microsoft.com/archive/blogs/windows8devsupport/ui-controllive-tile-windows-8-1-xamlvb-net</link>
      <pubDate>Thu, 17 Apr 2014 02:03:00 GMT</pubDate>
      <dc:creator><![CDATA[MingXu-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/windows8devsupport/2014/04/17/ui-controllive-tile-windows-8-1-xamlvb-net/</guid>
      <description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Windows store app可以通过live...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Windows store app可以通过live tile向用户展示动态信息，但是如果您想您的应用程序能够以丰富和多样化的UI展示信息时，那么标准的live tile模板就很难能达到您的要求了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本篇博客将介绍如何通过user controls来定义您的live tile的布局，您只需要将这个user control 以bitmap的形式保存，然后再添加live tile的内容即可。这样除了Windows 8中标准的live tile布局，您也可以得到如下效果：</p>
<p style="text-align: center;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/3660.tilesample.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/3660.tilesample.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/3660.tilesample.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/120x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/3660.tilesample.png" alt="" border="0" /></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虽然这也许不是您见过的最具吸引力的live tile，但是它的可取之处是它是由一个完全可定制的user control 以image的方式来呈现的。您可以更改上面图片中的任何一个UI element，这样可以动态呈现您的应用程序的状态。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来, 我们将讨论如何创建一个这样的live tile，在文章的结尾处您可以下载该project的完整代码。</p>
<p><strong>主要步骤</strong><strong></strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建自定义的live tile分为以下三个步骤：</p>
<ol>
<li>为您的live tile的布局创建一个user control</li>
<li>将这个user control以bitmap的形式呈现</li>
<li>在image上更新您的live tile的内容</li>
</ol>
<p><strong>注意事项</strong><strong></strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在创建这个live tile之前，您需要确认您的系统是Windows 8.1，并且已经安装visual studio 的2013版本（包括visual studio express）,因为本文中的示例不能在Windows 8.0上正常运行。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在visual studio 2013中新建一个项目例如: Visual Basic -&gt; Windows store app -&gt; BlankApp (XAML).</p>
<p><strong>第一步：创建</strong><strong>User Control</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 您的live tile将呈现什么样内容是没有限制的，我们会在以下的例子当中创建两个UI element（一个宽屏的tile和一个方屏的tile）。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建两个user controls的步骤如下：<strong></strong></p>
<ol>
<li>在解决方案资源管理器中右键单击该项目的名称，选择添加 -&gt; 新项目</li>
<li>选择user control</li>
<li>键入一个名称（分别为WideTileTemplate.xaml 和 MediumTileTemplate.xaml）</li>
<li>单击添加</li>
</ol>
<p>&nbsp;&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7558.VSAddUserControl.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7558.VSAddUserControl.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/7558.VSAddUserControl.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/7558.VSAddUserControl.png" alt="" border="0" /></a></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;向您的user control中添加什么UI内容取决于您所希望的live tile的布局。你可以参考下面的代码或者您也可以自定义您的User control。</p>
<p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong><strong>注意：</strong>在使用下面的代码之前您需要在您的project的根目录下添加一张名为&ldquo;'image.png&rdquo; 的图片：选择添加 -&gt; 现有项目，然后浏览并选择您计算机上的 .png格式的文件。(请注意, 为确保您的图片能够正常的显示, 请将图片更名为&ldquo;'image.png&rdquo;)。</p>
<p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong>此外,<strong> </strong>我们需要为这个control定义合适的大小，比如将宽屏的tile的大小定义为691 x 336像素，将方屏的tile的大小定义为336x336像素。</p>
<p>宽屏的tile的user control的定义如下：</p>
<pre class="scroll"><code class="html">&lt;UserControl x:Class="TileSamplerApp.WideTileTemplate" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation " xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml " <br /> xmlns:local="using:TileSamplerApp"<br /> xmlns:d="http://schemas.microsoft.com/expression/blend/2008 " xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006 "<br /> mc:Ignorable="d"<br /> d:DesignHeight="336" d:DesignWidth="691"&gt;<br /> <br /> &lt;Canvas x:Name="LayoutRoot" Width="691" Height="336" Background="Yellow"&gt;<br /> &lt;Image Source="image.png" HorizontalAlignment="Left" Height="316" VerticalAlignment="Top" <br /> Width="332" Canvas.Left="10" Canvas.Top="10"/&gt;<br /> &lt;TextBlock Text="Hello World" HorizontalAlignment="Left" Height="39" TextWrapping="Wrap" VerticalAlignment="Top" Width="266" FontSize="26" Foreground="Black" FontWeight="Bold" Canvas.Left="347" Canvas.Top="46"/&gt; <br /> &lt;TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Some more text!" VerticalAlignment="Top" Width="277" RenderTransformOrigin="0.5,0.5" Canvas.Left="347" Canvas.Top="159" FontSize="26" Height="30" Foreground="#FFE81C1C"/&gt;<br /> &lt;TextBlock Text="37" x:Name="Number" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Height="97" Width="122" FontSize="72" TextAlignment="Center" Canvas.Left="559" Canvas.Top="229" Foreground="#FF42105F"/&gt;<br /> &lt;/Canvas&gt;<br /> &lt;/UserControl&gt;<br /> </code></pre>
<p>方屏tile的user control的定义如下：</p>
<pre class="scroll"><code class="cplusplus">&lt;UserControl<br /> x:Class="TileSamplerApp.MediumTileTemplate"<br /> xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation "<br /> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml "<br /> xmlns:local="using:TileSamplerApp"<br /> xmlns:d="http://schemas.microsoft.com/expression/blend/2008 "<br /> xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006 "<br /> mc:Ignorable="d"<br /> d:DesignHeight="336" d:DesignWidth="336"&gt;<br /> <br /> &lt;Canvas x:Name="LayoutRoot" Width="336" Height="336" Background="Yellow"&gt;<br /> &lt;Image Source="image.png" HorizontalAlignment="Left" Height="167" Width="178"<br /> VerticalAlignment="Top" Canvas.Left="27" Canvas.Top="70"/&gt;<br /> &lt;TextBlock Text="Hello World" HorizontalAlignment="Left" Height="39" TextWrapping="Wrap" VerticalAlignment="Top" Width="266" FontSize="26" Foreground="Black" FontWeight="Bold" Canvas.Left="36"<br /> Canvas.Top="10"/&gt;<br /> &lt;TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Some more text!"<br /> VerticalAlignment="Top" Width="277" RenderTransformOrigin="0.5,0.5" Canvas.Left="36" Canvas.Top="270"<br /> FontSize="26" Height="30" Foreground="#FFE81C1C"/&gt;<br /> &lt;TextBlock Text="37" x:Name="Number" HorizontalAlignment="Center" TextWrapping="Wrap"<br /> VerticalAlignment="Top" Height="97" Width="122" FontSize="72" TextAlignment="Center" Canvas.Left="210"<br /> Canvas.Top="102" Foreground="#FF42105F"/&gt;<br /> &lt;/Canvas&gt;<br /> &lt;/UserControl&gt;<br /> </code></pre>
<p>将这两个user control添加到MainPage.xaml页面</p>
<ol>
<li>双击资源管理器中的MainPage.xaml,以便在designer设计器中打开它。</li>
<li>然后用下面的代码替换XAML页面的内容：</li>
</ol>
<pre class="scroll"><code class="html">&lt;Page x:Class="TileSamplerApp.MainPage"<br /> xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation " xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml "<br /> xmlns:local="using:TileSamplerApp" xmlns:d="http://schemas.microsoft.com/expression/blend/2008 " xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006 "<br /> mc:Ignorable="d"&gt;<br /> &lt;Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"&gt;<br /> &lt;local:WideTileTemplate x:Name="WideTile" HorizontalAlignment="Left" VerticalAlignment="Top"/&gt;<br /> &lt;local:MediumTileTemplate x:Name="MediumTile" HorizontalAlignment="Right" VerticalAlignment="Bottom"/&gt; &lt;Button Content="Create Tile" HorizontalAlignment="Left" Margin="170,606,0,0" VerticalAlignment="Top" Height="116" Width="210" Click="Button_Click"/&gt;<br /> &lt;/Grid&gt;<br /> &lt;/Page&gt;<br /> </code></pre>
<p>这样会向MainPage页面添加两个controls，设计器的样式如下所示：</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/5265.TileUserControl.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/5265.TileUserControl.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/64/61/5265.TileUserControl.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-64-61/5265.TileUserControl.png" alt="" border="0" /></a></p>
<p><strong>回顾</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在您项目的根目录下已包含以下文件：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个名为&ldquo;image.png&rdquo;的图片文件</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个名为WideTileTemplate.xaml的user control</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 一个名为MediumTileTemplate.xaml的user control</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 一个包含两个user controls的MainPage.xaml页面</p>
<p><strong>第二步：将</strong><strong>user controls </strong><strong>以</strong><strong>bitmap</strong><strong>的形式呈现并保存</strong><strong></strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在您已经成功的创建了您的user control 并可以在页面上显示，那么下一步您需要做的是将user control以image的形式呈现并将它们保存在您的应用程序的storage 文件夹下。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitmapRender创建了一个像素数据流，这个流组成了您的用户控件。这个数据流被编码过了（在本文中是.png格式），并且存储在一个文件里。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于上面所示步骤，我们将创建两个方法。第一个是将组成user control的像素转换成数据流，另一个是将数据流保存到文件中。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 您需要将上述步骤的代码放在MainPage.xaml.vb页面。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在对user control 进行编码并将其存储到文件之前，您需要在您的page页面添加一些命名空间。将下面的代码放在MainPage.xaml.vb页面的最顶端。这些代码能使我们在 MainPage.xaml.vb页面访问和使用某些Visual Basic的API和功能。</p>
<pre class="scroll"><code class="csharp"> Imports Windows.Storage<br /> Imports Windows.Graphics.Imaging<br /> Imports Windows.Storage.Streams<br /> Imports Windows.UI.Notifications<br /> Imports NotificationsExtensions.TileContent<br /> </code></pre>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 安装Notifications Extensions</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 您需要添加Notifications Extensions</p>
<ol>
<li>在visual studio窗口顶部的菜单栏中选择：TOOLS &nbsp;-&gt; Library Package Manager -&gt; Package Manager Console.</li>
<li>在底部的Package Manager &nbsp;Console窗口会出现PM -&gt; 提示符，您可以键入：Install-Package NotificationsExtensions.WinRT</li>
<li>按enter键</li>
</ol>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在MainPage.xaml.vb中, 以下代码用作实现将一个user control 以bitmap的形式呈现。</p>
<pre class="scroll"><code class="csharp">Public Async Function GenerateImageToFile(fileName As String, uiContent As FrameworkElement) As Task<br /> Dim file As StorageFile = Await ApplicationData.Current.LocalFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting)<br /> If file IsNot Nothing Then<br /> CachedFileManager.DeferUpdates(file)<br /> Using stream = Await file.OpenAsync(FileAccessMode.ReadWrite)<br /> Dim b = Await CaptureToStreamAsync(uiContent, stream, BitmapEncoder.PngEncoderId)<br /> End Using<br /> Dim status = Await CachedFileManager.CompleteUpdatesAsync(file)<br /> End If<br /> End Function<br /> <br /> Private Async Function CaptureToStreamAsync(uielement As FrameworkElement, stream As IRandomAccessStream, encoderId As Guid) As Task(Of RenderTargetBitmap)<br /> Dim renderTargetBitmap = New RenderTargetBitmap()<br /> Await renderTargetBitmap.RenderAsync(uielement)<br /> Dim pixels = Await renderTargetBitmap.GetPixelsAsync()<br /> Dim logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi<br /> Dim encoder = Await BitmapEncoder.CreateAsync(encoderId, stream)<br /> encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, CUInt(renderTargetBitmap.PixelWidth), CUInt(renderTargetBitmap.PixelHeight), logicalDpi, logicalDpi, pixels.ToArray())<br /> Await encoder.FlushAsync()<br /> Return renderTargetBitmap<br /> End Function<br /> </code></pre>
<p>让我们来逐步理解这些代码：</p>
<pre class="scroll"><code class="csharp">Public Async Function GenerateImageToFile(fileName As String, uiContent As FrameworkElement) As Task</code></pre>
<p>&nbsp;GenerateImageToFile方法是以一个文件名和user control作为输入参数，然后创建一个.png格式的image文件</p>
<pre class="scroll"><code class="csharp">Dim file As StorageFile = Await ApplicationData.Current.LocalFolder.CreateFileAsync(fileName , CreationCollisionOption.ReplaceExisting)</code></pre>
<p>这个方法是根据fileName这个输入参数创建一个名为fileName的文件</p>
<pre class="scroll"><code class="csharp">If file IsNot Nothing Then CachedFileManager.DeferUpdates(file)</code></pre>
<p>这个方法检查该文件是否存在，如果存在的话那么系统将停止对它进行更新和修改</p>
<pre class="scroll"><code class="csharp">Using stream = Await file.OpenAsync(FileAccessMode.ReadWrite)<br /> Dim b = Await CaptureToStreamAsync(uiContent, stream, BitmapEncoder.PngEncoderId)<br /> End Using<br /> </code></pre>
<p>这个代码块是先打开一个文件并将数据流存储在这个文件中。其中第二行代码是通过使用CaptureToStreamAsync方法将数据流进行编码（即将user control转换为.png格式的图像）</p>
<pre class="scroll"><code class="csharp">Dim status = Await CachedFileManager.CompleteUpdatesAsync(file)<br /> End If<br /> </code></pre>
<p>上面的代码是确保该方法直到将数据流完全更新到file中才真正结束。</p>
<pre class="scroll"><code class="csharp">Private Async Function CaptureToStreamAsync(uielement As FrameworkElement, stream As IRandomAccessStream, encoderId As Guid) As Task(Of RenderTargetBitmap)</code></pre>
<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;CaptureToStreamAsync方法根据user control的像素数据流将其转换为正确的图像格式。这个方法将一个framework element、数据流、一个编码器的encoderId作为输入，并将该framework element转化为图像。该函数的返回值是一个RenderTargetBitmap类型，随后我们将会为其保存为图像文件。</p>
<pre class="scroll"><code class="csharp">Dim renderTargetBitmap = New RenderTargetBitmap()<br /> Await renderTargetBitmap.RenderAsync(uielement)<br /> </code></pre>
<p>这两行代码是将图像数据刷新到RenderTargetBitmap对象以完成bitmap的创建。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面我们需要做的是根据上面创建好的image来定义live tile。</p>
<p><strong>步骤三：创建</strong><strong>live tile</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在我们来创建一个新的tile并更新应用程序的原有的tile。此示例将会创建宽屏和方屏这两种类型的tile。</p>
<p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong><strong>注意：</strong>您需要在您的应用程序清单中添加一个默认的宽屏tile以便您能够创建宽屏的tile。默认情况下，应用程序仅仅支持中型的和小型的tile。步骤如下：</p>
<ol>
<li>创建一个310*150像素的.png格式的图片</li>
<li>在项目资源管理器中，双击Package.appxmanifest 文件</li>
<li>选择Visual Assets选项卡</li>
<li>在左侧栏中选择310*150的徽标</li>
<li>在Scaled Assets中选择 310x150 图片文件来填充这个徽标.</li>
</ol>
<p>现在你可以在您的项目中启用宽屏的tile了。</p>
<p>你可以将以下代码添加到您的MainPage.xaml.vb页面, 创建宽型和中型的live tile：</p>
<pre class="scroll"><code class="csharp">Public Sub SetLiveTileImage(wideImageFileName As String, mediumImageFileName As String) TileUpdateManager.CreateTileUpdaterForApplication.Clear()<br /> Dim tileContent As NotificationsExtensions.TileContent.ITileWideImage = TileContentFactory.CreateTileWideImage()<br /> Dim squareTileContent = NotificationsExtensions.TileContent.TileContentFactory.CreateTileSquareImage() tileContent.Image.Src = "ms-appdata:///local/" &amp; wideImageFileName squareTileContent.Image.Src = "ms-appdata:///local/" &amp; mediumImageFileName tileContent.SquareContent = squareTileContent tileContent.Branding = TileBranding.None<br /> Dim MyTileNotification As TileNotification = tileContent.CreateNotification() TileUpdateManager.CreateTileUpdaterForApplication.Update(MyTileNotification)<br /> End Sub<br /> </code></pre>
<p><strong>注意：</strong>不同的tile 模板有不同的信息，但是我们创建一个仅包含图片的最基本的live tile。</p>
<p><strong>最后一步：将代码整合在一起</strong><strong></strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所有的工作您已经准备好了，但是你现在要做的是运行这些代码来创建一个live tile。在本例中我们将live tile的更新工作放在一个Button的click事件中。但是在您的应用程序中，您需要根据相应的逻辑来更新live tile，比如一个游戏的进度发生变化或者您的应用程序中产生了一个新的消息。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 您可以向您的MainPage.xaml页面添加一个button控件，将下面的代码粘贴到您的user control代码的后面：</p>
<pre class="scroll"><code class="csharp">&lt;Button Content="Create Tile" HorizontalAlignment="Left" Margin="170,606,0,0" VerticalAlignment="Top" Height="116" Width="210" Click="Button_Click" /&gt;</code></pre>
<p>现在您可以向Button click 事件添加事件处理程序了，您可以直接打开MainPage.xaml.vb页面并向其中添加Button_Click方法，或者在设计器中双击Button，这样您可以自动创建Button_Click方法：</p>
<pre class="scroll"><code class="csharp">Private Async Sub Button_Click(sender As Object, e As RoutedEventArgs)<br /> Await GenerateImageToFile("wideTile.png", WideTile)<br /> Await GenerateImageToFile("mediumTile.png", MediumTile)<br /> SetLiveTileImage("wideTile.png", "mediumTile.png")<br /> End Sub<br /> </code></pre>
<p>您可以尝试运行上面的代码，如果您有两台监视器，可以让其中一台运行开始菜单项，另一台运行该项目，当点击button的时候，您就可以在菜单项中看到tile更新。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该示例说明如何自定义一个live tile 的UI，如果您感兴趣, 我们还可以尝试, 比如：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ●向page页面添加一个TextBox，并将其中的Text填充到live tile中</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ●确保您页面中的某些control即使不可见也能保证live tile正确呈现</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ●通过FilePicker从Picture Library选择图片并填充到live tile中</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ●尝试各种不同的UI布局</p>
<p><strong>问题答疑</strong><strong></strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果您的tile并没有及时更新。这可能与windows限制tile更新的次数有关。可以尝试快速重启机器解决该问题。</p>
<p><strong>下载</strong><strong></strong></p>
<p><a href="https://onedrive.live.com/?cid=5af059da63be71bc&amp;id=5AF059DA63BE71BC%21156031&amp;ithint=file,.zip&amp;authkey=!AI0ZAScs0eanucY">下载整个项目</a></p>]]></content:encoded>
    </item>
  </channel>
</rss>