<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_马宁的嵌入式开发研究</title><subtitle type="text">Windows Phone, XNA, Windows Embedded, Windows Mobile</subtitle><id>http://feed.cnblogs.com/blog/u/31097/rss</id><updated>2012-05-16T11:43:48Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/31097/rss"/><entry><id>http://www.cnblogs.com/aawolf/archive/2012/05/16/2505146.html</id><title type="text">OpenXLive Push Notification Hosting服务开发指南</title><summary type="text">作者：马宁 示例代码下载： Download Windows Phone上支持Push Notification，用户可以使用微软的推送服务器（MPNS）向安装了自己软件的Windows Phone设备上推送三种不同的通知消息。 Push Notification的机制大致是这样的： 1. 运行在Windows Phone设备端的应用注册一个Push Notification Channel，获得一个唯一标识这个Channel的URI； 2. 将URI传回到开发者自己的服务器； 3. 当开发者需要发送Push Notification消息时，将规定格式的数据发送到之前获得的URI...</summary><published>2012-05-16T11:43:00Z</published><updated>2012-05-16T11:43:00Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><link rel="alternate" href="http://www.cnblogs.com/aawolf/archive/2012/05/16/2505146.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/archive/2012/05/16/2505146.html"/><content type="html">&lt;p&gt;&lt;strong&gt;作者：马宁&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;示例代码下载：&lt;/p&gt;  &lt;p&gt;&lt;a title="Download" href="http://files.cnblogs.com/aawolf/OpenXLive_Hosting_Demo.zip"&gt;Download&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Windows Phone上支持Push Notification，用户可以使用微软的推送服务器（MPNS）向安装了自己软件的Windows Phone设备上推送三种不同的通知消息。&lt;/p&gt;  &lt;p&gt;Push Notification的机制大致是这样的：&lt;/p&gt;  &lt;p&gt;1. 运行在Windows Phone设备端的应用注册一个Push Notification Channel，获得一个唯一标识这个Channel的URI；&lt;/p&gt;  &lt;p&gt;2. 将URI传回到开发者自己的服务器；&lt;/p&gt;  &lt;p&gt;3. 当开发者需要发送Push Notification消息时，将规定格式的数据发送到之前获得的URI上；&lt;/p&gt;  &lt;p&gt;4. 微软的推送服务器（MPNS）获得开发者发送的请求后，会通知到对应的Windows Phone设备上。&lt;/p&gt;  &lt;p&gt;整个过程如下图所示：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942405613.jpg"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="Ff402558_AP_Push_NotificationArch(en-us,VS_92)" border="0" alt="Ff402558_AP_Push_NotificationArch(en-us,VS_92)" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942418612.jpg" width="575" height="377" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;在整个过程中，对于开发者来说，有一个难点很难克服&amp;#8212;&amp;#8212;必须有自己的服务器，否则无法接收从Windows Phone应用中发送过来的URI。这个问题对于那些没有自己服务器的Windows Phone开发者来说，他们只能放弃在自己的应用中加入Push Notification的功能。&lt;/p&gt;  &lt;p&gt;OpenXLive为了解决这个问题，为开发者提供了Push Notification Hosting服务（OpenXLive Push Notification Hosting Server，简称OPNHS），允许开发者将OpenXLive的服务器作为自己的Push Notification服务器。只要开发者调用OpenXLive SDK中的API，就可以让OpenXLive的服务器来保存URI，当开发者需要发送Push Notification消息时，只需要登录OpenXLive开发者后台就可以发送了。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Silverlight应用中添加Push Notification&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;接下来，我们以Silverlight for Windows Phone应用为例，看看如何使用OpenXLive Push Notification Hosting功能，向 Silverlight应用发送三种不同的Push Notification。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1. 添加OpenXLive功能&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;首先，我们要为创建好的Silverlight应用添加OpenXLive引用。如果没有安装OpenXLive SDK的话，请在下面的链接中下载SDK。请注意，只有在0.9.8及其以上版本中，才包含OpenXLive Push Notification Hosting功能。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://developer.openxlive.net/sdk/download/"&gt;http://developer.openxlive.net/sdk/download/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;如果您已经安装了OpenXLive SDK，可以在安装路径（默认为C:\Program Files (x86)\Fulcrum Mobile Networks, Inc\OpenXLiveSDK\Bin\Silverlight）下找到OpenXLive.dll和OpenXLive.Silverlight.dll。&lt;/p&gt;  &lt;p&gt;找到这两个DLL后，我们需要将其拷贝到Silverlight应用的目录下，否则会产生一个访问异常。&lt;/p&gt;  &lt;p&gt;在Visual Studio的Solution Explorer中，选择Add References，添加OpenXLive.dll和OpenXLive.Silverlight.dll的引用。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942418579.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image003" border="0" alt="clip_image003" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942416038.png" width="527" height="424" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;然后，打开App.xaml.cs文件，添加下面的代码：&lt;/p&gt;  &lt;span class="kwrd"&gt;using&lt;/span&gt; OpenXLive;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; OpenXLive.Features;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Launching(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, LaunchingEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (XLiveGameManager.CurrentSession == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;GameSession session = XLiveGameManager.CreateSession(&lt;span class="str"&gt;"enMQ3rEC5jsw8XygdFHuGpfk"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;session.CreateSessionCompleted += &lt;span class="kwrd"&gt;new&lt;/span&gt; AsyncEventHandler(session_CreateSessionCompleted);&lt;br/&gt;&lt;br/&gt;session.Open();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; session_CreateSessionCompleted(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, AsyncEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;AsyncProcessResult result = e.Result;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (!result.ReturnValue)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// TODO: Error Handler&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Activated(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ActivatedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;XLiveGameManager.Activated();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Deactivated(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, DeactivatedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;XLiveGameManager.Deactivated();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Closing(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ClosingEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (XLiveGameManager.CurrentSession != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;XLiveGameManager.CurrentSession.Close();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;代码具体的解释可以参考《在Windows Phone应用中添加OpenXLive数据分析功能》，链接如下：&lt;a href="http://www.cnblogs.com/aawolf/archive/2011/10/03/2198607.html"&gt;http://www.cnblogs.com/aawolf/archive/2011/10/03/2198607.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;当OpenXLive的引用和功能调用添加完成后，我们就可以添加Push Notification代码了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 发送Tile Notification&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;为了保证足够的灵活性，所以，开发者仍然调用Push Notification的API来注册Push Notification的Channel。我们首先来演示，如何创建并发送Tile Notification。关于Tile Notification的详细信息，可以参考MSDN上的文章：&lt;/p&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/hh202970(VS.92).aspx"&gt;http://msdn.microsoft.com/en-us/library/hh202970(VS.92).aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;在Visual Studio中打开MainPage.xaml，添加三个ToggleSwitch控件，分别对应三种不同的Notification类型，选中控件添加Checked事件处理函数，然后进入代码编辑界面，添加如下的代码来创建Push Notification的Channel。&lt;/p&gt;&lt;p&gt;首先在MainPage.xaml.cs文件的顶部，添加引用：&lt;/p&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Phone.Notification;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; OpenXLive;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;接下来，在与Tile Notification对应的ToggleSwitch控件Checked事件中，添加创建Push Notification Channel的代码：&lt;/p&gt;&lt;span class="rem"&gt;// The name of our push channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; channelName = &lt;span class="str"&gt;"OpenXLivePushNotificationHostingChannel"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; toggleSwitchTile_Checked(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Try to find the push channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(channelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// If the channel was not found, then create a new connection to the push service.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;pushChannel = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotificationChannel(channelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Register for all the events before attempting to open the channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;pushChannel.Open();&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Bind this new channel for Tile events.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; !pushChannel.IsShellTileBound)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;var allowedDomains = &lt;span class="kwrd"&gt;new&lt;/span&gt; Collection&amp;lt;Uri&amp;gt; { &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;"http://picture.openxlive.com/"&lt;/span&gt;) };&lt;br/&gt;&lt;br/&gt;pushChannel.BindToShellTile(allowedDomains);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// The channel was already open, so just register for all the events.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;RegisterNotificationUri(pushChannel.ChannelUri);&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;创建Push Notification Channel的代码与MSDN上的一致，三种不同的Notification在创建时其实是一样的，只是在创建之后进行了不同的操作，所以才会分成不同的Notification。比如，Tile Notification就需要在创建后，调用BindToShellTile方法，将其绑定到Tile上；在关闭Notification Channel前，还要记得调用UnbindToShellTile方法，解除绑定。&lt;/p&gt;&lt;p&gt;特别要强调的是，如果您的背景图片是放在OpenXLive服务器上的话，需要在调用BindToShellTile方法之前，首先将OpenXLive的图片服务器（picture.openxlive.com）添加到允许访问的域名列表中。当然，如果您的图片来自其他域名的服务器，您也要将对应的域名加入这个列表中。&lt;/p&gt;&lt;p&gt;接下来，我们来看将Notification Channel的Uri注册到OpenXLive服务器上的代码：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RegisterNotificationUri(Uri uri)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Send Channel Uri to OpenXLive Hosting Server&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (OpenXLive.XLiveGameManager.CurrentSession != &lt;span class="kwrd"&gt;null&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&amp;amp;&amp;amp;&lt;br/&gt;&lt;br/&gt;OpenXLive.XLiveGameManager.CurrentSession.IsValid&lt;br/&gt;&lt;br/&gt;&amp;amp;&amp;amp;&lt;br/&gt;&lt;br/&gt;uri != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;OpenXLive.XLiveGameManager.CurrentSession.RegistNotificationUriCompleted&lt;br/&gt;&lt;br/&gt;+= &lt;span class="kwrd"&gt;new&lt;/span&gt; OpenXLive.Features.AsyncEventHandler(CurrentSession_RegistNotificationUriCompleted);&lt;br/&gt;&lt;br/&gt;OpenXLive.XLiveGameManager.CurrentSession.RegisterNotificationUri(uri);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; CurrentSession_RegistNotificationUriCompleted(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, OpenXLive.AsyncEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;OpenXLive.Features.AsyncProcessResult result = e.Result;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (result.ReturnValue)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;Debug.WriteLine(&lt;span class="str"&gt;"Channel Uri has been send to OpenXLive Hosting Server"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;Debug.WriteLine(result.ErrorMessage);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;调用OpenXLive Push Notification Hosting的方法非常简单，首先判断一下XLiveGameManager对象中CurrentSession属性中的GameSession对象是否有效，如果有效则首先添加RegistNotificationUriCompleted事件处理方法，然后调用GameSession的RegisterNotificationUri方法，将Push Notification Channel的Uri传递到OpenXLive Notification Hosting服务器（OPNHS）上即可。OPNHS没有提供解除绑定的方法，因为Notification Channel在解除绑定后会自动失效，OPNHS会将失效的Uri自动抛弃，所以客户端引用就没有必要解除绑定了。&lt;/p&gt;&lt;p&gt;还有两个需要提示的最佳实践：因为Push Notification Channel的注册需要GameSession有效，所以，在XLiveGameManager的CreateSession方法的CreateSessionCompleted事件处理函数中创建Push Notification Channel，并将其注册到OPNHS中，是最为安全的。&lt;/p&gt;&lt;p&gt;另外，由于HttpNotificationChannel创建Notification Channel本身也是一个异步调用，在某些情况下，如果我们在创建Notification Channel之后，马上注册到OPNHS上，Uri可能为空。所以，我们必须在HttpNotificationChannel的ChannelUriUpdated事件处理函数中增加注册代码，防止注册处理被漏掉。&lt;/p&gt;&lt;p&gt;好了，接下来看一下HttpNotificationChannel的ChannelUriUpdated事件处理函数的代码：&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; PushChannel_ChannelUriUpdated(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, NotificationChannelUriEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (e.ChannelUri != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;RegisterNotificationUri(e.ChannelUri);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;Dispatcher.BeginInvoke(() =&amp;gt;&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Display the new URI for testing purposes. Normally, the URI would be passed back to your web service at this point.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;System.Diagnostics.Debug.WriteLine(e.ChannelUri.ToString());&lt;br/&gt;&lt;br/&gt;});&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;虽然有一些Push Notification Channel创建的代码没有完整展示，这部分代码不影响OPNHS的使用，您可以在示例代码中看到完整的代码。&lt;/p&gt;&lt;p&gt;好了，到这里，我们就完成了客户端的代码工作，接下来就可以看一下运行的效果了。在客户端代码运行前，您必须确认已经在OpenXLive的开发者网站上创建了OpenXLive的游戏/应用，并且已经取得了有效的API Secrecy Key，具体的做法您可以参考《在开发者网站上创建OpenXLive游戏》：&lt;/p&gt;&lt;p&gt;&lt;a href="http://wiki.openxlive.net/Tutorial-4-Create-OpenXLive-Game-in-website.ashx"&gt;http://wiki.openxlive.net/Tutorial-4-Create-OpenXLive-Game-in-website.ashx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;客户端程序开始运行之后，我们会看到下面的界面，并打开Tile Notification对应的ToggleSwitch控件：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942422417.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="3" border="0" alt="3" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942428480.png" width="282" height="468" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;然后点击模拟器上的Windows键，回到主界面，并切换到应用程序列表界面，将我们的示例程序pin到主界面上来显示：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942426811.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="2" border="0" alt="2" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942427334.png" width="270" height="448" /&gt;&lt;/a&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942437301.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="4" border="0" alt="4" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942436188.png" width="270" height="447" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;好了，我们现在已经打开了Tile Notification的Channel，并且将其注册到了OPNHS上，而且把应用程序的Tile pin到主界面上。客户端的工作就完成了。&lt;/p&gt;&lt;p&gt;作为开发者，想向客户端发送Tile Notification的时候，只需要登录到OpenXLive的开发者网站，在开发者后台的控制面板中选择对应的游戏/应用，然后在右侧的功能选项中，选择&amp;#8220;推送通知&amp;#8221;（Push Notification），在二级菜单中，选择&amp;#8220;Tile推送通知&amp;#8221;，我们会看到如下界面：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942437791.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="z1" border="0" alt="z1" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942446122.png" width="562" height="485" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Tile Notification一共能够传递六个参数，分为两组。前景部分，是标题（Title）、数字（Count）和前景图片（BackgroundImage），需要指出的是，数字的现实范围是0-99之间的整形数字；而背景组，是背景标题（BackTitle）、内容（BackContent）和背景图片（BackBackgroundImage）。Tile显示的布局与基本样式无法修改，如下图所示：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942446646.jpg"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image013" border="0" alt="clip_image013" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942447659.jpg" width="406" height="175" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;背景图片即可以是应用程序内部的资源图片，也可以是来自网络的图片。所以，OpenXLive的服务器也提供了图片上传的功能，开发者可以将Tile图片上传至OpenXLive服务器，然后再推送至Windows Phone手机。&lt;/p&gt;&lt;p&gt;如果使用应用程序内部的资源图片，在BackgroundImage栏输入图片在xap包中的相对路径即可。将图片添加到程序中作为背景图片，可以按以下步骤操作：&lt;/p&gt;&lt;p&gt;1. 右键项目，单击 &lt;strong&gt;添加&lt;/strong&gt;，然后再单击 &lt;strong&gt;添加现有项&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;2. 选中要添加的图片，单击 &lt;strong&gt;打开&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;3. 鼠标右键单击添加的图片，然后选择 &lt;strong&gt;属&lt;/strong&gt;&lt;strong&gt;性&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;4. 找到 &lt;strong&gt;属性&lt;/strong&gt; 对话框中的 &lt;strong&gt;生成操作&lt;/strong&gt; 属性，并设置为 &lt;strong&gt;内&lt;/strong&gt;&lt;strong&gt;容&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;5. 将 &lt;strong&gt;复制到输出目&lt;/strong&gt;&lt;strong&gt;录 &lt;/strong&gt;设置为 &lt;strong&gt;如果较新则复&lt;/strong&gt;&lt;strong&gt;制&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;发送Tile Notification 时，要使用该图片只需在BackgroundImage栏输入图片名称（包括后缀名）即可。如果图片不在根目录下则输入 Folder/Image.jpg。&lt;/p&gt;&lt;p&gt;目前OPNHS的功能相对简单，每次发送Push Notification时，开发者只能登录OpenXLive服务器，手工发送，还没有实现定时发送的功能。复杂功能会随着开发者的要求，在后续的版本中逐步实现。&lt;/p&gt;&lt;p&gt;好了，当您填写好Tile Notification的内容后，点击&amp;#8220;发送&amp;#8221;按钮。在Windows Phone的主界面上，您很快就可以看到推送过来的Tile内容了。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942456546.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image015" border="0" alt="clip_image015" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/20120516194245974.png" width="254" height="420" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3. 发送Toast Notification&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;第二个推送通知类型是Toast Notification，当程序运行在后台时，Toast Notification会在屏幕的最上端显示一个提示条，和来短信、发现无线网络的系统提示一致。Toast Notification一般用在需要唤醒应用程序的时候，比如应用程序现在有新的内容等。&lt;/p&gt;&lt;p&gt;需要指出的是，每个应用程序最多支持打开一个Notification Channel，在示例程序中，我们并没有做几个Notification Channel的互斥，打开一个新的Channel前，应该关闭另外的Channel，否则会引发异常。&lt;/p&gt;&lt;p&gt;我们先来看一下表示Toast的ToggleSwitch控件的Checked和Unchecked事件处理函数：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; toggleSwitchToast_Checked(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Try to find the push channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(ToastChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// If the channel was not found, then create a new connection to the push service.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;pushChannel = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotificationChannel(ToastChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Register for all the events before attempting to open the channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Register for this notification only if you need to receive the notifications while your application is running.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ShellToastNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationEventArgs&amp;gt;(PushChannel_ShellToastNotificationReceived);&lt;br/&gt;&lt;br/&gt;pushChannel.Open();&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Bind this new channel for Tile events.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.BindToShellToast();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// The channel was already open, so just register for all the events.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Register for this notification only if you need to receive the notifications while your application is running.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ShellToastNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationEventArgs&amp;gt;(PushChannel_ShellToastNotificationReceived);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Send Channel Uri to OpenXLive Hosting Server&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;RegisterNotificationUri(pushChannel.ChannelUri);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; toggleSwitchToast_Unchecked(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Try to find the push channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(ToastChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;pushChannel.UnbindToShellToast();&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Remove push notification channel&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.Close();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;大部分代码与之前的Tile Notification相同，只是增加了Notification Channel的ShellToastNotificationReceived事件处理函数，并且调用BindToShellToast方法，将Notification Channel绑定到Toast上。&lt;/p&gt;&lt;p&gt;接下来，我们要处理两种情况：第一种，接收到Toast Notification时，应用程序正在运行；第二种，接收到Toast Notification时，应用程序在后台。当程序运行在后台时，Toast提示条会显示，当用户点击时，会跳转到Toast Notification中包括的命令行所指定的应用程序页面中。如果应用在前台，我们就要处理Notification Channel的ShellToastNotificationReceived事件处理函数，代码如下：&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; PushChannel_ShellToastNotificationReceived(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, NotificationEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;StringBuilder message = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; relativeUri = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;&lt;br/&gt;&lt;br/&gt;message.AppendFormat(&lt;span class="str"&gt;"Received Toast {0}:\n"&lt;/span&gt;, DateTime.Now.ToShortTimeString());&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Parse out the information that was part of the message.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; key &lt;span class="kwrd"&gt;in&lt;/span&gt; e.Collection.Keys)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;message.AppendFormat(&lt;span class="str"&gt;"{0}: {1}\n"&lt;/span&gt;, key, e.Collection[key]);&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.Compare(&lt;br/&gt;&lt;br/&gt;key,&lt;br/&gt;&lt;br/&gt;&lt;span class="str"&gt;"wp:Param"&lt;/span&gt;,&lt;br/&gt;&lt;br/&gt;System.Globalization.CultureInfo.InvariantCulture,&lt;br/&gt;&lt;br/&gt;System.Globalization.CompareOptions.IgnoreCase) == 0)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;relativeUri = e.Collection[key];&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Display a dialog of all the fields in the toast.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;Dispatcher.BeginInvoke(() =&amp;gt; MessageBox.Show(message.ToString()));&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;为了处理第二种情况，我们要创建一个新的页面，命名为Page2.xaml。我们要在Page2的OnNavigatedTo方法中增加一段代码，以显示导航来源是哪里：&lt;/p&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;base&lt;/span&gt;.OnNavigatedTo(e);&lt;br/&gt;&lt;br/&gt;textBlockFrom.Text = &lt;span class="str"&gt;"Navigated here from "&lt;/span&gt; + &lt;span class="kwrd"&gt;this&lt;/span&gt;.NavigationContext.QueryString[&lt;span class="str"&gt;"NavigatedFrom"&lt;/span&gt;];&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;好了，到这里，我们客户端的代码写完了。我们运行代码示例，并且打开Toast Notification的开关，然后将应用切换到后台。&lt;/p&gt;&lt;p&gt;然后，我们打开OpenXLive的开发者后台，切换至&amp;#8220;推送消息&amp;#8221;界面的&amp;#8220;Toast推送消息&amp;#8221;中。界面截图如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942455085.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="z4" border="0" alt="z4" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942457560.png" width="562" height="227" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Toast Notification有三个参数：Text1，是Toast消息的标题；Text2，是副标题；Param，是需要传递给应用程序的命令行参数，所以必须保证这个参数能够被应用程序解析，否则会引起应用程序崩溃，如果不填，则默认打开应用程序的主界面。&lt;/p&gt;&lt;p&gt;好了，接下来看运行效果如何了。当应用程序在后台的情况下，首先会显示Toast提示条，点击提示条后，会进入命令行指定的应用程序页面。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942468607.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="5" border="0" alt="5" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942463906.png" width="258" height="427" /&gt;&lt;/a&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942476348.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="6" border="0" alt="6" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942474364.png" width="257" height="426" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;在应用程序运行在前台的情况下，我们会用一个MessageBox来显示收到的消息：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942475967.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="7" border="0" alt="7" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942472346.png" width="294" height="487" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;好了，我们完成了第二个Toast Notification的全部工作。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4. 发送Raw Notification&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Raw Notification是三种推送通知中用的比较少的一种，因为Raw Notification只有在应用程序在前台的情况下才有用。在这种情况下，一般的开发者会倾向于使用自己更加能够掌控的Pull方式，而不是由服务器端发起的Push方式。无所谓了，反正对于Raw Notification，我们是要介绍的。&lt;/p&gt;&lt;p&gt;首先还是客户端的代码，已经是轻车熟路了：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; toggleSwitchRaw_Checked(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Try to find the push channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(RawChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// If the channel was not found, then create a new connection to the push service.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;pushChannel = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotificationChannel(RawChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Register for all the events before attempting to open the channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;pushChannel.HttpNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;HttpNotificationEventArgs&amp;gt;(PushChannel_HttpNotificationReceived);&lt;br/&gt;&lt;br/&gt;pushChannel.Open();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// The channel was already open, so just register for all the events.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;pushChannel.HttpNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;HttpNotificationEventArgs&amp;gt;(PushChannel_HttpNotificationReceived);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Display the URI for testing purposes. Normally, the URI would be passed back to your web service at this point.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;System.Diagnostics.Debug.WriteLine(pushChannel.ChannelUri.ToString());&lt;br/&gt;&lt;br/&gt;MessageBox.Show(String.Format(&lt;span class="str"&gt;"Channel Uri is {0}"&lt;/span&gt;,&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUri.ToString()));&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Send Channel Uri to OpenXLive Hosting Server&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;RegisterNotificationUri(pushChannel.ChannelUri);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; PushChannel_HttpNotificationReceived(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, HttpNotificationEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; message;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; (System.IO.StreamReader reader = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.IO.StreamReader(e.Notification.Body))&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;message = reader.ReadToEnd();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;Dispatcher.BeginInvoke(() =&amp;gt;&lt;br/&gt;&lt;br/&gt;MessageBox.Show(String.Format(&lt;span class="str"&gt;"Received Notification {0}:\n{1}"&lt;/span&gt;,&lt;br/&gt;&lt;br/&gt;DateTime.Now.ToShortTimeString(), message))&lt;br/&gt;&lt;br/&gt;);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; toggleSwitchRaw_Unchecked(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Try to find the push channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(RawChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// If the channel was not found, then create a new connection to the push service.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;pushChannel.Close();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;唯一需要多说的是，增加了Notification Channel的HttpNotificationReceived事件处理方法，我们从e.Notification.Body中获取到发送的Raw消息，然后使用StreamReader将其读取为文本，还可以继续进行进一步的处理。&lt;/p&gt;&lt;p&gt;运行客户端程序，打开Raw Notification的选项，将应用程序保持在运行状态。登录OpenXLive开发者后台，&amp;#8220;推送消息&amp;#8221;界面的&amp;#8220;Raw推送消息&amp;#8221;中，将想要发送的文本粘贴到文本框中，点击&amp;#8220;发送&amp;#8221;按钮。&lt;/p&gt;&lt;p&gt;手机客户端的运行效果如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942487853.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="8" border="0" alt="8" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942485311.png" width="310" height="514" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;好了，到这里，我们就将OpenXLive Push Notification Hosting Server（OPNHS）的功能，如何发送三种Push Notification，以及在Silverlight for Windows Phone应用中如何创建Notification Channel、注册到OPNHS中和接收推送通知等。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;XNA游戏中添加Push Notification&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;接下来，我们会介绍，如何在XNA游戏中实现与Silverlight应用中相同的功能。其实，XNA中绝大部分功能与Silverlight类似，只是XNA是一个事件驱动的应用程序框架，而Silverlight是事件驱动，所以在选择创建Notification Channel的时间点上略有差异。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1. 添加OpenXLive功能&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;首先，我们还是首先添加OpenXLive的引用，在OpenXLive SDK的安装路径（默认为C:\Program Files (x86)\Fulcrum Mobile Networks, Inc\OpenXLiveSDK\Bin\XNA）下找到OpenXLive.dll和OpenXLive.Form.dll。这两个DLL是在XNA程序中使用的。&lt;/p&gt;&lt;p&gt;XNA游戏中，我们必须首先在Solution Explorer中打开Properties目录下的WMAppManifest.xml文件，找到下面这句代码，Publisher的名字不能为空，否则无法正确获得Push Notification的消息：&lt;/p&gt;&lt;p&gt;&amp;lt;App xmlns="" ProductID="{aee39b6f-5faf-41e6-a992-5055fdf3a13e}" Title="PushDemoXNA" RuntimeType="XNA" Version="1.0.0.0" Genre="Apps.Normal" Author="" Description="" Publisher="OpenXLive"&amp;gt;&lt;/p&gt;&lt;p&gt;我们打开Game1.cs文件，首先，在文件顶部添加引用：&lt;/p&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; OpenXLive;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; OpenXLive.Features;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; OpenXLive.Forms;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Phone.Notification;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;然后，声明一个XLiveFormManger变量，该对象主要是用来控制XNA中所有的UI Framework，如果不需要显示OpenXLive的XNA UI，该变量也可以不加：&lt;/p&gt;&lt;p&gt;XLiveFormManager manager;&lt;/p&gt;&lt;p&gt;接下来，定位到Initialize方法，接下来添加下面的代码：&lt;/p&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Initialize()&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// TODO: Add your initialization logic here&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (XLiveGameManager.CurrentSession == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;GameSession session = XLiveGameManager.CreateSession(&lt;span class="str"&gt;"enMQ3rEC5jsw8XygdFHuGpfk"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;session.CreateSessionCompleted += &lt;span class="kwrd"&gt;new&lt;/span&gt; AsyncEventHandler(session_CreateSessionCompleted);&lt;br/&gt;&lt;br/&gt;manager = &lt;span class="kwrd"&gt;new&lt;/span&gt; XLiveFormManager(&lt;span class="kwrd"&gt;this&lt;/span&gt;, session);&lt;br/&gt;&lt;br/&gt;session.Open();&lt;br/&gt;&lt;br/&gt;Components.Add(manager);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;base&lt;/span&gt;.Initialize();&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;在OpenXLive SDK 0.9.8及以上版本中，我们修改了创建XNA UI框架的方法，您可以先创建GameSession对象，然后再将GameSession对象传递给XLiveFormManger，这样可以保证Silverlight和XNA调用方式的基本一致。如果您的游戏中只适用了OpenXLive的逻辑代码，而没有使用UI代码的话，也可以不必创建XLiveFormManger对象。但是，调用GameSession的Open方法是必须的。然后，将XLiveFormManger对象作为Game Compoent添加到系统中，也能够保证OpenXLive的XNA UI系统能够被系统释放掉。&lt;/p&gt;&lt;p&gt;好了，短短几句话，我们就可以将OpenXLive加入到我们的XNA游戏中了。接下来，我们就要在GameSession创建成功的事件处理函数中添加Push Notification的代码了。&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; session_CreateSessionCompleted(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, AsyncEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;AsyncProcessResult result = e.Result;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (result.ReturnValue)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// TODO: Error Handler&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;CreateNotificationChannel();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;strong&gt;2. 发送Tile Notification&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;由于XNA的UI控制代码写起来比较费事，所以，我们就在这里简化了调用流程，每次运行程序，只能创建一种Push Notification，代码如下：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateNotificationChannel()&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;CreateTileNotification();&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//CreateToastNotification();&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//CreateRawNotification();&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;而创建Notification Channel的代码与Silverlight版本是一模一样的：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateTileNotification()&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (XLiveGameManager.CurrentSession != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; XLiveGameManager.CurrentSession.IsValid)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Try to find the push channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(TileChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// If the channel was not found, then create a new connection to the push service.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;pushChannel = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotificationChannel(TileChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Register for all the events before attempting to open the channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;pushChannel.Open();&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Bind this new channel for Tile events.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; !pushChannel.IsShellTileBound)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;var allowedDomains = &lt;span class="kwrd"&gt;new&lt;/span&gt; Collection&amp;lt;Uri&amp;gt; { &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;"http://picture.openxlive.com/"&lt;/span&gt;) };&lt;br/&gt;&lt;br/&gt;pushChannel.BindToShellTile(allowedDomains);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// The channel was already open, so just register for all the events.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;RegisterNotificationUri(pushChannel.ChannelUri);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; PushChannel_ChannelUriUpdated(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, NotificationChannelUriEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (e.ChannelUri != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;RegisterNotificationUri(e.ChannelUri);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Display the new URI for testing purposes. Normally, the URI would be passed back to your web service at this point.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;System.Diagnostics.Debug.WriteLine(e.ChannelUri.ToString());&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; PushChannel_ErrorOccurred(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, NotificationChannelErrorEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Error handling logic for your particular application would be here.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;MessageBox.Show(String.Format(&lt;span class="str"&gt;"A push notification {0} error occurred. {1} ({2}) {3}"&lt;/span&gt;,&lt;br/&gt;&lt;br/&gt;e.ErrorType, e.Message, e.ErrorCode, e.ErrorAdditionalData));&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;需要提示的是，这里的MessageBox是OpenXLive封装的MessageBox，用法和Silverlight中系统提供的一致。&lt;/p&gt;&lt;p&gt;最后，也是最核心的代码是注册Uri的部分代码：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RegisterNotificationUri(Uri uri)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Send Channel Uri to OpenXLive Hosting Server&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (OpenXLive.XLiveGameManager.CurrentSession != &lt;span class="kwrd"&gt;null&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&amp;amp;&amp;amp;&lt;br/&gt;&lt;br/&gt;OpenXLive.XLiveGameManager.CurrentSession.IsValid&lt;br/&gt;&lt;br/&gt;&amp;amp;&amp;amp;&lt;br/&gt;&lt;br/&gt;uri != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;OpenXLive.XLiveGameManager.CurrentSession.RegistNotificationUriCompleted&lt;br/&gt;&lt;br/&gt;+= &lt;span class="kwrd"&gt;new&lt;/span&gt; OpenXLive.Features.AsyncEventHandler(CurrentSession_RegistNotificationUriCompleted);&lt;br/&gt;&lt;br/&gt;OpenXLive.XLiveGameManager.CurrentSession.RegisterNotificationUri(uri);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; CurrentSession_RegistNotificationUriCompleted(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, OpenXLive.AsyncEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;OpenXLive.Features.AsyncProcessResult result = e.Result;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (result.ReturnValue)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;Debug.WriteLine(&lt;span class="str"&gt;"Channel Uri has been send to OpenXLive Hosting Server"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;Debug.WriteLine(result.ErrorMessage);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;好了，我们运行程序，然后将程序切换到后台，将游戏图标pin到主界面上，最后发送Tile Notification的效果如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942485835.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image026" border="0" alt="clip_image026" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942498625.png" width="263" height="436" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3. 发送Toast Notification&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;发送Toast Notification的代码如下：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateToastNotification()&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Try to find the push channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(ToastChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// If the channel was not found, then create a new connection to the push service.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;pushChannel = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotificationChannel(ToastChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Register for all the events before attempting to open the channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Register for this notification only if you need to receive the notifications while your application is running.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ShellToastNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationEventArgs&amp;gt;(PushChannel_ShellToastNotificationReceived);&lt;br/&gt;&lt;br/&gt;pushChannel.Open();&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Bind this new channel for Tile events.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.BindToShellToast();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// The channel was already open, so just register for all the events.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Register for this notification only if you need to receive the notifications while your application is running.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ShellToastNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationEventArgs&amp;gt;(PushChannel_ShellToastNotificationReceived);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Send Channel Uri to OpenXLive Hosting Server&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;RegisterNotificationUri(pushChannel.ChannelUri);&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;如果发送Toast Notification时，XNA游戏在运行，会调用下面的ShellToastNotificationReceived事件处理函数，显示MessageBox：&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; PushChannel_ShellToastNotificationReceived(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, NotificationEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;StringBuilder message = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; relativeUri = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;&lt;br/&gt;&lt;br/&gt;message.AppendFormat(&lt;span class="str"&gt;"Received Toast {0}:\n"&lt;/span&gt;, DateTime.Now.ToShortTimeString());&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Parse out the information that was part of the message.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; key &lt;span class="kwrd"&gt;in&lt;/span&gt; e.Collection.Keys)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;message.AppendFormat(&lt;span class="str"&gt;"{0}: {1}\n"&lt;/span&gt;, key, e.Collection[key]);&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.Compare(&lt;br/&gt;&lt;br/&gt;key,&lt;br/&gt;&lt;br/&gt;&lt;span class="str"&gt;"wp:Param"&lt;/span&gt;,&lt;br/&gt;&lt;br/&gt;System.Globalization.CultureInfo.InvariantCulture,&lt;br/&gt;&lt;br/&gt;System.Globalization.CompareOptions.IgnoreCase) == 0)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;relativeUri = e.Collection[key];&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Display a dialog of all the fields in the toast.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;MessageBox.Show(message.ToString());&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;需要特别提示的是，在XNA游戏中，命令行是无效的，如果添加一个无效的命令行参数，会造成程序崩溃，建议将命令行设为空即可。OpenXLive服务器发送Toast Notification后，运行效果如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942492737.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image028" border="0" alt="clip_image028" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942497164.png" width="248" height="410" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4. 发送Raw Notification&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;最后是Raw Notification，代码如下：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateRawNotification()&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Try to find the push channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(RawChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// If the channel was not found, then create a new connection to the push service.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;pushChannel = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotificationChannel(RawChannelName);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Register for all the events before attempting to open the channel.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;pushChannel.HttpNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;HttpNotificationEventArgs&amp;gt;(PushChannel_HttpNotificationReceived);&lt;br/&gt;&lt;br/&gt;pushChannel.Open();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// The channel was already open, so just register for all the events.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;&lt;br/&gt;pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;pushChannel.HttpNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;HttpNotificationEventArgs&amp;gt;(PushChannel_HttpNotificationReceived);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Display the URI for testing purposes. Normally, the URI would be passed back to your web service at this point.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;System.Diagnostics.Debug.WriteLine(pushChannel.ChannelUri.ToString());&lt;br/&gt;&lt;br/&gt;MessageBox.Show(String.Format(&lt;span class="str"&gt;"Channel Uri is {0}"&lt;/span&gt;,&lt;br/&gt;&lt;br/&gt;pushChannel.ChannelUri.ToString()));&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Send Channel Uri to OpenXLive Hosting Server&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;RegisterNotificationUri(pushChannel.ChannelUri);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; PushChannel_HttpNotificationReceived(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, HttpNotificationEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; message;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; (System.IO.StreamReader reader = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.IO.StreamReader(e.Notification.Body))&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;message = reader.ReadToEnd();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;MessageBox.Show(String.Format(&lt;span class="str"&gt;"Received Notification {0}:\n{1}"&lt;/span&gt;,&lt;br/&gt;&lt;br/&gt;DateTime.Now.ToShortTimeString(), message)&lt;br/&gt;&lt;br/&gt;);&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;运行效果如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942499639.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image030" border="0" alt="clip_image030" src="http://images.cnblogs.com/cnblogs_com/aawolf/201205/201205161942507654.png" width="472" height="285" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;到这里，我们就介绍了OpenXLive Push Notification Hosting Server的全部功能，需要指出的是，OpenXLive并没有提供自己的Push Notification服务，我们仍旧使用微软提供的Push Notification机制。OpenXLive Push Notification Hosting Server只是帮助那些没有服务器、又希望能够使用Push Notification服务的开发者，来管理Push Notification Channel，给他们一个友好的Web界面，供他们来发送自己的Push Notification消息。&lt;/p&gt;&lt;p&gt;如果您还有任何的疑问，或者需要更详细的帮助，欢迎您访问OpenXLive的官方网站&lt;/p&gt;&lt;p&gt;英文版：&lt;a href="http://www.openxlive.com/"&gt;http://www.openxlive.com/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;中文版：&lt;a href="http://www.openxlive.net/"&gt;http://www.openxlive.net/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;中文论坛：&lt;a href="http://bbs.openxlive.com/"&gt;http://bbs.openxlive.com/&lt;/a&gt;&lt;/p&gt; &lt;img src="http://www.cnblogs.com/aawolf/aggbug/2505146.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/aawolf/archive/2012/05/16/2505146.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/aawolf/archive/2011/10/03/2198607.html</id><title type="text">在Windows Phone应用中添加OpenXLive数据分析功能</title><summary type="text">作者：马宁源代码下载地址：http://files.cnblogs.com/aawolf/OpenXLiveAnalytics.zip 在Windows Phone中很多应用需要数据查询功能，来确定每天的用户数和应用使用次数等关键信息。在iOS和Android中已经有非常多的类似应用了，比如Flurry, 友盟等，但是Windows Phone上只有Flurry提供了此类功能。但由于很多开发者来说，没有中文支持的Flurry有些可望而不可即。 其实，在OpenXLive也提供数据分析的支持，只是之前更多是用于游戏数据的统计和查询上。在这篇文章里，我们将介绍，如何将OpenXLive的数据分析.</summary><published>2011-10-03T09:36:00Z</published><updated>2011-10-03T09:36:00Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><link rel="alternate" href="http://www.cnblogs.com/aawolf/archive/2011/10/03/2198607.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/archive/2011/10/03/2198607.html"/><content type="html">&lt;p&gt;作者：马宁&lt;/p&gt;&lt;p&gt;源代码下载地址：&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/aawolf/OpenXLiveAnalytics.zip"&gt;http://files.cnblogs.com/aawolf/OpenXLiveAnalytics.zip&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &lt;/p&gt;&lt;p&gt;在Windows Phone中很多应用需要数据查询功能，来确定每天的用户数和应用使用次数等关键信息。在iOS和Android中已经有非常多的类似应用了，比如Flurry, 友盟等，但是Windows Phone上只有Flurry提供了此类功能。但由于很多开发者来说，没有中文支持的Flurry有些可望而不可即。&lt;/p&gt;  &lt;p&gt;其实，在OpenXLive也提供数据分析的支持，只是之前更多是用于游戏数据的统计和查询上。在这篇文章里，我们将介绍，如何将OpenXLive的数据分析功能应用在Windows Phone的应用程序开发中。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;创建OpenXLive应用&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;因为所有的统计数据都是保存在OpenXLive的云端存储服务器中，所以，我们要在OpenXLive网站上创建一个应用。&lt;/p&gt;  &lt;p&gt;首先，登录OpenXLive网站(&lt;a href="http://www.openxlive.com/"&gt;http://www.openxlive.com/&lt;/a&gt;)，如果没有帐号，我们需要创建一个相应的帐号，通过电子邮件激活帐号之后，我们还需要升级成为开发者。&lt;/p&gt;  &lt;p&gt;在激活邮件地址后，我们重新回到OpenXLive的网站，输入用户名和密码后，我们会进入用户资料编辑界面，在这里，我们可以填写完整的个人信息，使得朋友在网络中更加容易地找到你。用户资料中最后一项为&amp;#8220;Developer Information&amp;#8221;。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031735226475.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; margin-right: auto; margin-left: auto; float: none; display: block;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/aawolf/201110/20111003173525638.png" width="591" height="417" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;点击&amp;#8220;Developer Information&amp;#8221;，进入开发者申请界面：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201110/20111003173527407.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; margin-right: auto; margin-left: auto; float: none; display: block;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031735317536.png" width="401" height="447" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;在这个页面，我们要填写开发者类型（个人/公司/学生）、国家、城市、地址、电话、IM等信息。在填写完成后，我们会看到下面的开发者注册成功界面。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201110/20111003173533893.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; margin-right: auto; margin-left: auto; float: none; display: block;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/aawolf/201110/20111003173536529.png" width="545" height="238" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;在这个界面中，我们可以进入OpenXLive开发者首页，查看开发指南，也可以直接点击&amp;#8220;Create New Game&amp;#8221;，进入开发者后台。&lt;/p&gt;  &lt;p&gt;进入开发者后台界面之后，如果您之前已经创建过游戏，会显示已创建游戏的列表，如上图所示。在用户图标的下方，有Create New Game的按钮，点击，进入创建新游戏的界面。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031735425541.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; margin-right: auto; margin-left: auto; float: none; display: block;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031735465918.png" width="539" height="548" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;添加OpenXLive引用&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;为了引用OpenXLive的程序集，我们必须首先下载OpenXLive SDK并且完成安装。下载地址是：&lt;a href="http://developer.openxlive.com/sdk/download/"&gt;http://developer.openxlive.com/sdk/download/&lt;/a&gt; 目前的版本是0.9.6.&lt;/p&gt;  &lt;p&gt;创建Windows Phone Silverlight应用后，我们要获取OpenXLive的程序集。在开始菜单中，找到OpenXLive应用，其中OpenXLive目录下包括XNA和Silverlight两个目录。我们从Silverlight目录中取出OpenXLive.dll程序集，拷贝至我们的应用所在的目录。&lt;/p&gt;  &lt;p&gt;然后在Solution Explorer中，右键单击References，选择Add Reference。在对话框中选择Browse页面，然后找到OpenXLive.dll，将其添加到工程中。&lt;/p&gt;  &lt;p&gt;因为我们不需要OpenXLive的界面，所以只需要添加OpenXLive.dll即可。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031735512947.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; margin-right: auto; margin-left: auto; float: none; display: block;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031735556596.png" width="579" height="471" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;在添加完引用之后，我们就可以添加代码了。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;创建Session&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;接下来，我们要为工程添加OpenXLive的引用代码。打开工程中的App.xaml.cs文件，首先找到Application_Launching方法：&lt;/p&gt;  &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Launching(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, LaunchingEventArgs e)&lt;br/&gt;{&lt;br/&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (XLiveGameManager.CurrentSession == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;    {&lt;br/&gt;        GameSession session = XLiveGameManager.CreateSession(&lt;span class="str"&gt;"xxxxxxxx"&lt;/span&gt;);&lt;br/&gt;        session.CreateSessionCompleted += &lt;span class="kwrd"&gt;new&lt;/span&gt; AsyncEventHandler(session_CreateSessionCompleted);&lt;br/&gt;        session.Open();&lt;br/&gt;    }&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;我们在这个方法里判断是否已经有Game Session存在，如果没有的话，则调用XLiveGameManager的CreateSession方法来创建一个Game Session，需要传递的参数，是我们在OpenXLive网站上获得的Secret Key。&lt;/p&gt;&lt;p&gt;然后，我们可以添加一个CreateSessionCompleted事件处理函数，来获取Game Session是否被创建的事件。当然，这个事件处理函数是可选的，我们可以不添加。&lt;/p&gt;&lt;p&gt;最后，调用Game Session的Open方法，来打开Game Session就可以了。&lt;/p&gt;&lt;p&gt;然后是关闭这个Game Session，在Application_Closing方法里调用Close方法。&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Closing(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ClosingEventArgs e)&lt;br/&gt;{&lt;br/&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (XLiveGameManager.CurrentSession != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;    {&lt;br/&gt;        XLiveGameManager.CurrentSession.Close();&lt;br/&gt;    }&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;如果我们不显式调用Close方法的话，Game Session在创建24小时后会自动过期，所以也不会造成太大的影响，唯一的问题是游戏时间将失效。&lt;/p&gt;&lt;p&gt;为了支持墓碑机制，我们还要特意在Application_Activated和Application_Deactivated函数中，添加对于墓碑机制的处理。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Activated(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ActivatedEventArgs e)&lt;br/&gt;{&lt;br/&gt;    XLiveGameManager.Activated();&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Deactivated(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, DeactivatedEventArgs e)&lt;br/&gt;{&lt;br/&gt;    XLiveGameManager.Deactivated();&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;好了，到这里我们就大功告成了，够简单吧？&lt;/p&gt;&lt;p&gt;&lt;strong&gt;查看数据结果&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;当我们的Windows Phone软件发布之后，就可以在OpenXLive网站上查看应用程序的在线数据了。&lt;/p&gt;&lt;p&gt;首先，我们访问OpenXLive网站&lt;a href="http://www.openxlive.com/"&gt;http://www.openxlive.com/&lt;/a&gt; ，在网页右上角点击Login登录，成功登录之后，我们会在OpenXLive首页右上角的位置看到下面的网页：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031735588840.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; margin-right: auto; margin-left: auto; float: none; display: block;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031736021758.png" width="391" height="146" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;点击My Game，可以进入游戏后台管理的Dashboard中。如果用户登录后，访问OpenXLive开发者网站(&lt;a href="http://developer.openxlive.com/"&gt;http://developer.openxlive.com/&lt;/a&gt;)，在右侧的Dashboard中选择&amp;#8220;Managed your games&amp;#8221;也可以进入开发者后台管理界面。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031736042607.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; margin-right: auto; margin-left: auto; float: none; display: block;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031736079245.png" width="607" height="348" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;上图所示，包括我们创建的所有游戏和应用，点击应用图标会进入应用的产业页面，点击应用标题，则进入应用的管理界面。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031736093474.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; margin-right: auto; margin-left: auto; float: none; display: block;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/aawolf/201110/20111003173613603.png" width="674" height="255" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;点击管理界面中的Statistics按钮，进入数据分析界面。&lt;/p&gt;&lt;p&gt;在数据分析界面中，我们可以查看一些通用信息，比如创建Session的数量、使用人数等信息。点击View，则进入详细数据分析界面。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031736158453.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; margin-right: auto; margin-left: auto; float: none; display: block;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031736174252.png" width="690" height="396" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;在详细数据分析界面中，我们可以考到用户数、Session数的时间分布，按照月、周、日来进行显示等。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031736219396.png"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; margin-right: auto; margin-left: auto; float: none; display: block;background-image: none;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/aawolf/201110/201110031736241889.png" width="615" height="360" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;好了，到这里，我们就介绍完OpenXLive目前的数据分析功能。下一步，OpenXLive还会加入自定义事件、地理分布信息等功能。&lt;/p&gt;  &lt;img src="http://www.cnblogs.com/aawolf/aggbug/2198607.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/aawolf/archive/2011/10/03/2198607.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/aawolf/archive/2011/08/25/2153827.html</id><title type="text">Kinect for Windows SDK开发初体验（四）景深数据</title><summary type="text">作者：马宁 终于可以坐下来继续这个系列了，在微博和博客园里，已经有无数人催过了，实在抱歉，一个人的精力毕竟是有限的，但我会抽出一切可用的时间，尽可能尽快完成。 这一章我们来说说景深数据Depth Data，这是Kinect的Depth Camera为我们提供的全新功能，以往的技术只能够通过图像识别来完成的一些工作，我们可以借助景深来帮我们完成了。比如，前景与背景的分离，以前只能将背景设置为蓝屏或者绿屏，但是现在有了景深数据，我们就可以很容易地将前景物体从背景中分离出来。当然，需要特别说明的是，Depth Camera技术是由以色列公司PrimeSense提供的。 程序布局 在这一章里，我们要完</summary><published>2011-08-25T14:26:00Z</published><updated>2011-08-25T14:26:00Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><link rel="alternate" href="http://www.cnblogs.com/aawolf/archive/2011/08/25/2153827.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/archive/2011/08/25/2153827.html"/><content type="html">&lt;p&gt;作者：马宁 &lt;p&gt;终于可以坐下来继续这个系列了，在微博和博客园里，已经有无数人催过了，实在抱歉，一个人的精力毕竟是有限的，但我会抽出一切可用的时间，尽可能尽快完成。 &lt;p&gt;这一章我们来说说景深数据Depth Data，这是Kinect的Depth Camera为我们提供的全新功能，以往的技术只能够通过图像识别来完成的一些工作，我们可以借助景深来帮我们完成了。比如，前景与背景的分离，以前只能将背景设置为蓝屏或者绿屏，但是现在有了景深数据，我们就可以很容易地将前景物体从背景中分离出来。当然，需要特别说明的是，Depth Camera技术是由以色列公司PrimeSense提供的。 &lt;p&gt;&lt;strong&gt;程序布局&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;在这一章里，我们要完成的工作非常简单，根据物体距离Kinect的远近，设置成不同的颜色。首先，我们要创建一个新的WPF工程，然后添加一个Image控件：&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Image&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="240"&lt;/span&gt; &lt;span class="attr"&gt;HorizontalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;="Left"&lt;/span&gt; &lt;span class="attr"&gt;Margin&lt;/span&gt;&lt;span class="kwrd"&gt;="62,41,0,0"&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="image1"&lt;/span&gt; &lt;span class="attr"&gt;Stretch&lt;/span&gt;&lt;span class="kwrd"&gt;="Fill"&lt;/span&gt; &lt;span class="attr"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;="Top"&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="320"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;p&gt;然后是MainWindow.xaml.cs中的核心代码，这部分代码与之前的代码大体一致，所以不做过多解释了：&lt;span class="rem"&gt;//Kinect RuntimeRuntime &lt;/span&gt;&lt;br/&gt;&lt;br/&gt;Runtime nui = &lt;span class="kwrd"&gt;new&lt;/span&gt; Runtime(); &lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Window_Loaded(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//UseDepthAndPlayerIndex and UseSkeletalTracking&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;nui.Initialize(RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//register for event&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;nui.DepthFrameReady += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;ImageFrameReadyEventArgs&amp;gt;(nui_DepthFrameReady);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//DepthAndPlayerIndex ImageType&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240,&lt;br/&gt;&lt;br/&gt;ImageType.DepthAndPlayerIndex);&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Window_Closed(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;nui.Uninitialize();&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;nbsp; &lt;p&gt;唯一需要大家注意的是，我们在初始化函数中传递的参数是RuntimeOptions.UseDepthAndPlayerIndex，这表示景深信息中会包含PlayerIndex的信息。接下来，我们就要花点时间来理解DepthAndPlayerIndex的实际结构。&lt;p&gt;&lt;strong&gt;理解DepthAndPlayerIndex&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;先来看DepthFrameReady事件处理函数，如下：&lt;span class="kwrd"&gt;void&lt;/span&gt; nui_DepthFrameReady(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ImageFrameReadyEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Convert depth information for a pixel into color information &lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] ColoredBytes = GenerateColoredBytes(e.ImageFrame); &lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// create an image based on the colored bytes &lt;/span&gt;&lt;br/&gt;&lt;br/&gt;PlanarImage image = e.ImageFrame.Image;&lt;br/&gt;&lt;br/&gt;image1.Source = BitmapSource.Create( &lt;br/&gt;&lt;br/&gt;image.Width, image.Height, 96, 96, PixelFormats.Bgr32, &lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;null&lt;/span&gt;, ColoredBytes, image.Width * PixelFormats.Bgr32.BitsPerPixel / 8); &lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;nbsp; &lt;p&gt;DepthFrameReady事件会返回一个ImageFrame对象，其中会包含一个PlanarImage对象。PlanarImage对象会包含一个byte[]数组，这个数组中包含每个像素的深度信息。这个数组的特点是，从图像左上角开始、从左到右，然后从上到下。&lt;p&gt;该数组中每个像素由两个bytes表示，我们需要通过位运算的办法来获取每个像素的位置信息。&lt;p&gt;如果是Depth Image Type，将第二个bytes左移8位即可。Distance (0,0) = (&lt;span class="kwrd"&gt;int&lt;/span&gt;)(Bits[0] | Bits[1] &amp;lt;&amp;lt; 8 );&amp;nbsp;&lt;p&gt;如果是DepthAndPlayerIndex Image Type，第一个bytes右移三位去掉Player Index信息，第二个bytes左移5位。Distance (0,0) =(&lt;span class="kwrd"&gt;int&lt;/span&gt;)(Bits[0] &amp;gt;&amp;gt; 3 | Bits[1] &amp;lt;&amp;lt; 5);&amp;nbsp;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;DepthAndPlayerIndex image类型的第一个bytes前三位包括Player Index信息。Player Index最多包含六个可能值：&lt;p&gt;0， 没有玩家；1，玩家1；2，玩家2，以此类推。&lt;p&gt;我们可以用下面的方法来获取Player Index信息：&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetPlayerIndex(&lt;span class="kwrd"&gt;byte&lt;/span&gt; firstFrame)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//returns 0 = no player, 1 = 1st player, 2 = 2nd player...&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt;)firstFrame &amp;amp; 7; &lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;nbsp; &lt;p&gt;&lt;strong&gt;设置颜色&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;接下来，我们创建一个bytes数组，用来存储颜色值。&lt;span class="kwrd"&gt;if&lt;/span&gt; (distance &amp;lt;= 900)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//we are very close&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;colorFrame[index + BlueIndex] = 255;&lt;br/&gt;&lt;br/&gt;colorFrame[index + GreenIndex] = 0;&lt;br/&gt;&lt;br/&gt;colorFrame[index + RedIndex] = 0;&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (GetPlayerIndex(depthData[depthIndex]) &amp;gt; 0)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//we are the farthest&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;colorFrame[index + BlueIndex] = 0;&lt;br/&gt;&lt;br/&gt;colorFrame[index + GreenIndex] = 255;&lt;br/&gt;&lt;br/&gt;colorFrame[index + RedIndex] = 255;&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;当然，我们最好是设置几个边界值，来定义不同距离的不同颜色：&lt;span class="rem"&gt;//equal coloring for monochromatic histogram&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;var intensity = CalculateIntensityFromDepth(distance);&lt;br/&gt;&lt;br/&gt;colorFrame[index + BlueIndex] = intensity;&lt;br/&gt;&lt;br/&gt;colorFrame[index + GreenIndex] = intensity;&lt;br/&gt;&lt;br/&gt;colorFrame[index + RedIndex] = intensity;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;float&lt;/span&gt; MaxDepthDistance = 4000; &lt;span class="rem"&gt;// max value returned&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;float&lt;/span&gt; MinDepthDistance = 850; &lt;span class="rem"&gt;// min value returned&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;float&lt;/span&gt; MaxDepthDistanceOffset = MaxDepthDistance - MinDepthDistance;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt; CalculateIntensityFromDepth(&lt;span class="kwrd"&gt;int&lt;/span&gt; distance)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//formula for calculating monochrome intensity for histogram&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(255 - (255 * Math.Max(distance - MinDepthDistance, 0) / (MaxDepthDistanceOffset)));&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;最后，把所有代码放在一起，我们设定的颜色值为：&lt;p&gt;蓝色，小于900；900到2000，绿色；大于2000，红色&lt;p&gt;代码如下：        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] GenerateColoredBytes(ImageFrame imageFrame)&lt;br/&gt;        {    &lt;br/&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; height = imageFrame.Image.Height;    &lt;br/&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; width = imageFrame.Image.Width;     &lt;br/&gt;            &lt;br/&gt;            &lt;span class="rem"&gt;//Depth data for each pixel    &lt;/span&gt;&lt;br/&gt;            Byte[] depthData = imageFrame.Image.Bits;      &lt;br/&gt;            &lt;br/&gt;            &lt;span class="rem"&gt;//colorFrame contains color information for all pixels in image    &lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;//Height x Width x 4 (Red, Green, Blue, empty byte)    &lt;/span&gt;&lt;br/&gt;            Byte[] colorFrame = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[imageFrame.Image.Height * imageFrame.Image.Width * 4];     &lt;br/&gt;            &lt;br/&gt;            &lt;span class="rem"&gt;//Bgr32  - Blue, Green, Red, empty byte    &lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;//Bgra32 - Blue, Green, Red, transparency     &lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;//You must set transparency for Bgra as .NET defaults a byte to 0 = fully transparent     &lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;//hardcoded locations to Blue, Green, Red (BGR) index positions           &lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; BlueIndex = 0;    &lt;br/&gt;            &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GreenIndex = 1;    &lt;br/&gt;            &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; RedIndex = 2;     &lt;br/&gt;            var depthIndex = 0;    &lt;br/&gt;            &lt;br/&gt;            &lt;span class="kwrd"&gt;for&lt;/span&gt; (var y = 0; y &amp;lt; height; y++)    &lt;br/&gt;            {                &lt;br/&gt;                var heightOffset = y * width;         &lt;br/&gt;                &lt;br/&gt;                &lt;span class="kwrd"&gt;for&lt;/span&gt; (var x = 0; x &amp;lt; width; x++)        &lt;br/&gt;                {            &lt;br/&gt;                    var index = ((width - x - 1) + heightOffset) * 4;             &lt;br/&gt;                    &lt;br/&gt;                    &lt;span class="rem"&gt;//var distance = GetDistance(depthData[depthIndex], depthData[depthIndex + 1]);            &lt;/span&gt;&lt;br/&gt;                    var distance = GetDistanceWithPlayerIndex(depthData[depthIndex], depthData[depthIndex + 1]);             &lt;br/&gt;                    &lt;br/&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (distance &amp;lt;= 900)            &lt;br/&gt;                    {                &lt;br/&gt;                        &lt;span class="rem"&gt;//we are very close                &lt;/span&gt;&lt;br/&gt;                        colorFrame[index + BlueIndex] = 255;                &lt;br/&gt;                        colorFrame[index + GreenIndex] = 0;                &lt;br/&gt;                        colorFrame[index + RedIndex] = 0;                   &lt;br/&gt;                    }            &lt;br/&gt;                    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (distance &amp;gt; 900 &amp;amp;&amp;amp; distance &amp;lt; 2000)            &lt;br/&gt;                    {                &lt;br/&gt;                        &lt;span class="rem"&gt;//we are a bit further away                &lt;/span&gt;&lt;br/&gt;                        colorFrame[index + BlueIndex] = 0;                &lt;br/&gt;                        colorFrame[index + GreenIndex] = 255;                &lt;br/&gt;                        colorFrame[index + RedIndex] = 0;            &lt;br/&gt;                    }            &lt;br/&gt;                    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (distance &amp;gt; 2000)            &lt;br/&gt;                    {                &lt;br/&gt;                        &lt;span class="rem"&gt;//we are the farthest                &lt;/span&gt;&lt;br/&gt;                        colorFrame[index + BlueIndex] = 0;                &lt;br/&gt;                        colorFrame[index + GreenIndex] = 0;                &lt;br/&gt;                        colorFrame[index + RedIndex] = 255;            &lt;br/&gt;                    }             &lt;br/&gt;                    &lt;br/&gt;                    &lt;span class="rem"&gt;//Color a player            &lt;/span&gt;&lt;br/&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (GetPlayerIndex(depthData[depthIndex]) &amp;gt; 0)            &lt;br/&gt;                    {                &lt;br/&gt;                        &lt;span class="rem"&gt;//we are the farthest                &lt;/span&gt;&lt;br/&gt;                        colorFrame[index + BlueIndex] = 0;                &lt;br/&gt;                        colorFrame[index + GreenIndex] = 255;                &lt;br/&gt;                        colorFrame[index + RedIndex] = 255;            &lt;br/&gt;                    }             &lt;br/&gt;                    &lt;br/&gt;                    &lt;span class="rem"&gt;//jump two bytes at a time            &lt;/span&gt;&lt;br/&gt;                    depthIndex += 2;        &lt;br/&gt;                &lt;br/&gt;                }    &lt;br/&gt;            }     &lt;br/&gt;            &lt;br/&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; colorFrame;&lt;br/&gt;        }&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;程序的现实效果如下图：&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108252226245933.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image001" border="0" alt="clip_image001" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108252226253392.png" width="527" height="353"&gt;&lt;/a&gt;&lt;p&gt;&lt;strong&gt;写到最后&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;到这里，我们就将Kinect SDK中NUI的基本内容介绍完了，接下来，我们要介绍Audio部分，或者借助一些实际的例子，来看一下Kinect SDK的实际应用。&lt;/p&gt; &lt;img src="http://www.cnblogs.com/aawolf/aggbug/2153827.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/aawolf/archive/2011/08/25/2153827.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/aawolf/archive/2011/08/03/2125692.html</id><title type="text">马宁的Windows Phone 7.1初体验（三）——Tile</title><summary type="text">作者：马宁 前边介绍Push Notification时，其实已经谈到了Tile Notification。在Windows Phone 7.1中，Smart Tile得到了极大的提高。我们不但可以控制Tile的动画显示、内容和背景切换，而且还能够为同一个应用提供两个Tile，比如一个天气预报的应用程序，就可以在手机的首页上显示多个Tile，一个是北京的天气，另一个是上海的天气等。 实现Application Tile MSDN上的文章写的又臭又长，其实挺简单的事情，弄得那么复杂。我试着改写了一下例子，加入到应用的一个Button点击事件里： // Application Tile is al</summary><published>2011-08-02T18:36:00Z</published><updated>2011-08-02T18:36:00Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><link rel="alternate" href="http://www.cnblogs.com/aawolf/archive/2011/08/03/2125692.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/archive/2011/08/03/2125692.html"/><content type="html">&lt;p&gt;&lt;b&gt;作者：马宁&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;前边介绍Push Notification时，其实已经谈到了Tile Notification。在Windows Phone 7.1中，Smart Tile得到了极大的提高。我们不但可以控制Tile的动画显示、内容和背景切换，而且还能够为同一个应用提供两个Tile，比如一个天气预报的应用程序，就可以在手机的首页上显示多个Tile，一个是北京的天气，另一个是上海的天气等。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;实现Application Tile&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;MSDN上的文章写的又臭又长，其实挺简单的事情，弄得那么复杂。我试着改写了一下例子，加入到应用的一个Button点击事件里：&lt;/p&gt;              &lt;span class="rem"&gt;// Application Tile is always the first Tile, even if it is not pinned to Start.&lt;/span&gt;&lt;br/&gt;            ShellTile TileToFind = ShellTile.ActiveTiles.First();&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Set the properties to update for the Application Tile.&lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Empty strings for the text values and URIs will result in the property being cleared.&lt;/span&gt;&lt;br/&gt;            StandardTileData NewTileData = &lt;span class="kwrd"&gt;new&lt;/span&gt; StandardTileData&lt;br/&gt;            {&lt;br/&gt;                Title = &lt;span class="str"&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;,&lt;br/&gt;                BackgroundImage = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;&amp;quot;Background.png&amp;quot;&lt;/span&gt;, UriKind.Relative),&lt;br/&gt;                Count = 2,&lt;br/&gt;                BackTitle = &lt;span class="str"&gt;&amp;quot;Back Tilte&amp;quot;&lt;/span&gt;,&lt;br/&gt;                BackBackgroundImage = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;&amp;quot;Background2.png&amp;quot;&lt;/span&gt;, UriKind.Relative),&lt;br/&gt;                BackContent = &lt;span class="str"&gt;&amp;quot;This is BackContent&amp;quot;&lt;/span&gt;&lt;br/&gt;            };&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Update the Application Tile&lt;/span&gt;&lt;br/&gt;            TileToFind.Update(NewTileData);&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;首先，我们要引用Microsoft.Phone.Shell命名空间，然后通过ShellTile.ActiveTiles.First()方法来获取应用最主要的ShellTile.每个应用至少会有一个Tile，所以不用担心该对象为空。然后我们创建一个StandardTileData对象，为其中的属性赋值。属性分为两组，每组都会有背景图片、标题和内容，显示位置如下图所示。如果设置两组Tile属性，则Tile在显示一段时间后会自动切换。最后，我们调用ShellTile对象的Update方法，将StandardTileData对象传递进去，就完成了新Tile的设置。BackgroundImage和BackBackgroundImage指定的是图片的URI，可以是本地的图片，也可以是来自网络的图片。我们使用的两个图片，都是以Content方式加入到工程中的图片。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235567616.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235574617.jpg" width="527" height="226" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;当我们将程序部署到设备或模拟器上时，首先会在Application List里出现对应的图标。我们长按图标，会出现一个菜单，选择Pin to start，会将应用程序的图标显示到手机首页上。&lt;/p&gt;&lt;p&gt;运行应用程序，点击Button后，Tile会被更新成新的式样。两张背景和内容会交替显示，显示效果如下图所示：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235579318.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image004" border="0" alt="clip_image004" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235576843.jpg" width="269" height="500" /&gt;&lt;/a&gt; &lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235576319.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006" border="0" alt="clip_image006" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235588304.jpg" width="271" height="500" /&gt;&lt;/a&gt; &lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235587781.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image008" border="0" alt="clip_image008" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235585306.jpg" width="268" height="499" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;实现 Secondary Tile&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在完成了Application Tile的显示之后，我们接下来要实现更复杂的Secondary Tile，当然，我们可以添加多个Tile。在实现Secondary Tile时，有两个技术点需要实现，一个是Tile的添加与显示；另一个则是，程序启动时如何区分是由哪个Tile点击启动应用的。&lt;/p&gt;&lt;p&gt;首先，我们来看如何添加Secondary Tile的代码：&lt;/p&gt;            &lt;span class="rem"&gt;// Look to see whether the Tile already exists and if so, don't try to create it again.&lt;/span&gt;&lt;br/&gt;            ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault(x =&amp;gt; x.NavigationUri.ToString().Contains(&lt;span class="str"&gt;&amp;quot;DefaultTitle=FromTile&amp;quot;&lt;/span&gt;));&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Create the Tile if we didn't find that it already exists.&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (TileToFind == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;            {&lt;br/&gt;                &lt;span class="rem"&gt;// Create the Tile object and set some initial properties for the Tile.&lt;/span&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// The Count value of 12 shows the number 12 on the front of the Tile. Valid values are 1-99.&lt;/span&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// A Count value of 0 indicates that the Count should not be displayed.&lt;/span&gt;&lt;br/&gt;                StandardTileData NewTileData = &lt;span class="kwrd"&gt;new&lt;/span&gt; StandardTileData&lt;br/&gt;                {&lt;br/&gt;                    BackgroundImage = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;&amp;quot;Background.png&amp;quot;&lt;/span&gt;, UriKind.Relative),&lt;br/&gt;                    Title = &lt;span class="str"&gt;&amp;quot;Secondary Tile&amp;quot;&lt;/span&gt;,&lt;br/&gt;                    Count = 12,&lt;br/&gt;                    BackTitle = &lt;span class="str"&gt;&amp;quot;Back of Tile&amp;quot;&lt;/span&gt;,&lt;br/&gt;                    BackContent = &lt;span class="str"&gt;&amp;quot;Welcome to the back of the Tile&amp;quot;&lt;/span&gt;,&lt;br/&gt;                    BackBackgroundImage = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;&amp;quot;Background2.png&amp;quot;&lt;/span&gt;, UriKind.Relative)&lt;br/&gt;                };&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Create the Tile and pin it to Start. This will cause a navigation to Start and a deactivation of our application.&lt;/span&gt;&lt;br/&gt;                ShellTile.Create(&lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;&amp;quot;/MainPage.xaml?DefaultTitle=FromTile&amp;quot;&lt;/span&gt;, UriKind.Relative), NewTileData);&lt;br/&gt;            }&lt;br/&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;            {&lt;br/&gt;                TileToFind.Delete();&lt;br/&gt;            }&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;首先调用ShellTile.ActiveTiles.FirstOrDefault方法，获取在NavigationUri属性中包含&amp;#8220;DefaultTitle=FromTile&amp;#8221;字样的ShellTile对象，如果获取到的ShellTile对象为空，则创建Secondary Tile，否则调用ShellTile的Delete方法，删除这个Tile。&lt;/p&gt;&lt;p&gt;创建Secondary Tile的过程，首先创建StandardTileData对象，将显示的各个参数进行赋值，这一步与Application Tile相同；然后，调用ShellTile的Create方法，第一个参数是URI，即点击该Tile后，调用Page的命令行，可以包含参数，第二个参数是StandardTileData对象，用于指定显示式样。&lt;/p&gt;&lt;p&gt;需要注意的是，如果Page命令行指定不对，会引起用户点击Tile时，应用直接退出，由于无法调试，第一次接触这个问题时，会找不到具体的原因。&lt;/p&gt;&lt;p&gt;Secondary Tile显示效果如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235584782.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image010" border="0" alt="clip_image010" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235592307.jpg" width="253" height="470" /&gt;&lt;/a&gt; &lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030235597008.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image012" border="0" alt="clip_image012" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/20110803023559945.jpg" width="248" height="468" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;接下来，我们就要处理区分不同Tile点击的事件了，需要重载MainForm的OnNavigatedTo方法：&lt;/p&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt; = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.NavigationContext.QueryString != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;            {&lt;br/&gt;                &lt;span class="kwrd"&gt;this&lt;/span&gt;.NavigationContext.QueryString.TryGetValue(&lt;span class="str"&gt;&amp;quot;DefaultTitle&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;out&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt;);&lt;br/&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;value&lt;/span&gt; != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;                {&lt;br/&gt;                    textBoxTitle.Text = &lt;span class="kwrd"&gt;value&lt;/span&gt;;&lt;br/&gt;                }&lt;br/&gt;                &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;                {&lt;br/&gt;                    textBoxTitle.Text = &lt;span class="str"&gt;&amp;quot;FromMain&amp;quot;&lt;/span&gt;;&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnNavigatedTo(e);&lt;br/&gt;        }&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;通过NavigationContext.QueryString的TryGetValue方法来获取DefaultTitle参数的值，如果无法获取到该值，则认为该点击来自第一个Tile，相反则来自第二个Tile。我们将参数显示在主页面的文本框里，当然，实际应用中可以有更加复杂的业务逻辑。界面显示效果如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/20110803023559421.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image014" border="0" alt="clip_image014" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030236009582.jpg" width="280" height="526" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;到这里，我们简单介绍了如何添加Tile、修改Tile内容，除此之外，还有如何修改Tile的初始值，指定Tile更新的时间间隔等。在这里，我们就不介绍了，大家可以参考又臭又长的MSDN文档，这部分不长，我可以保证。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;好了，到这里，我们正式将Windows Phone 7.1中的Tile编程的内容介绍完了。Windows Phone采用的是HUB方式，对于功能进行分类，所以，就要求Tile具备更丰富的显示方式和展现形式。而且，多个应用可以对应于一个Tile，同样一个应用也可以对应多个Tile，这样极大提高了主页与应用之间交互的丰富程度。&lt;/p&gt;&lt;p&gt;当然，具体的Tile，还要在实际的开发中使用，才能真正了解其优缺点。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;OpenXLive杯Windows Phone游戏开发大赛&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030236003519.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image016" border="0" alt="clip_image016" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108030236004632.jpg" width="212" height="225" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;OpenXLive杯Windows Phone游戏开发大赛，是由OpenXLive联合国内知名的开发者社区：DevDiv、智机网、WPMind、Silverlight银光中国和XNA游戏世界，一起举办的针对Windows Phone游戏开发的比赛。&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.openxlive.net/posts/news/40"&gt;http://www.openxlive.net/posts/news/40&lt;/a&gt;&lt;/p&gt; &lt;img src="http://www.cnblogs.com/aawolf/aggbug/2125692.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/aawolf/archive/2011/08/03/2125692.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/aawolf/archive/2011/08/02/2124442.html</id><title type="text">马宁的Windows Phone 7.1初体验（二）——Push Notification</title><summary type="text">作者：马宁 Push Notification并不是Windows Phone 7.1的新功能，但是之前的文章里对这部分都缺少详细的分析，所以姑且就把Push Notification放到这部分里吧。 很多iOS开发者都将WP7里的Push Notification说成抄袭iOS的产物，孰不知，微软才是Push Notification技术的先行者，Windows Mobile时代的Push Mail技术可以说是独步天下，连Symbian也要授权使用相关的技术。 Push Notification的技术为什么越来越重要，其实这跟移动设备的特点紧密相关，移动设备网络的不稳定性，决定了以Socke</summary><published>2011-08-01T17:24:00Z</published><updated>2011-08-01T17:24:00Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><link rel="alternate" href="http://www.cnblogs.com/aawolf/archive/2011/08/02/2124442.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/archive/2011/08/02/2124442.html"/><content type="html">&lt;p&gt;&lt;strong&gt;作者：马宁&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Push Notification并不是Windows Phone 7.1的新功能，但是之前的文章里对这部分都缺少详细的分析，所以姑且就把Push Notification放到这部分里吧。&lt;/p&gt; &lt;p&gt;很多iOS开发者都将WP7里的Push Notification说成抄袭iOS的产物，孰不知，微软才是Push Notification技术的先行者，Windows Mobile时代的Push Mail技术可以说是独步天下，连Symbian也要授权使用相关的技术。&lt;/p&gt; &lt;p&gt;Push Notification的技术为什么越来越重要，其实这跟移动设备的特点紧密相关，移动设备网络的不稳定性，决定了以Socket为代表的强连接方式并不适用，所以大家更多选择HTTP协议作为主要的通讯方式。但是HTTP的特点是，设备找服务器很容易，通过URL就可以了，但服务器找设备就难上加难了，因为设备会随时切换移动网络，IP地址之类的经常性失效。当然设备端轮询的方式可以解决这个问题，但移动设备的电源、网络都是稀缺资源。所以，OS级别的Push Notification技术就变成了一种珍贵的战略资源，而且，在封闭式的操作系统中，只有OS厂商提供的Push Notification才能够获得最好的效率。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Push Notification简介&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;目前，Windows Phone支持三种Push Notification方式：Toast Notifications、Tile Notifications和Raw Notifications，我不想翻译成中文名字了，因为&amp;#8220;吐司&amp;#8221;之类的翻译无法帮助理解。&lt;/p&gt; &lt;p&gt;Toast Notifications，当我们的程序没有运行时，我们希望有一种形式可以通知用户，并且让用户调用对应的应用，就像收到SMS时，调用Messaging程序一样。运行效果如下图，当用户点击Toast时，可以调用对应的程序。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108020123526989.jpg"&gt;&lt;img style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image002" border="0" alt="clip_image002" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108020123538842.jpg" width="340" height="213" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Tile Notifications，用于更新启动界面上的Tile，可以通过Tile Notifications设置Tile的背景图片、Count和Title等属性，各属性显示位置如下图所示。我们可以通过该技术来提示用户，我们的应用有新的事件发生，比如SNS上有多少新的回复等。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108020123533269.jpg"&gt;&lt;img style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image004" border="0" alt="clip_image004" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108020123533792.jpg" width="343" height="148" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Raw Notifications，最简单，当你的应用程序运行时，可以接收Raw Notification信息，如果程序没有运行，则接受不到Raw Notification。&lt;/p&gt; &lt;p&gt;接下来，我们会以Toast Notifications为例详细介绍，Push Notification的原理和使用方法。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108020123531807.jpg"&gt;&lt;img style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image006" border="0" alt="clip_image006" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108020123549822.jpg" width="643" height="422" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;首先，还是引用这张广为流传的图示吧，确实是目前能够找到的最详细的示意图了。下面是步骤叙述：&lt;/p&gt; &lt;p&gt;1-3，应用通过调用HttpNotificationChannel接口，向Microsoft Push Notification Service (MPNS)请求一个URI，这个URI会在服务器端发送Notification消息时，作为验证发送目标的唯一标识；这样做的一个好处是，当同一个设备上有多个应用在监听Notification时，不会相互干扰。&lt;/p&gt; &lt;p&gt;4. 应用会将获得的URI传到自己的服务器上，这个URI会存储在自己的服务器上，用于发送Push Notification时调用。URI的传递和存储方式，由开发者自己决定，不过要保证传输过程的加密，以及存储时的安全性。接下来的实例里，传递和存储URI的方式就很有创意。&lt;/p&gt; &lt;p&gt;5-6. 当服务器端有信息要通知应用时，需要向MPNS发起一个Http请求，而MPNS将请求转发到相应的设备上，设备上的应用接到Push Notification的消息后，进行相应的处理。&lt;/p&gt; &lt;p&gt;其实过程挺简单，被MSDN文档说得神乎其神。接下来，我们挨个看一下各个类型的Notification。偷点懒，不自己写Sample Code了，请大家去下面的链接里下载。不过注意Sample Code的更新，最近有同学因为更新不及时，而影响了开发进度。&lt;/p&gt; &lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ff431744(VS.92).aspx"&gt;http://msdn.microsoft.com/en-us/library/ff431744(VS.92).aspx&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;初始化 Notifications&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;首先是Toast Notifications，这种Notification在实际应用中最为有效，不但可以提示用户有新的消息，而且还让用户选择是否打开当时的应用。不过比起iOS的Notifications来，Toast Notifications能够容纳的信息量实在有限。所以，开发者要适当&amp;#8220;浓缩&amp;#8221;需要推送的消息。&lt;/p&gt; &lt;p&gt;我们按照调用的顺序，依次来分析代码，首先来看客户端部分ToastNotificationClient的代码：&lt;/p&gt;            &lt;span class="rem"&gt;/// Holds the push channel that is created or found.&lt;/span&gt;&lt;br/&gt;            HttpNotificationChannel pushChannel;&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// The name of our push channel.&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; channelName = &lt;span class="str"&gt;"ToastSampleChannel"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            InitializeComponent();&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Try to find the push channel.&lt;/span&gt;&lt;br/&gt;            pushChannel = HttpNotificationChannel.Find(channelName);&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// If the channel was not found, then create a new connection to the push service.&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (pushChannel == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;            {&lt;br/&gt;                pushChannel = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotificationChannel(channelName);&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Register for all the events before attempting to open the channel.&lt;/span&gt;&lt;br/&gt;                pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;                pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Register for this notification only if you need to receive the notifications while your application is running.&lt;/span&gt;&lt;br/&gt;                pushChannel.ShellToastNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationEventArgs&amp;gt;(PushChannel_ShellToastNotificationReceived);&lt;br/&gt;&lt;br/&gt;                pushChannel.Open();&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Bind this new channel for toast events.&lt;/span&gt;&lt;br/&gt;                pushChannel.BindToShellToast();&lt;br/&gt;&lt;br/&gt;            }&lt;br/&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;            {&lt;br/&gt;                &lt;span class="rem"&gt;// The channel was already open, so just register for all the events.&lt;/span&gt;&lt;br/&gt;                pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;                pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Register for this notification only if you need to receive the notifications while your application is running.&lt;/span&gt;&lt;br/&gt;                pushChannel.ShellToastNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationEventArgs&amp;gt;(PushChannel_ShellToastNotificationReceived);&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Display the URI for testing purposes. Normally, the URI would be passed back to your web service at this point.&lt;/span&gt;&lt;br/&gt;                System.Diagnostics.Debug.WriteLine(pushChannel.ChannelUri.ToString());&lt;br/&gt;                MessageBox.Show(String.Format(&lt;span class="str"&gt;"Channel Uri is {0}"&lt;/span&gt;,&lt;br/&gt;                    pushChannel.ChannelUri.ToString()));&lt;br/&gt;&lt;br/&gt;            }&lt;br/&gt;&amp;nbsp;&amp;nbsp;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;代码比较多，我们逐步来看，首先要声明一个HttpNotificationChannel的变量，命名空间为Microsoft.Phone.Notification。接下来，声明该Notification Channel的名称，该名称是Channel的唯一标识名，不能与其他Channel重复。接下来，我们调用HttpNotificationChannel的静态方法Find来查找，当前的Channel是否存在，如果存在则返回HttpNotificationChannel对象实例，不存在则返回空。如果该程序从未在当前设备上运行过，则HttpNotificationChannel对象为空，只要运行过一次，则能够通过Find方法来获取对象实例。&lt;/p&gt;&lt;p&gt;先来说未创建Channel的情况，创建HttpNotificationChannel的对象，并将Channel名称作为参数传递进去。然后处理该对象的两个事件：ChannelUriUpdated和ErrorOccurred。当URI发生变化时，会触发ChannelUriUpdated事件，我们在创建Channel对象时，会触发该事件，另外一个ErrorOccurred事件，则用于错误处理。&lt;/p&gt;&lt;p&gt;当程序已经在运行时，默认是接收不到Toast Notification消息的，所以，我们还需要处理ShellToastNotificationReceived事件，当程序运行时，也可以接收到相应的消息。&lt;/p&gt;&lt;p&gt;然后调用HttpNotificationChannel的Open方法，打开该Channel，最后是BindToShellToast方法，通知Shell，该Notification的Channel已经被创建。&lt;/p&gt;&lt;p&gt;获取Channel后的代码与之大体类似，但我们可以通过HttpNotificationChannel的ChannelUri属性来获取Channel的URI，该URI值就是需要传递给我们自己服务器的唯一值，标记了该设备上的该Channel。&lt;/p&gt;&lt;p&gt;而创建Channel后，我们也可以获取URI的值，不过我们需要在ChannelUriUpdated事件处理函数里获取该URI值：&lt;/p&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; PushChannel_ChannelUriUpdated(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, NotificationChannelUriEventArgs e)&lt;br/&gt;        {&lt;br/&gt;&lt;br/&gt;            Dispatcher.BeginInvoke(() =&amp;gt;&lt;br/&gt;            {&lt;br/&gt;                &lt;span class="rem"&gt;// Display the new URI for testing purposes.   Normally, the URI would be passed back to your web service at this point.&lt;/span&gt;&lt;br/&gt;                System.Diagnostics.Debug.WriteLine(e.ChannelUri.ToString());&lt;br/&gt;                MessageBox.Show(String.Format(&lt;span class="str"&gt;"Channel Uri is {0}"&lt;/span&gt;,&lt;br/&gt;                    e.ChannelUri.ToString()));&lt;br/&gt;&lt;br/&gt;            });&lt;br/&gt;        }&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;到此为止，我们已经完成了Notification Channel的创建，并且获得了唯一标识的URI。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;触发Notification&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;接下来，我们来看Server的代码。我们自己的Server与Microsoft Push Notification Server（MPNS）之间是通过Http协议，使用HttpWebRequest来发送请求。理论上来说，我们也可以使用客户端程序向MPNS发送Notification请求。为什么要用ASP.NET来编写，最主要的原因还是在于客户端应用要将URI传递给Server端，显然基于ASP.NET的Web应用在这方面是最容易的。&lt;/p&gt;&lt;p&gt;不过我们的实例中，没有客户端将URI传递给服务器端的代码，而是采用了最简单的办法：由开发者直接将URI拷贝到ASP.NET的Web应用中。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/20110802012354661.jpg"&gt;&lt;img style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image008" border="0" alt="clip_image008" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/20110802012354628.jpg" width="596" height="379" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;接下来，我们来看Server端的代码：&lt;/p&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br/&gt;            {&lt;br/&gt;                &lt;span class="rem"&gt;// Get the Uri that the Microsoft Push Notification Service returns to the Push Client when creating a notification channel.&lt;/span&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Normally, a web service would listen for Uri's coming from the web client and maintain a list of Uri's to send&lt;/span&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// notifications out to.&lt;/span&gt;&lt;br/&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; subscriptionUri = TextBoxUri.Text.ToString();&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;                HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriptionUri);&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// We will create a HTTPWebRequest that posts the toast notification to the Microsoft Push Notification Service.&lt;/span&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// HTTP POST is the only allowed method to send the notification.&lt;/span&gt;&lt;br/&gt;                sendNotificationRequest.Method = &lt;span class="str"&gt;"POST"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// The optional custom header X-MessageID uniquely identifies a notification message. &lt;/span&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// If it is present, the // same value is returned in the notification response. It must be a string that contains a UUID.&lt;/span&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// sendNotificationRequest.Headers.Add("X-MessageID", "&amp;lt;UUID&amp;gt;");&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Create the toast message.&lt;/span&gt;&lt;br/&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; toastMessage = &lt;span class="str"&gt;"&amp;lt;?xml version=\"1.0\" encoding=\"utf-8\"?&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                &lt;span class="str"&gt;"&amp;lt;wp:Notification xmlns:wp=\"WPNotification\"&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                   &lt;span class="str"&gt;"&amp;lt;wp:Toast&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                        &lt;span class="str"&gt;"&amp;lt;wp:Text1&amp;gt;"&lt;/span&gt; + TextBoxTitle.Text.ToString() + &lt;span class="str"&gt;"&amp;lt;/wp:Text1&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                        &lt;span class="str"&gt;"&amp;lt;wp:Text2&amp;gt;"&lt;/span&gt; + TextBoxSubTitle.Text.ToString() + &lt;span class="str"&gt;"&amp;lt;/wp:Text2&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                        &lt;span class="str"&gt;"&amp;lt;wp:Param&amp;gt;/Page2.xaml?NavigatedFrom=Toast Notification"&lt;/span&gt; + TextBoxSubTitle.Text.ToString() + &lt;span class="str"&gt;"&amp;lt;/wp:Param&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                   &lt;span class="str"&gt;"&amp;lt;/wp:Toast&amp;gt; "&lt;/span&gt; +&lt;br/&gt;                &lt;span class="str"&gt;"&amp;lt;/wp:Notification&amp;gt;"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Sets the notification payload to send.&lt;/span&gt;&lt;br/&gt;                &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] notificationMessage = Encoding.Default.GetBytes(toastMessage);&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Sets the web request content length.&lt;/span&gt;&lt;br/&gt;                sendNotificationRequest.ContentLength = notificationMessage.Length;&lt;br/&gt;                sendNotificationRequest.ContentType = &lt;span class="str"&gt;"text/xml"&lt;/span&gt;;&lt;br/&gt;                sendNotificationRequest.Headers.Add(&lt;span class="str"&gt;"X-WindowsPhone-Target"&lt;/span&gt;, &lt;span class="str"&gt;"toast"&lt;/span&gt;);&lt;br/&gt;                sendNotificationRequest.Headers.Add(&lt;span class="str"&gt;"X-NotificationClass"&lt;/span&gt;, &lt;span class="str"&gt;"2"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;                &lt;span class="kwrd"&gt;using&lt;/span&gt; (Stream requestStream = sendNotificationRequest.GetRequestStream())&lt;br/&gt;                {&lt;br/&gt;                    requestStream.Write(notificationMessage, 0, notificationMessage.Length);&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Send the notification and get the response.&lt;/span&gt;&lt;br/&gt;                HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();&lt;br/&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; notificationStatus = response.Headers[&lt;span class="str"&gt;"X-NotificationStatus"&lt;/span&gt;];&lt;br/&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; notificationChannelStatus = response.Headers[&lt;span class="str"&gt;"X-SubscriptionStatus"&lt;/span&gt;];&lt;br/&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; deviceConnectionStatus = response.Headers[&lt;span class="str"&gt;"X-DeviceConnectionStatus"&lt;/span&gt;];&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Display the response from the Microsoft Push Notification Service.  &lt;/span&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Normally, error handling code would be here.  In the real world, because data connections are not always available,&lt;/span&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// notifications may need to be throttled back if the device cannot be reached.&lt;/span&gt;&lt;br/&gt;                TextBoxResponse.Text = notificationStatus + &lt;span class="str"&gt;" | "&lt;/span&gt; + deviceConnectionStatus + &lt;span class="str"&gt;" | "&lt;/span&gt; + notificationChannelStatus;&lt;br/&gt;            }&lt;br/&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)&lt;br/&gt;            {&lt;br/&gt;                TextBoxResponse.Text = &lt;span class="str"&gt;"Exception caught sending update: "&lt;/span&gt; + ex.ToString();&lt;br/&gt;            }&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;Server端程序的主体是调用HttpWebRequest对象，来实现HTTP POST的方法。发送的消息以XML形式呈现，在上面代码中表现为toastMessage字符串，wp:Toast指定Notification类型，wp:Text1指定标题，wp:Text2指定子标题，wp:Param指定传递的参数。&lt;/p&gt;&lt;p&gt;请大家注意wp:Param，我们可以认为该参数相当于调用了客户端应用中NavigationService的Navigate方法，必须确认客户端有指定的页面可以进行跳转。当用户点击Toast Notification的提示条时，客户端应用会调用wp:Param，从而跳转到指定界面上。&lt;/p&gt;&lt;p&gt;我们可以通过该参数来传递一些参数，比如标识本次Notification是由哪条消息引发的。不过该参数中不应该包括敏感信息、安全信息，因为无法保证这些信息的安全。最好的办法是，传递一个ID值，当客户端访问服务器时，由服务器端判断该ID是否有效。&lt;/p&gt;&lt;p&gt;接下来，我们还要为HTTP 头添加自定义字段，这部分参考Sample Code就可以了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;接收Notification&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;当Server端代码完成后，我们回到客户端，看一下当MPNS找到设备后，如何触发我们的客户端代码。首先是Page2.xaml的OnNavigatedTo方法：&lt;/p&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnNavigatedTo(e);&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;//  If we navigated to this page&lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// from the MainPage, the DefaultTitle parameter will be "FromMain".  If we navigated here&lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// when the secondary Tile was tapped, the parameter will be "FromTile".&lt;/span&gt;&lt;br/&gt;            textBlockFrom.Text = &lt;span class="str"&gt;"Navigated here from "&lt;/span&gt; + &lt;span class="kwrd"&gt;this&lt;/span&gt;.NavigationContext.QueryString[&lt;span class="str"&gt;"NavigatedFrom"&lt;/span&gt;];&lt;br/&gt;        }&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;通过NavigationContext.QueryString属性来获取自定义参数，试过传两个参数，后一个收到不到，目前成功的是传递一个参数的情况。&lt;/p&gt;&lt;p&gt;还有一种情况是，当客户端程序运行时，接收到Toast Notification时，该如何处理：&lt;/p&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; PushChannel_ShellToastNotificationReceived(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, NotificationEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            StringBuilder message = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();&lt;br/&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; relativeUri = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;&lt;br/&gt;&lt;br/&gt;            message.AppendFormat(&lt;span class="str"&gt;"Received Toast {0}:\n"&lt;/span&gt;, DateTime.Now.ToShortTimeString());&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Parse out the information that was part of the message.&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; key &lt;span class="kwrd"&gt;in&lt;/span&gt; e.Collection.Keys)&lt;br/&gt;            {&lt;br/&gt;                message.AppendFormat(&lt;span class="str"&gt;"{0}: {1}\n"&lt;/span&gt;, key, e.Collection[key]);&lt;br/&gt;&lt;br/&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.Compare(&lt;br/&gt;                    key,&lt;br/&gt;                    &lt;span class="str"&gt;"wp:Param"&lt;/span&gt;,&lt;br/&gt;                    System.Globalization.CultureInfo.InvariantCulture,&lt;br/&gt;                    System.Globalization.CompareOptions.IgnoreCase) == 0)&lt;br/&gt;                {&lt;br/&gt;                    relativeUri = e.Collection[key];&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Display a dialog of all the fields in the toast.&lt;/span&gt;&lt;br/&gt;            Dispatcher.BeginInvoke(() =&amp;gt; MessageBox.Show(message.ToString()));&lt;br/&gt;&lt;br/&gt;        }&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;该方法是HttpNotificationChannel的ShellToastNotificationReceived事件处理函数，具体内容不详细解释了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tile Notifications&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Tile Notification是另一种Notification，主要用于在Windows Phone的首页上显示Smart Tile。很多内置的WP应用可以显示Tile上的自定义显示，比如Messaging程序里可以显示当前未读的短信有多少。Tile Notification可以帮助我们实现类似的功能，通常的一个用法是，首先发送一条Toast Notification，如果用户不理睬，可以发送一条Tile Notification，在Smart Tile上显示提示，让用户在方便时，再处理该条请求。&lt;/p&gt;&lt;p&gt;Tile Notification的实现代码与Toast Notification类似，所以，我们不在这里列出全部源代码了，只是列出与上面不同的部分代码。&lt;/p&gt;&lt;p&gt;首先来看Server部分的代码：&lt;/p&gt;                &lt;span class="rem"&gt;// Create the tile message.&lt;/span&gt;&lt;br/&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; tileMessage = &lt;span class="str"&gt;"&amp;lt;?xml version=\"1.0\" encoding=\"utf-8\"?&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                &lt;span class="str"&gt;"&amp;lt;wp:Notification xmlns:wp=\"WPNotification\"&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                    &lt;span class="str"&gt;"&amp;lt;wp:Tile&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                      &lt;span class="str"&gt;"&amp;lt;wp:BackgroundImage&amp;gt;"&lt;/span&gt; + TextBoxBackgroundImage.Text + &lt;span class="str"&gt;"&amp;lt;/wp:BackgroundImage&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                      &lt;span class="str"&gt;"&amp;lt;wp:Count&amp;gt;"&lt;/span&gt; + TextBoxCount.Text + &lt;span class="str"&gt;"&amp;lt;/wp:Count&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                      &lt;span class="str"&gt;"&amp;lt;wp:Title&amp;gt;"&lt;/span&gt; + TextBoxTitle.Text + &lt;span class="str"&gt;"&amp;lt;/wp:Title&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                      &lt;span class="str"&gt;"&amp;lt;wp:BackBackgroundImage&amp;gt;"&lt;/span&gt; + TextBoxBackBackgroundImage.Text + &lt;span class="str"&gt;"&amp;lt;/wp:BackBackgroundImage&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                      &lt;span class="str"&gt;"&amp;lt;wp:BackTitle&amp;gt;"&lt;/span&gt; + TextBoxBackTitle.Text + &lt;span class="str"&gt;"&amp;lt;/wp:BackTitle&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                      &lt;span class="str"&gt;"&amp;lt;wp:BackContent&amp;gt;"&lt;/span&gt; + TextBoxBackContent.Text + &lt;span class="str"&gt;"&amp;lt;/wp:BackContent&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                   &lt;span class="str"&gt;"&amp;lt;/wp:Tile&amp;gt; "&lt;/span&gt; +&lt;br/&gt;                &lt;span class="str"&gt;"&amp;lt;/wp:Notification&amp;gt;"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Sets the notification payload to send.&lt;/span&gt;&lt;br/&gt;                &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] notificationMessage = Encoding.Default.GetBytes(tileMessage);&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Sets the web request content length.&lt;/span&gt;&lt;br/&gt;                sendNotificationRequest.ContentLength = notificationMessage.Length;&lt;br/&gt;                sendNotificationRequest.ContentType = &lt;span class="str"&gt;"text/xml"&lt;/span&gt;;&lt;br/&gt;                sendNotificationRequest.Headers.Add(&lt;span class="str"&gt;"X-WindowsPhone-Target"&lt;/span&gt;, &lt;span class="str"&gt;"token"&lt;/span&gt;);&lt;br/&gt;                sendNotificationRequest.Headers.Add(&lt;span class="str"&gt;"X-NotificationClass"&lt;/span&gt;, &lt;span class="str"&gt;"1"&lt;/span&gt;);&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;TileMessage与ToastMessage大体类似，标签变为wp:Tile，而其中包括的数据分为两组：BackgroundImage、Title和Content，显示位置可以参考文章前面的示意图。BackgroundImage可以是本地的资源，也可以是远程的图片链接。&lt;/p&gt;&lt;p&gt;接下来是客户端的部分代码：&lt;/p&gt;                pushChannel = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotificationChannel(channelName);&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Register for all the events before attempting to open the channel.&lt;/span&gt;&lt;br/&gt;                pushChannel.ChannelUriUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelUriEventArgs&amp;gt;(PushChannel_ChannelUriUpdated);&lt;br/&gt;                pushChannel.ErrorOccurred += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;NotificationChannelErrorEventArgs&amp;gt;(PushChannel_ErrorOccurred);&lt;br/&gt;&lt;br/&gt;                pushChannel.Open();&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Bind this new channel for Tile events.&lt;/span&gt;&lt;br/&gt;                pushChannel.BindToShellTile();&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;Tile Notification无需添加任何额外的代码，在调用HttpNotificationChannel的Open方法后，还需要调用BindToShellTile的方法，通知Shell绑定该Tile Notification。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Raw Notifications&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Raw Notification的用法最简单，在程序运行时，收到Raw Notification时，更新应用程序界面上的某些元素。&lt;/p&gt;&lt;p&gt;首先，我们来看Server端的代码：&lt;/p&gt;                &lt;span class="rem"&gt;// Create the raw message.&lt;/span&gt;&lt;br/&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; rawMessage = &lt;span class="str"&gt;"&amp;lt;?xml version=\"1.0\" encoding=\"utf-8\"?&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                &lt;span class="str"&gt;"&amp;lt;root&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                    &lt;span class="str"&gt;"&amp;lt;Value1&amp;gt;"&lt;/span&gt; + TextBoxValue1.Text.ToString() + &lt;span class="str"&gt;"&amp;lt;Value1&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                    &lt;span class="str"&gt;"&amp;lt;Value2&amp;gt;"&lt;/span&gt; + TextBoxValue2.Text.ToString() + &lt;span class="str"&gt;"&amp;lt;Value2&amp;gt;"&lt;/span&gt; +&lt;br/&gt;                &lt;span class="str"&gt;"&amp;lt;/root&amp;gt;"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Sets the notification payload to send.&lt;/span&gt;&lt;br/&gt;                &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] notificationMessage = Encoding.Default.GetBytes(rawMessage);&lt;br/&gt;&lt;br/&gt;                &lt;span class="rem"&gt;// Sets the web request content length.&lt;/span&gt;&lt;br/&gt;                sendNotificationRequest.ContentLength = notificationMessage.Length;&lt;br/&gt;                sendNotificationRequest.ContentType = &lt;span class="str"&gt;"text/xml"&lt;/span&gt;;&lt;br/&gt;                sendNotificationRequest.Headers.Add(&lt;span class="str"&gt;"X-NotificationClass"&lt;/span&gt;, &lt;span class="str"&gt;"3"&lt;/span&gt;);&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;RawMessage非常简单，只需要指定Value1, Value2就可以了，这些值是自定义的，然后指定HTTP头的X-NotificationgClass的值为3，代表Raw Notification。&lt;/p&gt;&lt;p&gt;接下来是客户端代码的片段：&lt;/p&gt;pushChannel = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotificationChannel(channelName);&lt;br/&gt;pushChannel.HttpNotificationReceived += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;HttpNotificationEventArgs&amp;gt;(PushChannel_HttpNotificationReceived);&lt;br/&gt;pushChannel.Open();&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; PushChannel_HttpNotificationReceived(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, HttpNotificationEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; message;&lt;br/&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;using&lt;/span&gt; (System.IO.StreamReader reader = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.IO.StreamReader(e.Notification.Body))&lt;br/&gt;            {&lt;br/&gt;                message = reader.ReadToEnd();&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;            Dispatcher.BeginInvoke(() =&amp;gt;&lt;br/&gt;                MessageBox.Show(String.Format(&lt;span class="str"&gt;"Received Notification {0}:\n{1}"&lt;/span&gt;,&lt;br/&gt;                    DateTime.Now.ToShortTimeString(), message))&lt;br/&gt;                    );&lt;br/&gt;        }&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;HttpNotificationChannel创建完成后，只需要调用Open方法即可，不需要绑定到Shell上。另外，还需要处理HttpNotificationChannel的HttpNotificationReceived事件处理函数，具体的代码不解释了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;好了，到这里，我们正式将Windows Phone 7.1中的Push Notification介绍完了。为了增加用户黏性，Push Notification可能是一种非常有效的方式，但是请开发者谨慎使用，如果太多的垃圾信息影响用户体验，那是得不偿失的。另外，我们还需要为Push Notification搭建一个Web服务器，这对于普通开发人员来说，也是一个很难接受的成本。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;OpenXLive杯Windows Phone游戏开发大赛&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108020123544740.jpg"&gt;&lt;img style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline;background-image: none;" title="clip_image010" border="0" alt="clip_image010" src="http://images.cnblogs.com/cnblogs_com/aawolf/201108/201108020123557215.jpg" width="212" height="225" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;OpenXLive杯Windows Phone游戏开发大赛，是由OpenXLive联合国内知名的开发者社区：DevDiv、智机网、WPMind、Silverlight银光中国和XNA游戏世界，一起举办的针对Windows Phone游戏开发的比赛。&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.openxlive.net/posts/news/40"&gt;http://www.openxlive.net/posts/news/40&lt;/a&gt;&lt;/p&gt; &lt;img src="http://www.cnblogs.com/aawolf/aggbug/2124442.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/aawolf/archive/2011/08/02/2124442.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/aawolf/archive/2011/06/21/2086139.html</id><title type="text">Kinect for Windows SDK开发初体验（三）骨骼追踪</title><summary type="text">作者：马宁 我们的Kinect SDK开发开始渐入佳境了，Skeleton Tracking（骨骼追踪）是Kinect的核心技术，正因为有了这项技术，很多有趣的功能才得以实现。 首先，我们来看一下骨骼追踪的具体实现。Kinect最多可以追踪20个骨骼点，而且目前只能追踪人体，其他的物体或者动物就无能为力了。下图介绍了Kinect骨骼点的分布情况： 初始化代码 接下来，我们来看一下骨骼追踪的代...</summary><published>2011-06-21T08:16:00Z</published><updated>2011-06-21T08:16:00Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><link rel="alternate" href="http://www.cnblogs.com/aawolf/archive/2011/06/21/2086139.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/archive/2011/06/21/2086139.html"/><content type="html">&lt;p&gt;作者：马宁&lt;/p&gt;  &lt;p&gt;我们的Kinect SDK开发开始渐入佳境了，Skeleton Tracking（骨骼追踪）是Kinect的核心技术，正因为有了这项技术，很多有趣的功能才得以实现。&lt;/p&gt;  &lt;p&gt;首先，我们来看一下骨骼追踪的具体实现。Kinect最多可以追踪20个骨骼点，而且目前只能追踪人体，其他的物体或者动物就无能为力了。下图介绍了Kinect骨骼点的分布情况：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106211612551171.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="7" border="0" alt="7" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106211614267781.png" width="446" height="444" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;初始化代码&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;接下来，我们来看一下骨骼追踪的代码是如何编写的。首先，我们要创建一个新的Visual C#的工程，叫做&amp;#8220;SkeletonTracking&amp;#8221;，添加Kinect程序集和Coding4Fun程序集的工作，可以参考上一篇&amp;#8220;Kinect for Windows SDK开发初体验（二）操作Camera&amp;#8221;的内容，在这里不再重复。&lt;/p&gt;  &lt;p&gt;首先我们还是创建Runtime对象，在初始化时，指定UseSkeletalTracking的RuntimeOptions，然后在SkeletonFrameReady事件中添加处理函数。&lt;/p&gt;  Runtime nui; &lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Window_Loaded(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;nui = &lt;span class="kwrd"&gt;new&lt;/span&gt; Runtime();&lt;br/&gt;&lt;br/&gt;nui.Initialize(RuntimeOptions.UseSkeletalTracking); &lt;br/&gt;&lt;br/&gt;nui.SkeletonFrameReady += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;SkeletonFrameReadyEventArgs&amp;gt;(nui_SkeletonFrameReady);&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;接下来，窗体关闭时的事件处理函数：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Window_Closed(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;nui.Uninitialize();&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;如果这个时候，我们在空的nui_SkeletonFrameReady事件处理函数中，添加一个断点：&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; nui_SkeletonFrameReady(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, SkeletonFrameReadyEventArgs e) &lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;正确连接Kinect设备，并且站在Kinect前，让Kinect能够正确识别人体时，SkeletonFrameReady事件将被触发。&lt;/p&gt;&lt;p&gt;我们可以通过下图看到返回的事件处理参数，其中比较重要的是SkeletonFrame和Skeletons两个对象。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106211615089556.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image[11]" border="0" alt="image[11]" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106211615479780.png" width="703" height="380" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;strong&gt;添加代码&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;接下来，我们要准备WPF的界面，在界面上添加五个小球，来跟踪头部、双手和膝盖的位置。在MainPage.xaml中，添加下列代码：&lt;/p&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Canvas&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;MainCanvas&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Ellipse&lt;/span&gt; &lt;span class="attr"&gt;Canvas&lt;/span&gt;.&lt;span class="attr"&gt;Left&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Canvas&lt;/span&gt;.&lt;span class="attr"&gt;Top&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;headEllipse&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Stroke&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Black&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Fill&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Orange&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Ellipse&lt;/span&gt; &lt;span class="attr"&gt;Canvas&lt;/span&gt;.&lt;span class="attr"&gt;Left&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Canvas&lt;/span&gt;.&lt;span class="attr"&gt;Top&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;rightEllipse&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Stroke&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Black&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Fill&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SlateGray&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Ellipse&lt;/span&gt; &lt;span class="attr"&gt;Canvas&lt;/span&gt;.&lt;span class="attr"&gt;Left&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;100&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Canvas&lt;/span&gt;.&lt;span class="attr"&gt;Top&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Fill&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SpringGreen&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;leftEllipse&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Stroke&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Black&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Ellipse&lt;/span&gt; &lt;span class="attr"&gt;Canvas&lt;/span&gt;.&lt;span class="attr"&gt;Left&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;150&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Canvas&lt;/span&gt;.&lt;span class="attr"&gt;Top&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;KneeRightEllipse&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Stroke&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Black&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Fill&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Salmon&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Ellipse&lt;/span&gt; &lt;span class="attr"&gt;Canvas&lt;/span&gt;.&lt;span class="attr"&gt;Left&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;200&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Canvas&lt;/span&gt;.&lt;span class="attr"&gt;Top&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Fill&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Navy&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;KneeLeftEllipse&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Stroke&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Black&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Canvas&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;然后，我们在SkeletonFrameReady事件处理函数中添加捕捉SkeletonData的方法：&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; nui_SkeletonFrameReady(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, SkeletonFrameReadyEventArgs e) &lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;SkeletonFrame allSkeletons = e.SkeletonFrame;&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//get the first tracked skeleton&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;SkeletonData skeleton = (from s &lt;span class="kwrd"&gt;in&lt;/span&gt; allSkeletons.Skeletons&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;where&lt;/span&gt; s.TrackingState == SkeletonTrackingState.Tracked&lt;br/&gt;&lt;br/&gt;select s).FirstOrDefault();&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;我们使用了LINQ来获取TrackingState等于Tracked的SkeletonData数据。在SkeletonData对象的Joints属性集合中保存了所有骨骼点的信息。每个骨骼点的信息都是一个Joint对象，其中的Position的X、Y、Z表示了三维位置。其中X和Y的范围都是-1到1，而Z是Kinect到识别物体的距离。&lt;/p&gt;&lt;p&gt;我们可以用下面的代码，将Joint的位置缩放到合适的比例：&lt;/p&gt;Joint j = skeleton.Joints[JointID.HandRight].ScaleTo(640, 480, .5f, .5f);&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;最后两个参数为原始大小的最大值和最小值，上面的语句相当于将-0.5到0.5的范围扩大为0到640的范围。&lt;/p&gt;&lt;p&gt;我们封装了一个函数，将获取到的SkeletonData数据，转换为屏幕上的某一个圆圈：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetEllipsePosition(FrameworkElement ellipse, Joint joint) &lt;br/&gt;&lt;br/&gt;{ &lt;br/&gt;&lt;br/&gt;var scaledJoint = joint.ScaleTo(640, 480, .5f, .5f);&lt;br/&gt;&lt;br/&gt;Canvas.SetLeft(ellipse, scaledJoint.Position.X);&lt;br/&gt;&lt;br/&gt;Canvas.SetTop(ellipse, scaledJoint.Position.Y); &lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;最后，我们SkeletonFrameReady事件的处理方法会是这样的：&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; nui_SkeletonFrameReady(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, SkeletonFrameReadyEventArgs e) &lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;SkeletonFrame allSkeletons = e.SkeletonFrame;&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//get the first tracked skeleton&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;SkeletonData skeleton = (from s &lt;span class="kwrd"&gt;in&lt;/span&gt; allSkeletons.Skeletons&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;where&lt;/span&gt; s.TrackingState == SkeletonTrackingState.Tracked&lt;br/&gt;&lt;br/&gt;select s).FirstOrDefault();&lt;br/&gt;&lt;br/&gt;SetEllipsePosition(headEllipse, skeleton.Joints[JointID.Head]); &lt;br/&gt;&lt;br/&gt;SetEllipsePosition(leftEllipse, skeleton.Joints[JointID.HandLeft]); &lt;br/&gt;&lt;br/&gt;SetEllipsePosition(rightEllipse, skeleton.Joints[JointID.HandRight]);&lt;br/&gt;&lt;br/&gt;SetEllipsePosition(KneeLeftEllipse, skeleton.Joints[JointID.KneeLeft]);&lt;br/&gt;&lt;br/&gt;SetEllipsePosition(KneeRightEllipse, skeleton.Joints[JointID.KneeRight]);&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;最后，程序运行的效果如下，貌似膝盖的识别还是有些问题：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106211616081403.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="30" border="0" alt="30" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106211616185491.png" width="712" height="426" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;程序运行时，我们会发现小球运动时会有跳动的问题，为了减少这种情况，我们要设置SkeletonEngine引擎的TransformSmooth属性为true，并指定TransformSmoothParameters参数，根据应用的具体情况，该参数也应该被适当微调。&lt;/p&gt;&lt;p&gt;添加代码后的Load函数，代码如下：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Window_Loaded(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;nui = &lt;span class="kwrd"&gt;new&lt;/span&gt; Runtime();&lt;br/&gt;&lt;br/&gt;nui.Initialize(RuntimeOptions.UseSkeletalTracking); &lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//Must set to true and set after call to Initialize&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;nui.SkeletonEngine.TransformSmooth = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//Use to transform and reduce jitter&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;var parameters = &lt;span class="kwrd"&gt;new&lt;/span&gt; TransformSmoothParameters&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;Smoothing = 0.75f,&lt;br/&gt;&lt;br/&gt;Correction = 0.0f,&lt;br/&gt;&lt;br/&gt;Prediction = 0.0f,&lt;br/&gt;&lt;br/&gt;JitterRadius = 0.05f,&lt;br/&gt;&lt;br/&gt;MaxDeviationRadius = 0.04f&lt;br/&gt;&lt;br/&gt;};&lt;br/&gt;&lt;br/&gt;nui.SkeletonEngine.SmoothParameters = parameters;&lt;br/&gt;&lt;br/&gt;nui.SkeletonFrameReady += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;SkeletonFrameReadyEventArgs&amp;gt;(nui_SkeletonFrameReady);&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;写到最后&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;到这里， Kinect最精华的部分&amp;#8220;骨骼追踪&amp;#8221;已经介绍给大家了，大家可以去写一些有趣的应用了。接下来，我们会介绍另外一个Kinect的核心功能——Depth Data，景深数据。&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;OpenXLive杯Windows Phone游戏开发大赛&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013539658.jpg"&gt;&lt;img title="clip_image019" border="0" alt="clip_image019" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013545231.jpg" width="212" height="225" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;OpenXLive杯Windows Phone游戏开发大赛，是由OpenXLive联合国内知名的开发者社区：DevDiv、智机网、WPMind、Silverlight银光中国和XNA游戏世界，一起举办的针对Windows Phone游戏开发的比赛。&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.openxlive.net/posts/news/40"&gt;http://www.openxlive.net/posts/news/40&lt;/a&gt;&lt;/p&gt; &lt;img src="http://www.cnblogs.com/aawolf/aggbug/2086139.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/aawolf/archive/2011/06/21/2086139.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/aawolf/archive/2011/06/18/2084352.html</id><title type="text">Kinect for Windows SDK开发初体验（二）操作Camera</title><summary type="text">  作者：马宁 Kinect SDK出来之后，不到24小时，很多Geek们已经将自己的示例发布到网上去了。可见，好东西肯定会被大家认可的，不好的东西投入再多的宣传也没用。 这一篇我们就要正式进入Kinect的编程世界了，介绍我们如何从Camera获取图像信息。先来介绍一下Kinect的整体结构，省得大家在后边的介绍中被某些名词弄晕。 Kinect一共有三个Camera，其中中间的一个是RGB...</summary><published>2011-06-18T11:05:00Z</published><updated>2011-06-18T11:05:00Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><link rel="alternate" href="http://www.cnblogs.com/aawolf/archive/2011/06/18/2084352.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/archive/2011/06/18/2084352.html"/><content type="html">&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;作者：马宁&lt;/p&gt;  &lt;p&gt;Kinect SDK出来之后，不到24小时，很多Geek们已经将自己的示例发布到网上去了。可见，好东西肯定会被大家认可的，不好的东西投入再多的宣传也没用。&lt;/p&gt;  &lt;p&gt;这一篇我们就要正式进入Kinect的编程世界了，介绍我们如何从Camera获取图像信息。先来介绍一下Kinect的整体结构，省得大家在后边的介绍中被某些名词弄晕。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181530519386.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image_thumb[3]" border="0" alt="image_thumb[3]" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181534166412.png" width="494" height="324" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Kinect一共有三个Camera，其中中间的一个是RGB Camera，用来获取640x480的彩色图像，每秒钟最多获取30帧图像；两侧是两个景深(3D Depth)传感器，用来检测玩家的相对位置，原理和人眼立体成像是一样的，不过这两个传感器使用的是红外线，所以说奥巴马玩不了Kinect的人一定是居心叵测。Kinect两侧是麦克风，下边还有一个可移动底座，用来调整Kinect的仰角。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Kinect开发环境&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;今天我们主要是操作RGB Camera和Depth Sensor，首先，我们要完成Kinect开发环境的配置：&lt;/p&gt;  &lt;p&gt;第一步，创建WPF工程&lt;/p&gt;  &lt;p&gt;打开Visual Studio 2010，创建一个WPF工程，名叫KinectWpfDemo：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181534381788.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="21" border="0" alt="21" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181535031681.png" width="601" height="414" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;当然，由于Kinect SDK中包含基于.NET的程序集，除了WPF外，我们使用.NET WinForm或XNA框架都可以，目前还没有人在Silverlight平台上实验成功。&lt;/p&gt;  &lt;p&gt;第二步，添加Kinect程序集的引用&lt;/p&gt;  &lt;p&gt;在Solution Explorer中，右键单击KinectWpfDemo，在右键菜单中选择&amp;#8220;Add Reference&amp;#8230;&amp;#8221;。在弹出的对话框中，我们在.NET标签页里，选择&amp;#8220;Microsoft.Research.Kinect&amp;#8221;程序集。如下图所示：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181904196523.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="22" border="0" alt="22" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181904212752.png" width="542" height="434" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;第三步，添加Coding4Fun Kinect Toolkit&lt;/p&gt;  &lt;p&gt;这是一个可选项，不过为了之后的编程方便，建议大家添加一个。Coding4Fun Kinect Toolkit的下载地址：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://c4fkinect.codeplex.com/"&gt;http://c4fkinect.codeplex.com/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;解压缩后，一共有五个文件，针对WinForm、WPF平台，还有一个Microsoft.Expression.Drawing.dll。我们通过Add Reference，将Coding4Fun.Kinect.Wpf.dll添加进来。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181904215850.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="23" border="0" alt="23" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181904236854.png" width="372" height="515" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;获取RGB Camera数据&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;第四步，添加控件&lt;/p&gt;  &lt;p&gt;双击打开MainWindow.xaml，在设计器中添加两个Image控件，一个用于显示RGB图像，另一个用于显示Depth信息。&lt;/p&gt;  &lt;p&gt;第五步，引用命名空间&lt;/p&gt;  &lt;p&gt;打开MainWindow.xaml.cs文件，在文件头部添加对于Kinect对象的引用：&lt;/p&gt;  &lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Research.Kinect.Nui;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Research.Kinect.Audio;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Coding4Fun.Kinect.Wpf;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;回到MainWindow.xaml的设计器中，在属性窗口中选择Event，找到Loaded和Closed两个方法，分别双击，添加两个事件的处理函数：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181904234063.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="25" border="0" alt="25" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/20110618190424574.png" width="372" height="455" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;在MainWindow.xaml.cs文件的MainWindow类中，声明Runtime的变量：&lt;/p&gt;&lt;p&gt;Runtime nui;&lt;/p&gt;&lt;p&gt;然后，在Loaded事件的处理函数中添加Runtime初始化的代码：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Window_Loaded(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;nui = &lt;span class="kwrd"&gt;new&lt;/span&gt; Runtime();&lt;br/&gt;&lt;br/&gt;nui.Initialize(RuntimeOptions.UseColor| RuntimeOptions.UseDepth | RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking);&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;接下来是Closed事件中关闭Runtime的代码：&lt;/p&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Window_Closed(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;nui.Uninitialize();&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Runtime对象是Kinect SDK中最主要的一个类，所有针对Kinect的操作都由Runtime类进行了封装。Runtime的构造函数没有接受任何参数，但有一个显式的初始化函数Initialize，接受RuntimeOptions参数，指定调用Kinect的哪些功能。其中RuntimeOptions.UseColor表示使用RGB Camera，而RuntimeOptions.UseDepth则表示使用Depth传感器。&lt;/p&gt;&lt;p&gt;初始化工作完成之后，我们要通过RGB Camera来获取实时的图像数据了。我们首先要声明一个事件处理方法，来接收视频数据的信息：&lt;/p&gt;nui.VideoFrameReady += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;ImageFrameReadyEventArgs&amp;gt;(nui_VideoFrameReady);&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;然后是事件处理函数：&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; nui_VideoFrameReady(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ImageFrameReadyEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;PlanarImage imageData = e.ImageFrame.Image;&lt;br/&gt;&lt;br/&gt;image1.Source = BitmapSource.Create(imageData.Width, imageData.Height, 96, 96,&lt;br/&gt;&lt;br/&gt;PixelFormats.Bgr32, &lt;span class="kwrd"&gt;null&lt;/span&gt;, imageData.Bits, imageData.Width * imageData.BytesPerPixel);&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;//image1.Source = e.ImageFrame.ToBitmapSource();&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;提示：Getting Started上提供的Sample Code有误，需要将最后一个参数中的data.Width改为imageData.Width才可以正常运行。&lt;/p&gt;&lt;p&gt;VideoFrameReady事件会传递一个ImageFrameReadyEventArgs参数给事件处理函数，其中的ImageFrame会包含关于图片的各种信息，比如Type变量指定了图像是来自RGB还是Depth，Resolution变量指定了分辨率，而Image中以byte[]数组的方式保存了图像的真实数据。&lt;/p&gt;&lt;p&gt;然后的工作就是根据PlanarImage中包括的数据来创建一个Bitmap对象，然后将其传递给Image控件，显示到WPF程序的界面上。&lt;/p&gt;&lt;p&gt;最后，我们还要在构造函数里打开视频流，来获取视频数据：&lt;/p&gt;nui.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;第一个参数是ImageStreamType，用来指定打开的设备流类型；第二个参数是PoolSize，指定缓冲区的数量，至少为2，保证一个Buffer进行绘制，另一个Buffer进行数据填充；第三个参数指定Camera的分辨率；第四个参数则是获取的图片类型。&lt;/p&gt;&lt;p&gt;显示效果如下图所示：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181904253704.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="24 - Copy" border="0" alt="24 - Copy" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181904267773.png" width="616" height="412" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;上面的示例代码，没有使用Coding4Fun的Helper类，如果使用的话，则代码如下：&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; nui_VideoFrameReady(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ImageFrameReadyEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;image1.Source = e.ImageFrame.ToBitmapSource();&lt;br/&gt;&lt;br/&gt;e.ImageFrame.ToBitmapSource().Save(&lt;span class="str"&gt;&amp;quot;catpure.jpg&amp;quot;&lt;/span&gt;, ImageFormat.Jpeg);&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Helper类使用了C#的Extension Methods，为ImageFrame增加了一些转换方法。我们还可以将图像保存为文件，考虑到文件系统存储的效率文件，建议大家不用每张都存。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;获取Depth信息&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;接下来我们要获取Depth信息了，过程与RGB Camera类似。首先要确保Runtime对象被初始化时，已经添加了RuntimeOptions.UseDepth的属性，否则设备无法正常打开。&lt;/p&gt;&lt;p&gt;然后，添加获取Depth数据的事件处理，并打开Depth的数据流，这次的分辨率是320x240：&lt;/p&gt;nui.DepthFrameReady += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler&amp;lt;ImageFrameReadyEventArgs&amp;gt;(nui_DepthFrameReady);&lt;br/&gt;&lt;br/&gt;nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.Depth);&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;下面是事件处理函数，在另外一个Image函数里，显示Depth图像：&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; nui_DepthFrameReady(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ImageFrameReadyEventArgs e)&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;image2.Source = e.ImageFrame.ToBitmapSource(); &lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;偷懒，所以使用了Coding4Fun的Helper类。程序运行的效果如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181904289608.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="24" border="0" alt="24" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106181904308137.png" width="650" height="435" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;strong&gt;写到最后&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这一篇中，我们完成了Kinect开发环境的配置、添加了Coding4Fun Kinect Toolkit、从RGB Camera和Depth Sensor中获取了图像信息。&lt;/p&gt;&lt;p&gt;接下来，我们就要进入Kinect动作捕捉部分了。&lt;/p&gt; &lt;img src="http://www.cnblogs.com/aawolf/aggbug/2084352.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/aawolf/archive/2011/06/18/2084352.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/aawolf/archive/2011/06/17/2083249.html</id><title type="text">Kinect for Windows SDK开发初体验（一）环境配置</title><summary type="text">作者：马宁 万众期待的Kinect for Windows SDK终于在广大开发者的千呼万唤中发布了beta版，作为历史上销售最快的消费电子产品，早就有无数人想将其用于其他领域了。微软虽然在硬件接口上制造了一点小障碍，但并没有对Kinect的输出做任何加密。于是，基于Kinect的各种应用层出不穷，也有开源社区提供了针对Kinect的USB驱动程序，比如OpenKinect等。 微软从谏如流，推出了官方版的Kinect for Windows SDK，终于让广大开发者可以名正言顺地使用Kinect SDK了。我希望能够在第一时间为国内开发者提供Kinect开发相关的介绍，根据微软官方提供的指南</summary><published>2011-06-16T19:25:00Z</published><updated>2011-06-16T19:25:00Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><link rel="alternate" href="http://www.cnblogs.com/aawolf/archive/2011/06/17/2083249.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/archive/2011/06/17/2083249.html"/><content type="html">&lt;p&gt;作者：马宁&lt;/p&gt;  &lt;p&gt;万众期待的Kinect for Windows SDK终于在广大开发者的千呼万唤中发布了beta版，作为历史上销售最快的消费电子产品，早就有无数人想将其用于其他领域了。微软虽然在硬件接口上制造了一点小障碍，但并没有对Kinect的输出做任何加密。于是，基于Kinect的各种应用层出不穷，也有开源社区提供了针对Kinect的USB驱动程序，比如OpenKinect等。&lt;/p&gt;  &lt;p&gt;微软从谏如流，推出了官方版的Kinect for Windows SDK，终于让广大开发者可以名正言顺地使用Kinect SDK了。我希望能够在第一时间为国内开发者提供Kinect开发相关的介绍，根据微软官方提供的指南，从浅入深，将自己摸索Kinect SDK 的过程记录下来。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324415321.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="2" border="0" alt="2" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324427372.png" width="533" height="355" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;安装环境&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;首先来说，Kinect for Windows SDK的下载地址：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/download.aspx"&gt;http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/download.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Kinect SDK目前只支持Windows 7，分为x86和x64两个版本。开发工具方面还需要.NET Framework 4.0和Visual Studio 2010 （最低Express版本）的支持。&lt;/p&gt;  &lt;p&gt;Kinect SDK的视频开发教程：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://channel9.msdn.com/Series/KinectSDKQuickstarts?sort=recent#tab_sortBy_recent"&gt;http://channel9.msdn.com/Series/KinectSDKQuickstarts?sort=recent#tab_sortBy_recent&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Kinect SDK的开发指南：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/guides.aspx"&gt;http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/guides.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Kinect SDK的官方论坛：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://social.msdn.microsoft.com/Forums/en-US/kinectsdk/threads"&gt;http://social.msdn.microsoft.com/Forums/en-US/kinectsdk/threads&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;硬件设备的需求是：Kinect for Xbox 360 sensor和Xbox 360 Kinect AC Adapter/ Power Supply。&lt;/p&gt;  &lt;p&gt;如果您购买的是单独的Kinect，将包含Kinect AC Adapter/ Power Supply。但是如果您购买的是XBOX 360 Slim和Kinect的套装，就需要单独购买Kinect AC Adapter/ Power Supply。下面是亚马逊上的产品链接：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.amazon.com/Xbox-360-Kinect-Adapter-Power-Supply/dp/B004IXRXGY/ref=sr_1_1?ie=UTF8&amp;amp;qid=1308247174&amp;amp;sr=8-1"&gt;http://www.amazon.com/Xbox-360-Kinect-Adapter-Power-Supply/dp/B004IXRXGY/ref=sr_1_1?ie=UTF8&amp;amp;qid=1308247174&amp;amp;sr=8-1&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;安装步骤&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1. 硬件安装&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;下面的图片是Kinect和AC Adapter/ Power Supply：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324428834.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="WP_000094" border="0" alt="WP_000094" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324433916.jpg" width="548" height="412" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;按照接口连接好后，将USB插入到PC上，AC Adapter电源是可以支持220V的，所以不需要转换器直接插到电源上就可以。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2. Kinect SDK安装&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Kinect SDK的安装过程非常简单，无需任何设置，直接安装即可。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324446490.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="1" border="0" alt="1" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324449065.png" width="575" height="451" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;3. 环境测试&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Kinect SDK安装完成后，我们将Kinect转接口的USB接口插入到PC中。PC会发现新硬件，并且自动查找驱动程序安装。下图是安装完成后的示意图：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/20110617032445734.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="evm1" border="0" alt="evm1" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324458292.png" width="549" height="356" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;4. 测试程序&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;我们打开Kinect SDK中自带的Sample Skeletal Viewer就可以很方便地检测Kinect设备是否与PC已经连接好了。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324463898.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="evm2" border="0" alt="evm2" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324466788.png" width="633" height="240" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;为了测试，逼得我不得不闪亮出镜了。以后Kinect调试，说不定还真要请一个人站在那里，实现敏捷开发中的&amp;#8220;双人编程&amp;#8221;&amp;#8230;&amp;#8230;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;写到最后&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;我们今天关于Kinect的介绍就到这里，在Kinect SDK的发布会上展示了很多有意思的DEMO，可见Kinect的应用前景是无限广阔的。下图就是一个Kinect与虚拟增强现实整合的案例：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324477966.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="4" border="0" alt="4" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170324485001.png" width="558" height="318" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;下一节，我们会深入Kinect真实的开发环境，来编写第一个Kinect的应用程序。&lt;/p&gt; &lt;img src="http://www.cnblogs.com/aawolf/aggbug/2083249.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/aawolf/archive/2011/06/17/2083249.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/aawolf/archive/2011/06/17/2083222.html</id><title type="text">马宁的Windows Phone 7.1初体验——XNA与Silverlight集成</title><summary type="text">关于Windows Phone Mango真真假假的图片、视频已经在网上流传很久了，微软发布的Windows Phone 7.1 SDK可以让我们看到一部分Mango支持的功能。 普通用户对Mango的关注更多停留在多语言、多任务等方面，但对于开发者来说，Mango还有很多有趣的功能。我会试着将自己感兴趣的一些功能写出来，变成一个系列。 首先，大家要安装Windows Phone 7的SDK和Windows Phone 7.1 SDK的Beta 版，下载地址如下： http://www.microsoft.com/downloads/en/details.aspx?FamilyID=77586</summary><published>2011-06-16T16:14:00Z</published><updated>2011-06-16T16:14:00Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><link rel="alternate" href="http://www.cnblogs.com/aawolf/archive/2011/06/17/2083222.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/archive/2011/06/17/2083222.html"/><content type="html">&lt;p&gt;关于Windows Phone Mango真真假假的图片、视频已经在网上流传很久了，微软发布的Windows Phone 7.1 SDK可以让我们看到一部分Mango支持的功能。&lt;/p&gt;  &lt;p&gt;普通用户对Mango的关注更多停留在多语言、多任务等方面，但对于开发者来说，Mango还有很多有趣的功能。我会试着将自己感兴趣的一些功能写出来，变成一个系列。&lt;/p&gt;  &lt;p&gt;首先，大家要安装Windows Phone 7的SDK和Windows Phone 7.1 SDK的Beta 版，下载地址如下：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=77586864-ab15-40e1-bc38-713a95a56a05"&gt;http://www.microsoft.com/downloads/en/details.aspx?FamilyID=77586864-ab15-40e1-bc38-713a95a56a05&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;创建工程&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;关于Windows Phone 7.1的第一个功能是XNA与Silverlight的集成。Windows Phone里有两个Framework，Silverlight是做应用的，而XNA是做游戏开发的。Silverlight有一套非常好用的UI设计工具和控件体系，而XNA对于动画效果的处理又远远超过Silverlight。但是在WP7里，Silverlight和XNA必须是分开的，所以当Silverlight应用需要高性能显示，或者XNA游戏里需要编写UI时，都会碰到很多困难。&lt;/p&gt;  &lt;p&gt;于是，在WP 7.1里，提供了XNA与Silverlight集成的功能。接下来，我们就来看一下，如何创建一个Silverlight和XNA集成的应用。&lt;/p&gt;  &lt;p&gt;打开Visual Studio 2010，选择File-New Project，在Visual C#里找到Silverlight for Windows Phone，然后选择其中的&amp;#8220;Windows Phone 3D Graphics Application&amp;#8221;，这个名字有足够的迷惑性，XNA的2D也是支持的。如下图：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013375466.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="2" border="0" alt="2" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013387757.png" width="710" height="492" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;创建过程没有什么特殊的地方，创建完成后的工程如下图所示：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013392840.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="3" border="0" alt="3" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013406843.png" width="326" height="506" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;说实话，XNA与Silverlight集成的实现并不算优雅，有点叠床架屋的感觉。整个Solution里分为三个Project，其中GraphicsApp1是我们的主程序，主要的逻辑代码都是在这个工程里的，这是一个典型的Silverlight程序，包含了App.xaml和MainPage.xmal，多出来一个GamePage.xaml，这个是XNA的页面。除此之外，还有两个Library，分别叫做GraphicsApp1Library和GraphicsApp1LibraryContent，后边是XNA的Content库，前边一个应该是为了能够让Silverlight加载XNA资源所做的适配库。&lt;/p&gt;  &lt;p&gt;直接运行程序，我们会看到下面的界面，点击HomePage的Play按钮，我们就进入了XNA的GamePage界面：&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013418894.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="4" border="0" alt="4" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013429516.png" width="277" height="517" /&gt;&lt;/a&gt; &lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013437107.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="5" border="0" alt="5" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013437729.png" width="279" height="515" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;GamePage探秘&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;接下来，我们看一下GamePage.xaml的结构，看看这个看似普通的XAML页面里具体做了什么事情。首先是GamePage.xaml，如下：&lt;/p&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;phone:PhoneApplicationPage&lt;/span&gt; &lt;br/&gt;    &lt;span class="attr"&gt;x:Class&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;GraphicsApp2.GamePage&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;xmlns:x&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;xmlns:phone&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;xmlns:shell&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;xmlns:d&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://schemas.microsoft.com/expression/blend/2008&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;xmlns:mc&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://schemas.openxmlformats.org/markup-compatibility/2006&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;FontFamily&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;{StaticResource PhoneFontFamilyNormal}&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;FontSize&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;{StaticResource PhoneFontSizeNormal}&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;Foreground&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;{StaticResource PhoneForegroundBrush}&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;SupportedOrientations&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Portrait&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Orientation&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Portrait&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;mc:Ignorable&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;d&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;d:DesignHeight&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;800&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;d:DesignWidth&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;480&amp;quot;&lt;/span&gt;&lt;br/&gt;    &lt;span class="attr"&gt;shell:SystemTray&lt;/span&gt;.&lt;span class="attr"&gt;IsVisible&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span class="rem"&gt;&amp;lt;!--No XAML content as the page is rendered entirely with XNA--&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;br/&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;phone:PhoneApplicationPage&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;什么都没有&amp;#8230;&amp;#8230;所有的显示都是由XNA控制的。接下来，我们去看GamePage.xaml.cs，首先来看引用程序集的部分：&lt;/p&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Xna.Framework;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Xna.Framework.Content;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Xna.Framework.Graphics;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;引用了三个XNA的命名空间，接下来是变量声明：&lt;/p&gt;GameTimer timer;&lt;br/&gt;&lt;br/&gt;ContentManager content;&lt;br/&gt;&lt;br/&gt;SpriteBatch spriteBatch;&lt;br/&gt;&lt;br/&gt;Texture2D texture;&lt;br/&gt;&lt;br/&gt;Vector2 spritePosition;&lt;p&gt;除了GameTimer是生面孔外，其他几个都是老熟人，GameTimer也好理解，Silverlight是事件驱动的Framework，如果想定时更新的话，必须要加入一个Timer。接下来，是GamePage的构造函数：&lt;/p&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; GamePage()&lt;br/&gt;        {&lt;br/&gt;            InitializeComponent();&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Get the application's ContentManager&lt;/span&gt;&lt;br/&gt;            content = (Application.Current &lt;span class="kwrd"&gt;as&lt;/span&gt; App).Content;&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Create a timer for this page&lt;/span&gt;&lt;br/&gt;            timer = &lt;span class="kwrd"&gt;new&lt;/span&gt; GameTimer();&lt;br/&gt;            timer.UpdateInterval = TimeSpan.FromTicks(333333);&lt;br/&gt;            timer.Update += OnUpdate;&lt;br/&gt;            timer.Draw += OnDraw;&lt;br/&gt;        }&lt;p&gt;ContentManager对象是来自于App的Content属性，我们不会再有一个派生自Microsoft.Xna.Framework.Game的Host类了。然后是GameTimer的初始化工作，指定更新时间间隔，然后为Update和Draw事件添加方法。我不知道理解的是否正确，但有可能是GameTimer类重新实现了XNA Framework的机制。&lt;/p&gt;&lt;p&gt;然后是两个重载的Navigated函数：&lt;/p&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnNavigatedTo(NavigationEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            &lt;span class="rem"&gt;// Set the sharing mode of the graphics device to turn on XNA rendering&lt;/span&gt;&lt;br/&gt;            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Create a new SpriteBatch, which can be used to draw textures.&lt;/span&gt;&lt;br/&gt;            spriteBatch = &lt;span class="kwrd"&gt;new&lt;/span&gt; SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// TODO: use this.content to load your game content here&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Start the timer&lt;/span&gt;&lt;br/&gt;            timer.Start();&lt;br/&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnNavigatedTo(e);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnNavigatedFrom(NavigationEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            &lt;span class="rem"&gt;// Stop the timer&lt;/span&gt;&lt;br/&gt;            timer.Stop();&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Set the sharing mode of the graphics device to turn off XNA rendering&lt;/span&gt;&lt;br/&gt;            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnNavigatedFrom(e);&lt;br/&gt;        }&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;OnNavigatedTo函数实现了LoadContent的功能，第一句话值得注意，我们要首先打开GraphicsDevice的SetSharingMode为true，才能够让XNA元素正常的显示出来。这句话也交代了XNA最主要的类GraphicsDeviceManager的去向，被放到一个静态的SharedGraphicsDeviceManager对象里去了。&lt;/p&gt;&lt;p&gt;创建SpriteBatch和加载资源的过程不再叙述，最后要调用GameTimer的Start方法，来启动XNA的时间驱动机制，与之对应的是OnNavigatedFrom函数中，我们还需要调用GameTimer的Stop方法，来关闭时间驱动机制。&lt;/p&gt;&lt;p&gt;最后是熟悉的OnUpdate和OnDraw方法，就数这两个函数原汁原味地保留了XNA的特点。&lt;/p&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;/// Allows the page to run logic such as updating the world,&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;/// checking for collisions, gathering input, and playing audio.&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnUpdate(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, GameTimerEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            &lt;span class="rem"&gt;// TODO: Add your update logic here&lt;/span&gt;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;/// Allows the page to draw itself.&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnDraw(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, GameTimerEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.CornflowerBlue);&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// TODO: Add your drawing code here&lt;/span&gt;&lt;br/&gt;        }&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;添加Silverlight控件&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;如果只是在Silverlight应用里添加一个XNA的页面，恐怕还没有太大的吸引力。我们还应该让XNA和Silverlight能够在一个页面上显示。首先我们要打开GamePage.xaml文件，找到下面的代码：&lt;/p&gt;&lt;span class="rem"&gt;&amp;lt;!--No XAML content as the page is rendered entirely with XNA--&amp;gt;&lt;/span&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;将下列代码替换上面的注释：&lt;/p&gt;    &lt;span class="rem"&gt;&amp;lt;!-- LayoutRoot is the root grid where all page content is placed --&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Grid&lt;/span&gt; &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;LayoutRoot&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Grid.RowDefinitions&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RowDefinition&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Auto&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RowDefinition&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;*&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RowDefinition&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Auto&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Grid.RowDefinitions&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span class="rem"&gt;&amp;lt;!-- Toggles the visibility of the ColorPanel --&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ColorPanelToggleButton&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Click&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ColorPanelToggleButton_Click&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Margin&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1,0,-1,0&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Toggle Color Panel&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span class="rem"&gt;&amp;lt;!-- Arrange buttons in a horizontal line by using StackPanel --&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;StackPanel&lt;/span&gt; &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ColorPanel&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;2&amp;quot;&lt;/span&gt;  &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;100&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Orientation&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Horizontal&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;HorizontalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Center&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Visibility&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Visible&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;&amp;lt;!-- Buttons to set the rectangle to specific colors --&amp;gt;&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;Click&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;redButton_Click&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;HorizontalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Center&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;75&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Center&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;BorderThickness&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;3&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Firebrick&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;75&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;Click&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;greenButton_Click&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;HorizontalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Center&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;75&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Center&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;BorderThickness&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;3&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Lime&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;75&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;Click&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;blueButton_Click&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;HorizontalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Center&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;75&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Center&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;BorderThickness&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;3&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Blue&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;75&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;StackPanel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Grid&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;p&gt;如果编译的话，会提示没有Button对应的事件处理函数。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;添加代码&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;下面部分和MSDN提供的示例代码不同，我试图找到一种更简单的办法来更改颜色。首先，我们在GraphicsApp1LibraryContent工程里找到redRect.jpg，右键单击，选择Open With，然后在列表里选择Paint，用画图打开文件后，将整个图片涂成白色。做完这个工作后，记得一定要重新编译整个工程。&lt;/p&gt;&lt;p&gt;接下来，我们声明Color变量，并且在构造函数里赋初始值。&lt;/p&gt;Color bgColor;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; GamePage()&lt;br/&gt;&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;    // ...&lt;/span&gt;&lt;br/&gt; &lt;br/&gt;    bgColor = Color.Red;&lt;br/&gt;&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;然后我们增加事件处理函数，首先是控制颜色是否显示的控件：&lt;/p&gt;        &lt;span class="rem"&gt;// Toggle the visibility of the StackPanel named &amp;quot;ColorPanel&amp;quot;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ColorPanelToggleButton_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (System.Windows.Visibility.Visible == ColorPanel.Visibility)&lt;br/&gt;            {&lt;br/&gt;                ColorPanel.Visibility = System.Windows.Visibility.Collapsed;&lt;br/&gt;            }&lt;br/&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br/&gt;            {&lt;br/&gt;                ColorPanel.Visibility = System.Windows.Visibility.Visible;&lt;br/&gt;            }&lt;br/&gt;        }&lt;p&gt;然后是切换颜色的几个Button的处理函数：&lt;/p&gt;        &lt;span class="rem"&gt;// Switch to the red rectangle&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; redButton_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            bgColor = Color.Red;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span class="rem"&gt;// Switch to the green rectangle&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; greenButton_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            bgColor = Color.Green;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span class="rem"&gt;// Switch to the blue rectangle&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; blueButton_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            bgColor = Color.Blue;&lt;br/&gt;        }&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;最后，我们在OnDraw函数里，找到下面的代码：&lt;/p&gt;spriteBatch.Draw(texture, spritePosition, Color.White);&lt;p&gt;换成下面的代码：&lt;/p&gt;spriteBatch.Draw(texture, spritePosition, bgColor); &lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;这样我们就可以为白色的材质绘制出不同的颜色了。&lt;/p&gt;&lt;p&gt;现在程序可以编译通过了，但是运行程序后，Silverlight的控件却没办法显示出来。原因是Silverlight控件必须经过特殊的处理，才能够显示出来。首先要声明一个UIElementRenderer变量：&lt;/p&gt;&lt;span class="rem"&gt;// For rendering the XAML onto a texture&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;UIElementRenderer elementRenderer;&lt;p&gt;然后，在GamePage的构造函数里，添加下面的代码：&lt;/p&gt;&lt;span class="rem"&gt;// Use the LayoutUpdate event to know when the page layout &lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// has completed so we can create the UIElementRenderer&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;LayoutUpdated += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler(GamePage_LayoutUpdated);&lt;p&gt;添加GamePage_LayoutUpdated的函数，在函数中创建UIElementRenderer的对象：&lt;/p&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; GamePage_LayoutUpdated(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br/&gt;        {&lt;br/&gt;            &lt;span class="rem"&gt;// Create the UIElementRenderer to draw the XAML page to a texture.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Check for 0 because when we navigate away the LayoutUpdate event&lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// is raised but ActualWidth and ActualHeight will be 0 in that case.&lt;/span&gt;&lt;br/&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (ActualWidth &amp;gt; 0 &amp;amp;&amp;amp; ActualHeight &amp;gt; 0 &amp;amp;&amp;amp; elementRenderer == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br/&gt;            {&lt;br/&gt;                elementRenderer = &lt;span class="kwrd"&gt;new&lt;/span&gt; UIElementRenderer(&lt;span class="kwrd"&gt;this&lt;/span&gt;, (&lt;span class="kwrd"&gt;int&lt;/span&gt;)ActualWidth, (&lt;span class="kwrd"&gt;int&lt;/span&gt;)ActualHeight);&lt;br/&gt;            }&lt;br/&gt;        }&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;最后，在OnDraw函数里，添加下面的代码：&lt;/p&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;/// Allows the page to draw itself.&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnDraw(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, GameTimerEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.Black);&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// TODO: Add your drawing code here&lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Render the Silverlight controls using the UIElementRenderer&lt;/span&gt;&lt;br/&gt;            elementRenderer.Render();&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Draw the sprite&lt;/span&gt;&lt;br/&gt;            spriteBatch.Begin();&lt;br/&gt;            spriteBatch.Draw(texture, spritePosition, bgColor); &lt;span class="rem"&gt;//Color.White);&lt;/span&gt;&lt;br/&gt;            spriteBatch.DrawString(StartFont, &lt;span class="str"&gt;&amp;quot;Hello, XNA&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(50), Color.Blue);&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Using the texture from the UIElementRenderer, &lt;/span&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// draw the Silverlight controls to the screen&lt;/span&gt;&lt;br/&gt;            spriteBatch.Draw(elementRenderer.Texture, Vector2.Zero, Color.White);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;            spriteBatch.End();&lt;br/&gt;        }&lt;p&gt;再运行程序时，我们就可以看到Silverlight控件了，点击颜色控件，方块会切换成对应的颜色。如下图所示：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013444174.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="6" border="0" alt="6" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013441209.png" width="299" height="562" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;strong&gt;加载XNA资源&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;到这里，我们的体验基本上告一段落了，但是我试了一下是否能够正常加载XNA的字体，所以就写了最后这部分。&lt;/p&gt;&lt;p&gt;右键点击GraphicsApp1LibraryContent，选择Add &amp;#8211; New Item。在对话框中选择Sprite Font，我们将字体命名为StartFont。在打开的字体文件中，我们将Size改成30，如下面所示：&lt;/p&gt;    &lt;span class="rem"&gt;&amp;lt;!--&lt;/span&gt;&lt;br/&gt;&lt;span class="rem"&gt;    Size is a float value, measured in points. Modify this value to change&lt;/span&gt;&lt;br/&gt;&lt;span class="rem"&gt;    the size of the font.&lt;/span&gt;&lt;br/&gt;&lt;span class="rem"&gt;    --&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Size&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;30&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Size&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;p&gt;回到GamePage.xaml.cs文件中，我们首先声明SpriteFont变量：&lt;/p&gt;SpriteFont StartFont;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;然后，在OnNavigatedTo函数中，添加字体加载的代码：&lt;/p&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnNavigatedTo(NavigationEventArgs e)&lt;br/&gt;        {&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// Set the sharing mode of the graphics device to turn on XNA rendering&lt;/span&gt;&lt;br/&gt;            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            spriteBatch = &lt;span class="kwrd"&gt;new&lt;/span&gt; SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);&lt;br/&gt;&lt;br/&gt;            &lt;span class="rem"&gt;// TODO: use this.content to load your game content here&lt;/span&gt;&lt;br/&gt;            texture = content.Load&amp;lt;Texture2D&amp;gt;(&lt;span class="str"&gt;&amp;quot;redRect&amp;quot;&lt;/span&gt;);&lt;br/&gt;            StartFont = content.Load&amp;lt;SpriteFont&amp;gt;(&lt;span class="str"&gt;&amp;quot;StartFont&amp;quot;&lt;/span&gt;);&lt;p&gt;最后，在OnDraw函数里，添加字体的绘制函数：&lt;/p&gt;spriteBatch.DrawString(StartFont, &lt;span class="str"&gt;&amp;quot;Hello, XNA&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(50), Color.Blue);&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;程序运行的效果如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013451831.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="7" border="0" alt="7" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013469422.png" width="323" height="602" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;strong&gt;另一条路&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;除了在Silverlight for Windows Phone创建Windows Phone 3D Graphics Application外，我们还能够通过另一种方式创建XNA与Silverlight整合的应用程序。&lt;/p&gt;&lt;p&gt;在XNA Game Studio 4.0中，选择Windows Phone Rich Graphics Application：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013478649.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="1" border="0" alt="1" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013483764.png" width="714" height="495" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;通过这个向导创建的程序，与上面创建的程序大同小异，只是界面略有不同。运行界面如下：&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/20110617001349275.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="8" border="0" alt="8" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013503406.png" width="270" height="503" /&gt;&lt;/a&gt; &lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013528130.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="9" border="0" alt="9" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013536801.png" width="272" height="506" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;好了，到这里，我们正式将Windows Phone 7.1中的Silverlight与XNA整合应用介绍完了。在XNA游戏中，我们可以使用Silverlight来创建界面；也可以在Silverlight应用中编写高性能的3D界面。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;OpenXLive杯Windows Phone游戏开发大赛&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013539658.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image019" border="0" alt="clip_image019" src="http://images.cnblogs.com/cnblogs_com/aawolf/201106/201106170013545231.jpg" width="212" height="225" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;OpenXLive杯Windows Phone游戏开发大赛，是由OpenXLive联合国内知名的开发者社区：DevDiv、智机网、WPMind、Silverlight银光中国和XNA游戏世界，一起举办的针对Windows Phone游戏开发的比赛。&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.openxlive.net/posts/news/40"&gt;http://www.openxlive.net/posts/news/40&lt;/a&gt;&lt;/p&gt; &lt;img src="http://www.cnblogs.com/aawolf/aggbug/2083222.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/aawolf/archive/2011/06/17/2083222.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/aawolf/archive/2011/04/02/2003381.html</id><title type="text">如何将OpenXLive添加到WP7 Silverlight游戏中</title><summary type="text">OpenXLive beta版发布已经有一个半月的时间了，得到了开发者和玩家的好评，目前已经有五款OpenXLive游戏进入Windows Phone Marketplace，其中的7bomb和Super Hoops都取得了非常骄人的成绩。 当OpenXLive在XNA游戏中大展身手的同时，我们也听到了一些来自Silverlight程序员的抱怨。在Windows Phone 7中虽然提供了XNA的游戏开发平台，但相当一部分的游戏是采用Silverlight开发的。毕竟对于显示性能不高的游戏来说，Silverlight是一个颇具魅力的快速开发工具。 幸好，我们在最初的架构设计上考虑了未来支持Si</summary><published>2011-04-02T07:06:00Z</published><updated>2011-04-02T07:06:00Z</updated><author><name>马宁</name><uri>http://www.cnblogs.com/aawolf/</uri></author><link rel="alternate" href="http://www.cnblogs.com/aawolf/archive/2011/04/02/2003381.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/aawolf/archive/2011/04/02/2003381.html"/><content type="html">&lt;p&gt;OpenXLive beta版发布已经有一个半月的时间了，得到了开发者和玩家的好评，目前已经有五款OpenXLive游戏进入Windows Phone Marketplace，其中的7bomb和Super Hoops都取得了非常骄人的成绩。&lt;/p&gt;  &lt;p&gt;当OpenXLive在XNA游戏中大展身手的同时，我们也听到了一些来自Silverlight程序员的抱怨。在Windows Phone 7中虽然提供了XNA的游戏开发平台，但相当一部分的游戏是采用Silverlight开发的。毕竟对于显示性能不高的游戏来说，Silverlight是一个颇具魅力的快速开发工具。&lt;/p&gt;  &lt;p&gt;幸好，我们在最初的架构设计上考虑了未来支持Silverlight的可能性，所以将业务逻辑部分封装到了OpenXLive.dll中，而将XNA上的XLiveForm窗体和控件库封装到了OpenXLive.Forms.dll中。我们只需要在Silverlight中调用OpenXLive中的功能即可。&lt;/p&gt;  &lt;p&gt;在提供了一个OpenXLive on Silverlight的简单示例代码后，我们发现对Silverlight游戏的支持仍旧不够。首先，我们只提供了Leaderboard部分的示例代码，在缺乏文档的情况下，开发其他功能的UI是很困难的；其次，开发者并不希望自己动手写一个Silverlight UI，而只是想简单地在游戏中加入OpenXLive的支持，就像在XNA游戏中那样。&lt;/p&gt;  &lt;p&gt;所以，我们重新定义了OpenXLive Silverlight的功能，实现了OpenXLive中的所有功能，并将其封装到了OpenXLive.Silverlight.dll中。在开发过程中，我们尽力保持XNA和Silverlight框架的一致性，如果您使用过OpenXLive XNA版本，在Silverlight版本中，您会有一种似曾相识的感觉，这正是我们所希望的。&lt;/p&gt;  &lt;p&gt;需要提示的一点是，OpenXLive的Silverlight和XNA版本共同使用了一个逻辑程序集——OpenXLive.dll，所以他们在功能上是一致的。&lt;/p&gt;  &lt;p&gt;未来，我们会将OpenXLive Silverlight加入到OpenXLive SDK中，并提供Visual Studio模板。在某一个时间点上，我们会考虑对OpenXLive Silverlight进行开源，让开发者能够方便的将OpenXLive Silverlight修改成自己想要的样子。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;OpenXLive简介&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;微软为Windows Phone 7上的XNA和Silverlight游戏开发提供了非常好的开发工具和应用程序框架，使得开发者可以更加容易地开发出生动有趣的游戏来。但是随着开发的深入，我们发现，虽然我们开发的游戏品质可以和大公司的产品相媲美，但比起大公司游戏的用户体验还是相差很多。因为，我们必须将很多时间用于周边功能的开发，比如：启动界面(Splash Screen), 积分榜(Leaderboard)和游戏成就(Achievement)等，更不要奢谈为游戏加入SNS功能，比如：查看在线用户(Online Player)、云存储(Cloud Storage)等在线功能了。这些周边功能的开发时间，可能要超过游戏本身的开发时间，那我们该怎么办呢？&lt;/p&gt;  &lt;p&gt;OpenXLive正在想办法帮助个人开发者和小团队开发者，使他们在最短的时间内拥有以上这些只有大公司才可能拥有的游戏功能。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506102878.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="openxlive logo" border="0" alt="openxlive logo" src="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506117305.png" width="367" height="99" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;OpenXLive是一种为Windows Phone 7智能手机游戏开发者提供的云端在线服务。支持开发者为单机游戏增加云端和SNS功能，帮助开发者以最小的工作量将云端服务集成到自己的游戏中。这些云端服务包括：积分榜、游戏成就、在线对战、Social Network和云端存储等功能。与Open XLive类似的服务，还有iOS上的OpenFeint。&lt;/p&gt;  &lt;p&gt;OpenXLive目前支持Windows Phone的XNA与Silverlight开发框架，不需要开发者编写UI代码，即可在游戏中方便地调用OpenXLive的界面及功能。由于XNA和Silverlight是两个不同的应用程序框架，所以，OpenXLive提供了不同的引用方式来支持XNA和Silverlight游戏。&lt;/p&gt;  &lt;p&gt;本文讨论的是如何将OpenXLive加入到Silverlight游戏中，如果您的游戏采用XNA编写，请查看《OpenXLive开发入门》，链接如下：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://wiki.openxlive.net/Getting-Started-with-Open-XLive.ashx"&gt;http://wiki.openxlive.net/Getting-Started-with-Open-XLive.ashx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;添加引用&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;您可以在下面的链接中下载单独的OpenXLive Silverlight SDK:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://resource.openxlive.com/resource/Download/ad686043-d477-4d5a-bc83-f27520a3d600" href="http://resource.openxlive.com/resource/Download/ad686043-d477-4d5a-bc83-f27520a3d600"&gt;http://resource.openxlive.com/resource/Download/ad686043-d477-4d5a-bc83-f27520a3d600&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;首先，我们假设您已经有了基于Silverlight开发的Windows Phone游戏。如果您想从头创建一个OpenXLive Silverlight游戏，您可以参考下一节《OpenXLive Silverlight向导使用》。&lt;/p&gt;  &lt;p&gt;我们采用的示例工程OpenXLiveGameSilverlight，您可以在OpenXLive的资源网站中找到。&lt;/p&gt;  &lt;p&gt;首先，我们在OpenXLive SDK的bin文件夹下找到OpenXLive.dll和OpenXLive.Silverlight.dll，将其拷贝到工程所在的目录中。&lt;/p&gt;  &lt;p&gt;然后，在Visual Studio 2010中，打开OpenXLiveGameSilverlight工程，在Solution Explorer中找到References节点，右键单击啊，选择Add References，在对话框中选择Browse页面，找到工程目录下的OpenXLive.dll和OpenXLive.Silverlight.dll，将两个程序集的引用加入到工程中。&lt;/p&gt;  &lt;p&gt;添加成功后，如下图所示：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506116192.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="SLDemo1" border="0" alt="SLDemo1" src="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506119747.png" width="312" height="401" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;修改初始页面&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;在引用添加完成之后，我们还要修改WMAppMainifest.xml文件，使Silverlight游戏启动时，启动OpenXLive.Silverlight中所包含的Startup页面。&lt;/p&gt;  &lt;p&gt;在工程的Propertes节点下找到WMAppMainifest.xml文件，双击打开，如下图所示：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506115810.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="SLDemo2" border="0" alt="SLDemo2" src="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506124141.png" width="376" height="376" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;WMAppMainifest.xml文件的结构如下：&lt;/p&gt;  &lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;utf-8&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Deployment&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://schemas.microsoft.com/windowsphone/2009/deployment&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;AppPlatformVersion&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;7.0&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;App&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;ProductID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;{3cf35939-f7f6-4808-969c-22d520f6a526}&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Title&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;OpenXLiveGameSilverlight&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;RuntimeType&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Silverlight&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Version&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1.0.0.0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Genre&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;apps.normal&amp;quot;&lt;/span&gt;  &lt;span class="attr"&gt;Author&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;OpenXLiveGameSilverlight author&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Description&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Sample description&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Publisher&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;OpenXLiveGameSilverlight&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;IconPath&lt;/span&gt; &lt;span class="attr"&gt;IsRelative&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;IsResource&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;ApplicationIcon.png&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;IconPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Capabilities&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Capability&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ID_CAP_GAMERSERVICES&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Capabilities&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Tasks&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DefaultTask&lt;/span&gt;  &lt;span class="attr"&gt;Name&lt;/span&gt; &lt;span class="kwrd"&gt;=&amp;quot;_default&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;NavigationPage&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;OpenXLive.Silverlight;component/Forms/StartupPage.xaml&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Tasks&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Tokens&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PrimaryToken&lt;/span&gt; &lt;span class="attr"&gt;TokenID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;OpenXLiveGameSilverlightToken&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;TaskName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;_default&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TemplateType5&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BackgroundImageURI&lt;/span&gt; &lt;span class="attr"&gt;IsRelative&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;IsResource&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Background.png&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;BackgroundImageURI&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Count&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;0&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Count&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;OpenXLiveGameSilverlight&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TemplateType5&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PrimaryToken&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Tokens&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;App&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Deployment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;在WMAppMainifest.xml文件中找到&lt;b&gt;DefaultTask&lt;/b&gt;节点，并将其中的NavigationPage改为&amp;#8221;OpenXLive.Silverlight;component/Forms/StartupPage.xaml&amp;#8221;。这样能保证Silverlight游戏启动之后，会首先启动OpenXLive的Startup页面。&lt;/p&gt;&lt;p&gt;接下来，我们还要完成对XLiveSLFormManager对象的初始化工作。打开工程中的App.xaml.cs文件，首先在文件顶部加入对OpenXLive.Silverlight的引用：&lt;/p&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; OpenXLive.Silverlight;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;然后，在App类中找到&lt;b&gt;Application_Launching&lt;/b&gt;方法，加入XLiveSLFormManager对象的创建操作：&lt;/p&gt;        &lt;span class="rem"&gt;// Code to execute when the application is launching (eg, from Start)&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;// This code will not execute when the application is reactivated&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Launching(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, LaunchingEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            XLiveSLFormManager manager = &lt;span class="kwrd"&gt;new&lt;/span&gt; XLiveSLFormManager(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;xxxxxxxxxxxxxxxx&amp;quot;&lt;/span&gt;);&lt;br/&gt;        }&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;其中，第一个参数为App实例的引用，第二个参数为SecretKey，该Key是在OpenXLive网站上创建游戏时，由系统生成的，作为OpenXLive系统识别游戏的唯一标识符，请保证这个SecretKey的安全，以防止其他游戏进行仿冒。&lt;/p&gt;&lt;p&gt;更多详细情况，请查看《在开发者网站上创建OpenXLive游戏》，链接如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://wiki.openxlive.net/Tutorial-4-Create-OpenXLive-Game-in-website.ashx"&gt;http://wiki.openxlive.net/Tutorial-4-Create-OpenXLive-Game-in-website.ashx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;当然，我们也可以在App类中创建一个static的FormManager属性，用于在程序的其他地方调用XLiveSLFormManager对象，但这一步不是必须的，代码如下：&lt;/p&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; XLiveSLFormManager FromManager { get; &lt;span class="kwrd"&gt;internal&lt;/span&gt; set; }&lt;br/&gt;&lt;br/&gt;        &lt;span class="rem"&gt;// Code to execute when the application is launching (eg, from Start)&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;// This code will not execute when the application is reactivated&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Launching(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, LaunchingEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            FromManager = &lt;span class="kwrd"&gt;new&lt;/span&gt; XLiveSLFormManager(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;xxxxxxxxxxxxxxxxxx&amp;quot;&lt;/span&gt;);&lt;br/&gt;        }&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;我们运行程序，能够看到下面的界面，是不是有一种似曾相识的感觉？点击Game Center和Leaderboards，我们可以进入相关的界面：&lt;/p&gt;&lt;p align="center"&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506135155.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SLDemo3" border="0" alt="SLDemo3" src="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506133170.png" width="197" height="365" /&gt;&lt;/a&gt;&amp;#160;&amp;#160; &lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506139549.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SL2" border="0" alt="SL2" src="http://images.cnblogs.com/cnblogs_com/aawolf/201104/20110402150614563.png" width="197" height="365" /&gt;&lt;/a&gt;&amp;#160; &lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506156876.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SL3" border="0" alt="SL3" src="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506156843.png" width="196" height="364" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;目前OpenXLive Silverlight只支持竖屏（Portrait）显示，未来我们会加入对于横屏（Landscape）的支持。另外，除了Startup界面之外，其他OpenXLive界面都是黑色背景，这样做主要是为了节省系统资源。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;添加背景和事件处理&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;接下来，为了美化启动界面，我们要加入背景图片。添加背景图片的操作非常简单：在Solution Explorer中，选择Project节点，右键单击，选择Add &amp;#8211; Existing Item，在选择一副PNG或JPG的图片，尺寸最好是800x480，这样能够有效保证图片不变形。&lt;/p&gt;&lt;p&gt;另外请确认一下，我们加入的图片Build Action为Resource，且Copy to Output Directory选择&amp;#8220;Do not copy&amp;#8221;。&lt;/p&gt;&lt;p&gt;然后，回到App.xaml.cs文件的Application_Launching方法中：&lt;/p&gt;        &lt;span class="rem"&gt;// Code to execute when the application is launching (eg, from Start)&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;// This code will not execute when the application is reactivated&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Launching(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, LaunchingEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            FromManager = &lt;span class="kwrd"&gt;new&lt;/span&gt; XLiveSLFormManager(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;xxxxxxxxxxxxxxxxxxx&amp;quot;&lt;/span&gt;);&lt;br/&gt;            StartupPage.BackgroundPath = &lt;span class="str"&gt;&amp;quot;/OpenXLiveGameSilverlight;component/OpenXLive.Portrait.png&amp;quot;&lt;/span&gt;;&lt;br/&gt;        }&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;我们要为StartupPage添加BackgroundPath，示例代码的写法是针对游戏本身的资源，也可以指定一个来自Web的链接，不过出于显示效果的考虑，建议您不要这么做。OpenXLiveGameSilverlight，是资源所在程序集的名称；component/OpenXLive.Portrait.png，是资源的引用路径，如果资源包含在一个文件夹中，写法应该是component/MyFolder/OpenXLive.Portrait.png。&lt;/p&gt;&lt;p&gt;最后提醒，请大家千万不要忘记字符串前面的&amp;#8220;/&amp;#8221;，没有这个符号，程序将抛出异常。&lt;/p&gt;&lt;p&gt;接下来，我们要加入Startup页面的事件处理函数，当用户点击某一个按钮时，会触发一个事件操作。我们在下面增加了其中两个按钮的事件处理方法：&lt;/p&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; XLiveSLFormManager FromManager { get; &lt;span class="kwrd"&gt;internal&lt;/span&gt; set; }&lt;br/&gt;&lt;br/&gt;        &lt;span class="rem"&gt;// Code to execute when the application is launching (eg, from Start)&lt;/span&gt;&lt;br/&gt;        &lt;span class="rem"&gt;// This code will not execute when the application is reactivated&lt;/span&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Launching(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, LaunchingEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            FromManager = &lt;span class="kwrd"&gt;new&lt;/span&gt; XLiveSLFormManager(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;xxxxxxxxxxxxxxxxxx&amp;quot;&lt;/span&gt;);&lt;br/&gt;            StartupPage.BackgroundPath = &lt;span class="str"&gt;&amp;quot;/OpenXLiveGameSilverlight;component/OpenXLive.Portrait.png&amp;quot;&lt;/span&gt;;&lt;br/&gt;            StartupPage.NewGameButtonClick += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler(StartupPage_NewGameButtonClick);&lt;br/&gt;            StartupPage.AboutButtonClick += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler(StartupPage_AboutButtonClick);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; StartupPage_AboutButtonClick(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br/&gt;        {&lt;br/&gt;            MessageBox.Show(&lt;span class="str"&gt;&amp;quot;OpenXLive Silverlight Demo 1.0&amp;quot;&lt;/span&gt;);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; StartupPage_NewGameButtonClick(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br/&gt;        {&lt;br/&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.RootFrame.Navigate(&lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;&amp;quot;/MainPage.xaml&amp;quot;&lt;/span&gt;, UriKind.Relative));&lt;br/&gt;        }&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;AboutButtonClick的处理函数非常简单，只是调用了Message来显示游戏的版本信息。而NewGameButtonClick则是为了调用开发人员自己编写的Silverlight游戏界面，这个界面应该存在于Silverlight游戏的程序集中。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506162283.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="SL1" border="0" alt="SL1" src="http://images.cnblogs.com/cnblogs_com/aawolf/201104/20110402150617199.png" width="237" height="441" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;最后，我们得到的Silverlight启动界面就是上图这样。我们在Silverlight的界面中，没有增加Exit选项，因为Silverlight界面默认不支持退出操作，只能通过按Back键来退出程序。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用Wizard创建新游戏&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;接下来，我们要介绍如何使用Visual Studio 2010的Template来创建一个OpenXLive Silverlight游戏。OpenXLive Silverlight的模板会包括在OpenXLive SDK中，如果您安装了OpenXLive SDK，就可以在Visual Studio 2010中创建基于Silverlight的游戏了。&lt;/p&gt;&lt;p&gt;首先，打开Visual Studio 2010，在File菜单中选择New-Project，在New Project对话框中，选择Visual C#下的Silverlight for Windows Phone中的OpenXLive Silverlight节点，然后选择创建OpenXLiveSilverlightGame。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506186512.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Wizard1" border="0" alt="Wizard1" src="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506196413.png" width="657" height="393" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;OpenXLiveSilverlightGame工程创建完毕后，如果直接编译，会得到下列的错误提示：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506193349.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Wizard2" border="0" alt="Wizard2" src="http://images.cnblogs.com/cnblogs_com/aawolf/201104/201104021506205824.png" width="631" height="148" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;这个错误是为了提醒开发者，要在OpenXLive开发者网站上创建自己的游戏，获取游戏对应的Secret Key，才能够正常使用OpenXLive的在线功能。&lt;/p&gt;&lt;p&gt;获取Secret Key的方法，请参考《在开发者网站上创建OpenXLive游戏》，链接如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://wiki.openxlive.net/Tutorial-4-Create-OpenXLive-Game-in-website.ashx"&gt;http://wiki.openxlive.net/Tutorial-4-Create-OpenXLive-Game-in-website.ashx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;打开App.xaml.cs文件，找到下面的代码：&lt;/p&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; XLiveSLFormManager FromManager { get; &lt;span class="kwrd"&gt;internal&lt;/span&gt; set; }&lt;br/&gt;&lt;br/&gt;&lt;span class="preproc"&gt;#error&lt;/span&gt; Please full your game Secret Key &lt;span class="kwrd"&gt;in&lt;/span&gt; below code&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; APISecretKey = &lt;span class="str"&gt;&amp;quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxx&amp;quot;&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span class="rem"&gt;// Code to execute when the application is launching (eg, from Start)&lt;/span&gt;&lt;br/&gt;&lt;span class="rem"&gt;// This code will not execute when the application is reactivated&lt;/span&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Launching(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, LaunchingEventArgs e)&lt;br/&gt;{&lt;br/&gt;    FromManager = &lt;span class="kwrd"&gt;new&lt;/span&gt; XLiveSLFormManager(&lt;span class="kwrd"&gt;this&lt;/span&gt;, APISecretKey);&lt;br/&gt;    StartupPage.BackgroundPath = &lt;span class="str"&gt;&amp;quot;/OpenXLiveSilverlightGame2;component/OpenXLive.Portrait.png&amp;quot;&lt;/span&gt;;&lt;br/&gt;    StartupPage.NewGameButtonClick += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler(StartupPage_NewGameButtonClick);&lt;br/&gt;    StartupPage.AboutButtonClick += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler(StartupPage_AboutButtonClick);&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;开发者将Secret Key加入到高亮显示部分，并且注释掉#error代码，我们的工程就可以正常编译了。&lt;/p&gt;&lt;p&gt;我们也可以修改New Game Button的事件处理函数，来决定调用哪个Silverlight窗体。&lt;/p&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; StartupPage_NewGameButtonClick(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br/&gt;{&lt;br/&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.RootFrame.Navigate(&lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;&amp;quot;/MainPage.xaml&amp;quot;&lt;/span&gt;, UriKind.Relative));&lt;br/&gt;}&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;到这里，我们就介绍完了如何通过Visual Studio 2010向导来创建OpenXLive Silverlight游戏的方法。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;写在最后&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我们用几乎与XNA版本相同的顺序，叙述了如何将OpenXLive Silverlight加入到Windows Phone Silverlight的游戏中去。接下来，我们会介绍，如何提交成绩、提交成就，考虑到Silverlight的界面编程更加容易，我们并不会提供一个标准的成绩提交界面，该界面只会以示例代码的形式出现。&lt;/p&gt;&lt;p&gt;&lt;a href="http://wiki.openxlive.net/OpenXLive-Silverlight.ashx"&gt;http://wiki.openxlive.net/OpenXLive-Silverlight.ashx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;引用&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;OpenXLive&lt;/strong&gt;&lt;strong&gt;官方网站&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.openxlive.net/"&gt;http://www.openxlive.net/&lt;/a&gt;&lt;strong&gt; &lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;OpenXLive&lt;/strong&gt;&lt;strong&gt;开发者网站&lt;/strong&gt;&lt;strong&gt; &lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.openxlive.net/"&gt;http://developer.openxlive.net/&lt;/a&gt;&lt;strong&gt; &lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;OpenXLive&lt;/strong&gt;&lt;strong&gt;开发入门&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://wiki.openxlive.net/Getting-Started-with-Open-XLive.ashx"&gt;http://wiki.openxlive.net/Getting-Started-with-Open-XLive.ashx&lt;/a&gt;&lt;/p&gt; &lt;img src="http://www.cnblogs.com/aawolf/aggbug/2003381.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/aawolf/archive/2011/04/02/2003381.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
