﻿<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>学习日记 &#187; metro</title>
	<atom:link href="https://www.softwareace.cn/?feed=rss2&#038;tag=metro" rel="self" type="application/rss+xml" />
	<link>https://www.softwareace.cn</link>
	<description>时刻想着为自己的产品多做一些对他好的事情</description>
	<lastBuildDate>Fri, 20 Mar 2026 06:58:28 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	
	<item>
		<title>Windows 8 Metro 风格应用程序的生命周期</title>
		<link>https://www.softwareace.cn/?p=764</link>
		<comments>https://www.softwareace.cn/?p=764#comments</comments>
		<pubDate>Wed, 02 Apr 2014 02:01:18 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[开发经验]]></category>
		<category><![CDATA[metro]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=764</guid>
		<description><![CDATA[为 Windows 8 中的 Metro 风格应用程序开发生命周期模型时我们牢记以下几个方面：保持应用程序响应 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>为 Windows 8 中的 Metro 风格应用程序开发生命周期模型时我们牢记以下几个方面：保持应用程序响应能力、节省电池电量并提供出色且一致的性能。Metro 风格应用程序关键在于全屏沉浸式体验。因此，Windows 8 中新的生命周期模型重点关注前台应用程序，确保积极主动的用户体验并充分实现设备的全部价值。在本博文中，我将带您浏览生命周期模型的新状态以及为了使应用程序出色运行您需要做的工作。</p>
<h3>Metro 风格应用程序的生命周期</h3>
<p>在任意给定时间，您的 Metro 风格应用程序都处于以下四种生命周期状态之一：<strong>未运行、正在运行</strong>、<strong>已挂起</strong>或<strong>已终止</strong>。当应用程序在不同状态之间切换时，它会收到生命周期事件，这些事件可帮助您向用户提供一致且高性能的体验。</p>
<p>下图显示了 Metro 风格应用程序如何在各状态之间切换：</p>
<p><img title="Metro 风格应用程序的生命周期" alt="用表示循环模式的箭头连接起来的 3 个框。未运行 &gt; 正在激活 &gt; 正在运行 &gt; 正在挂起 &gt; 已挂起 &gt; 正在终止 &gt; 未运行。" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-51-31-metablogapi/1563.app_2D00_lifecycle_5F00_018E5A34.png" width="642" height="397" border="0" /></p>
<p>当用户启动 Metro 风格应用程序、在应用程序之间切换以及关闭应用程序时，所有这些应用程序都会经历这些状态。当用户在应用程序之间切换时，应用程序很可能频繁在<strong>正在运行</strong>和<strong>已挂起</strong>状态之间切换。因此，应用程序必须处理生命周期事件。</p>
<p>当您的应用程序在各个生命周期状态之间切换时，它会收到以下生命周期事件：</p>
<div align="center">
<table border="0" cellspacing="0" cellpadding="3" align="center">
<tbody>
<tr>
<td valign="top" width="34%"><strong>事件</strong></td>
<td valign="top" width="34%"><strong>从</strong></td>
<td valign="top" width="31%"><strong>到</strong></td>
</tr>
<tr>
<td valign="top" width="34%">activated</td>
<td valign="top" width="34%">未运行</td>
<td valign="top" width="31%">正在运行</td>
</tr>
<tr>
<td valign="top" width="34%">suspending 或 checkpoint (WinJS)</td>
<td valign="top" width="34%">正在运行</td>
<td valign="top" width="31%">已挂起</td>
</tr>
<tr>
<td valign="top" width="34%">resuming</td>
<td valign="top" width="34%">已挂起</td>
<td valign="top" width="31%">正在运行</td>
</tr>
</tbody>
</table>
</div>
<h4>挂起</h4>
<p>通常情况下，Metro 风格应用程序会在用户切换到另一应用程序时停止运行。Windows 会挂起不在前台的应用程序。当您的应用程序挂起时，它在内存中处于冻结状态。处于此状态时，它无法运行，但如果用户返回该应用程序，Windows 可立即将其恢复。这样，Windows 就可以让前台应用程序更好地使用系统资源，并确保后台应用程序不会耗尽用户的电池电量。</p>
<p>当您的应用程序离开前台时，Windows 会等待几秒钟以便能够快速切换回该应用程序，然后才尝试将其挂起。您的应用程序必须注册 <strong>suspending</strong> 或 <strong>checkpoint</strong>(JavaScript) 事件，当 Windows 需要将其挂起时，它会收到这些事件。这是应用程序的重要时刻；可利用此机会保存必须保留在持久存储中的应用程序数据。通常，您的应用程序会按原样恢复，您不需要持久留存的数据，因为它们仍然在内存中。但您需要存储这些数据以防 Windows 为了释放系统资源而终止应用程序。保存足够的应用程序数据可让用户返回到当应用程序挂起时他们在应用程序中所处的位置。这样，您的客户就会感觉您的应用程序始终处于运行状态。</p>
<p>如果应用程序没有在收到挂起事件后的 5 秒内从挂起事件处理程序中返回，Windows 会将其终止。切勿在挂起事件处理程序中执行任何繁重操作，这一点非常重要。应保存应用程序数据并快速返回。</p>
<p>在本博文中，我们以股票应用程序为例。该应用程序可以使用挂起事件来保存用户上次查看的股票以及股价图的时间范围。这样一来，如果应用程序被终止，它就可以正好重新启动到用户上次查看该应用程序时所看到的同一视图。例如，针对股票应用程序的建议是，借此机会发送本地磁贴通知，以便在 Windows 挂起应用程序之前，应用程序的磁贴能够使用最新信息进行更新。</p>
<h5>在 JavaScript 中处理挂起</h5>
<p>如果您使用 Windows JavaScript 库 (WinJS) 编写 Metro 风格应用程序，则可以使用 <strong>checkpoint</strong> 事件处理挂起。</p>
<blockquote>
<div id="codeSnippetWrapper">
<pre class="crayon-plain-tag">var app = WinJS.Application;

function checkpointHandler() {
    // The checkpoint event gives us the chance to save application data.
    // In this case, we save the current stock info that the user is viewing.
    app.sessionState.lastSeenStock = selectedStock;
    app.sessionState.lastSeenRange = selectedRange;

    // Send client side notifications
    Tile.sendTileUpdate(selectedStock, stockInfo.change, stockInfo.lastSale, 
stockInfo.lastSaleTime, stockInfo.open); 
}

app.addEventListener(&quot;checkpoint&quot;, checkpointHandler);</pre>
</div>
</blockquote>
<p>这只是一个概要。有关详细信息，请参阅开发中心中的<a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh465138.aspx" target="_blank">如何挂起应用程序（JavaScript 和 HTML）</a>。</p>
<h5>在 XAML 中处理挂起</h5>
<p>如果您使用 XAML 和 C# 编写 Metro 风格应用程序，则可以对应用程序对象使用 <strong>Suspending</strong> 事件来处理应用程序挂起。</p>
<blockquote>
<div id="codeSnippetWrapper">
<pre class="crayon-plain-tag">public App()
{
    InitializeComponent();
    this.Suspending += new SuspendingEventHandler(OnSuspending);
}

async protected void OnSuspending(object sender, SuspendingEventArgs args)
{
    // The Suspending event gives us the chance to save application state
    // In this case, we save the current stock info that the user is viewing

    // Because writing to a file is asynchronous, we grab a deferral which ensures
    // that suspending doesn&rsquo;t complete until our file write is complete
    SuspendingDeferral deferral = args.SuspendingOperation.GetDeferral();

    // Here we create a SuspensionManager class which handles adding session data
    // to a Dictionary and then serializing that data to a file
    SuspensionManager.SessionState[&quot;lastSeenStock&quot;] = stock;
    SuspensionManager.SessionState[&quot;lastSeenRange&quot;] = range;
    await SuspensionManager.SaveAsync();

     // Send client side notifications
    Tile.SendTileUpdate(stock, stockInfo.Change, stockInfo.LastSale, 
stockInfo.LastSaleTime, stockInfo.Open);

    deferral.Complete();
}</pre>
</div>
</blockquote>
<p>这同样只是一个概要。有关如何在 XAML 和 C# 中处理挂起的详细信息，请参阅开发中心中的<a href="http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh465115.aspx" target="_blank">如何挂起应用程序（VB/C#/C++ 和 XAML）</a>。</p>
<h4>恢复</h4>
<p>当应用程序恢复时，它将从 Windows 将其挂起它所处的状态继续进行。具体说就是：当应用程序挂起，应用程序数据和状态保留在内存中，因此当它恢复时，一切都保持它挂起时的状态。在收到 <strong>resuming</strong> 事件时，您不需要明确还原任何已保存的数据。</p>
<p>但您希望您的应用程序看起来始终处于运行状态。为此，它必须保持连接并显示最新数据。但是在恢复之前，您的应用程序可能会在挂起状态停留很长时间。因此数据或网络连接可能会过时，在应用程序恢复时，可能需要刷新连接。当用户将您的应用程序切换到前台时，它会收到 <strong>resuming</strong> 事件。您可以在应用程序收到此事件时刷新应用程序内容并重新连接网络资源。</p>
<p>在我们的示例股票应用程序中，将在恢复时刷新应用程序在挂起前所具有的所有缓存股票数据。之前的数据可能已存在数小时甚至数天之久。如果用户看到这些旧数据，他们就会意识到所用应用程序并非始终处于运行状态。因此在恢复时，我们的股票应用程序必须更新其所有数据。这样，应用程序每次切换到前台时，用户都会看到最新的股票价格、股价图和新闻文章。</p>
<h5>在 JavaScript 中处理恢复</h5>
<p>在 JavaScript 中，您可以在 <strong>Windows.UI.WebUI.WebUIApplication</strong> 命名空间中使用 Windows 运行时 <strong>resuming </strong>事件。这是专门用于 JavaScript 应用程序的 resuming 事件。</p>
<blockquote>
<div id="codeSnippetWrapper">
<pre class="crayon-plain-tag">function resumingHandler() {
    //Update the selected stock with the latest news, stock info, and chart data
    News.requestNews(stock);
    Api.getStockInfoData(stock).then(function(data){displayStockInfo(data); });
    Api.getHistoryData(range).then(function (chartData) 
{CanvasChart.drawChart(&quot;chartCanvas&quot;, chartData, Chart.getChartOptions(false));});

    // Send client side notifications
    Tile.sendTileUpdate(stock, stockInfo.change, stockInfo.lastSale, 
stockInfo.lastSaleTime, stockInfo.open);    
        }

Windows.UI.WebUI.WebUIApplication.addEventListener(&quot;resuming&quot;, resumingHandler);</pre>
</div>
</blockquote>
<p>有关详细信息，请参阅开发中心中的<a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh465114.aspx" target="_blank">如何恢复应用程序（JavaScript 和 HTML）</a>。</p>
<h5>在 XAML 中处理恢复</h5>
<p>如果您使用 XAML 和 C# 编写 Metro 风格应用程序，则可以对应用程序对象使用 <strong>Resuming</strong> 事件来处理应用程序恢复。</p>
<blockquote>
<div id="codeSnippetWrapper">
<pre class="crayon-plain-tag">public App()
{
    InitializeComponent();
    this.Resuming += new EventHandler&amp;lt;object&amp;gt;(App_Resuming);
}

        async private void App_Resuming(object sender, object e)
        {
            //Update the selected stock with the latest news, stock info, and chart data
            News.RequestNews(stock);

            Data data = await Api.GetStockInfoDataAsync(stock);
            Api.DisplayStockInfo(data);

            Chart chartData = await Api.GetHistoryDataAsync(range);
            CanvasChart.DrawChart(&quot;chartCanvas&quot;, chartData, Chart.GetChartOptions(false));

            // Send client side notifications
    Tile.SendTileUpdate(stock, stockInfo.Change, stockInfo.LastSale, stockInfo.LastSaleTime, stockInfo.Open);
        }</pre>
</div>
</blockquote>
<p>有关如何在 VB/C#/C++ 和 XAML 中处理恢复的详细信息，请参阅开发中心中的<a href="http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh465110.aspx" target="_blank">如何恢复应用程序（VB/C#/C++ 和 XAML）</a>。</p>
<h4>激活</h4>
<p>激活与您应用程序的启动方式息息相关。在 Metro 风格应用程序中它起到多方面的作用。有关如何使用 Metro 风格应用程序激活处理合约的更多详细信息，请参阅我们之前的博文<a href="http://blogs.msdn.com/b/windowsappdev_cn/archive/2012/03/30/windows-8-activating-contracts.aspx" target="_blank">在您的应用程序中激活 Windows 8 合约</a>。本文中我们重点介绍当 Windows 终止您的应用程序，随后用户又重新启动它时，如何使用激活来还原之前保存的数据。</p>
<p>Windows 可能会出于多个原因终止已挂起的应用程序。例如：用户手动关闭应用程序或注销，或者系统的资源不足（诸如游戏之类的应用程序可能需要大量资源！）。如果用户在 Windows 终止应用程序后启动应用程序，它会收到 <strong>activated</strong> 事件，用户会看到应用程序的初始屏幕，直到应用程序被激活。您可以使用此事件确定应用程序是否需要还原上次挂起时保存的数据，或者您是否必须加载应用程序的默认数据。<strong>activated</strong> 事件参数包含一个 <strong>PreviousExecutionState</strong> 属性，该属性会告诉您在激活之前应用程序所处的状态。该属性的值是 <strong>Windows.ApplicationModel.Activation.ApplicationExecutionState</strong> 枚举值之一。</p>
<div align="center">
<table border="0" cellspacing="0" cellpadding="3" align="center">
<tbody>
<tr>
<td valign="top" width="28%"><strong>终止原因</strong></td>
<td valign="top" width="35%"><strong>PreviousExecutionState 值</strong></td>
<td valign="top" width="35%"><strong>要采取的操作</strong></td>
</tr>
<tr>
<td valign="top" width="28%">由系统终止（由于资源限制、关机、重新启动等等）</td>
<td valign="top" width="35%">Terminated</td>
<td valign="top" width="35%">还原会话数据</td>
</tr>
<tr>
<td valign="top" width="28%">由用户关闭</td>
<td valign="top" width="35%">ClosedByUser</td>
<td valign="top" width="35%">使用默认数据启动</td>
</tr>
<tr>
<td valign="top" width="28%">          意外终止，或者应用程序自用户的会话启动后一直未运行</td>
<td valign="top" width="35%">NotRunning</td>
<td valign="top" width="35%">使用默认数据启动</td>
</tr>
</tbody>
</table>
</div>
<p><strong>PreviousExecutionState</strong> 的值还可以是 <strong>Running</strong> 或 <strong>Suspended</strong>，但在这些情况下，您的应用程序之前并未终止，因此您不必考虑是否需要还原数据。</p>
<p>当应用程序已激活并且其 <strong>PreviousExecutionState</strong> 值为 <strong>Terminated</strong> 时，您必须还原已保存的会话数据，以使应用程序完全保持用户上次看到的样子。如果用户手动关闭应用程序、应用程序意外终止或者在当前会话中尚未运行，则您必须忽略之前的会话数据并使用默认视图启动应用程序。</p>
<p>我们的示例股票应用程序使用 <strong>activated</strong> 事件重新显示挂起时所保存的股票和股价图信息。该应用程序还刷新其缓存的网络数据。这样，用户看到的就是他们离开该应用程序时所查看的股票，但股票价格、股价图和新闻文章全都是最新的。</p>
<h5>在 JavaScript 中处理激活</h5>
<p>如果您使用 Windows JavaScript 库 (WinJS) 编写 Metro 风格应用程序，则可以使用 <strong>activated</strong> 事件处理激活。</p>
<p>在 <strong>activated</strong> 事件处理程序代码中，您的应用程序可以检查 <strong>sessionState</strong> 对象，以确定它是应加载保存的数据，还是应显示默认主页视图。<strong>SessionState</strong> 通过检查 <strong>eventArgs.detail.previousExecutionState</strong> 自动确定应用程序上次的状态。如果 <strong>sessionState</strong> 已填充，则使用它还原会话数据，否则使用应用程序的默认数据。</p>
<blockquote>
<div id="codeSnippetWrapper">
<pre class="crayon-plain-tag">var app = WinJS.Application;

function activatedHandler(eventArgs) {
    if (eventArgs.detail.kind == Windows.ApplicationModel.Activation.ActivationKind.launch) {
        // Check whether the session state variables are valid.
        // If so, retrieve the stock and range values saved in the checkpoint handler
        if (app.sessionState) {
            stock = app.sessionState.lastSeenStock;
            range = app.sessionState.lastSeenRange;
        } 
        // If not, use the app's default values
        else{
            stock = &quot;DOW&quot;;
            range = &quot;1M&quot;;           
        }

        // Initialize the WinJS controls asynchronously behind the app splash screen
        // Start retrieving the latest stock data asynchronously after the controls are ready
        eventObject.setPromise(WinJS.UI.processAll().then(function() {
            Api.initializeUserStocks();
        }));
    }
}

app.addEventListener(&quot;activated&quot;, activatedHandler);</pre>
</div>
</blockquote>
<p>有关如何在 JavaScript 中处理激活的详细信息，请参阅开发中心中的<a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh465102.aspx" target="_blank">如何激活应用程序（JavaScript 和 HTML）</a>。</p>
<h5>在 XAML 中处理激活</h5>
<p>在使用 XAML 和 C# 的 Metro 风格应用程序中，您可以替代 <strong>OnLaunched</strong> 事件来处理从磁贴基本激活应用程序。</p>
<p>在 <strong>OnLaunched</strong> 事件处理程序代码中，您的应用程序可以检查事件参数上的 <strong>PreviousExecutionState</strong>。如果它等于 <strong>Terminated</strong>，<strong></strong>则还原您在 <strong>Suspending</strong> 事件中保存的数据。如果是其他值，则使用应用程序的默认数据。</p>
<blockquote>
<div id="codeSnippetWrapper">
<pre class="crayon-plain-tag">async protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
    // Check whether the session data should be restored
            if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
            {
                // Here we've created a SuspensionManager class which handles restoring session
                // data from a file and then gives access to that data through a Dictionary
                await SuspensionManager.RestoreAsync();

// Retrieve the stock and range values saved in the suspend handler 
stock = SuspensionManager.SessionState[&quot;lastSeenStock&quot;];
                range = SuspensionManager.SessionState[&quot;lastSeenRange&quot;];
            }
            // If not, use the app's default values
            else
            {
                stock = &quot;DOW&quot;;
                range = &quot;1M&quot;;
            }

    // Start retrieving the latest stock data
            Api.InitializeUserStocks();

            Window.Current.Activate();
        }</pre>
</div>
</blockquote>
<p>有关如何在 XAML 中处理激活的详细信息，请参阅开发中心中的<a href="http://msdn.microsoft.com/en-us/library/windows/apps/xaml/Hh465093(v=win.10).aspx" target="_blank">如何激活应用程序（VB/C#/C++ 和 XAML）</a>。</p>
<h3>打造出色应用程序生存期体验的提示</h3>
<p>现在您已了解了所有基础知识，下面是一些可帮助您为应用程序打造出色生存期体验以便在用户看来应用程序始终处于活动和最新状态的一些提示。</p>
<h4>有时最好重新开始</h4>
<p>如果自用户上次查看应用程序已过了很长时间，有时最好将应用程序重置为其默认视图。多久才算很久完全由您决定，但如果应用程序的内容看起来陈旧或过时，则建议您将应用程序恢复为其主页视图。这会使应用程序在用户看来更加智能。</p>
<p>例如，如果您要构建一个新闻阅读器应用程序，在用户从该应用程序切出后，它可能会被挂起。过了一段时间后，当用户回到新闻阅读器应用程序时，应用程序将会恢复。在恢复处理程序中，检查当前文章已存在多长时间，以确定它现在是否已过时。如果文章太旧，则显示默认主页视图而不是旧文章。</p>
<h4>在正确的时间保存正确的数据</h4>
<p>在应用程序的整个生命周期中，始终以增量方式保存重要数据。由于应用程序只有最多五秒的时间来运行挂起事件处理程序代码，因此您需要确保在应用程序挂起时，您的重要应用程序数据已保存到持久存储。</p>
<p>在编写应用程序时，您需要管理以下两种类型的数据：<strong>会话数据</strong>和<strong>用户数据</strong>。会话数据是应用程序中与用户的当前体验相关的临时数据。例如，用户正在查看的当前股票、用户正在 eBook 中阅读的当前页面或一个很长的项目列表中的滚动位置。用户数据是持久性的，必须始终可供用户访问，无论它们是什么。例如，用户正在键入的进行中文档、在应用程序中拍摄的照片或用户在游戏中的进度。</p>
<p>确保在应用程序挂起时，它已将这两种数据类型保存到持久存储。</p>
<h4>还原会话数据</h4>
<p>用户希望 Metro 风格应用程序通常保持他们上次使用它时所处的状态。从开发人员的角度看，当您的应用程序从挂起状态恢复或从未运行状态激活时，还原之前保存的会话数据通常是合理的。</p>
<p>例如，如果您的应用程序包括购物车功能，并且用户向购物车中添加商品后从应用程序中切出，那么在用户恢复或重新激活该应用程序时维护购物车中的那些商品应该是有意义的。</p>
<p>再举一个例子，假设某应用程序显示新闻文章。如果用户之前正在查看某特定文章，然后切换到另一应用程序，用户会希望当他们回到您的应用程序中时，他们能够看到之前正在查看的文章。</p>
<h4>释放挂起事件处理程序中的独占资源</h4>
<p>如果应用程序在执行过程中获取了任何独占资源（例如文件句柄或外部设备引用），那么它在收到 <strong>suspending</strong> 事件时则必须释放这些资源。此外，如果您的应用程序需要使用这些独占资源才能继续运行，那么在收到 <strong>resuming</strong> 事件时，则必须回收这些资源。</p>
<h4>不要关闭应用程序！</h4>
<p>Windows 8 中的 Metro 风格应用程序永远不能将其自身关闭或者提供应用程序用户界面让用户关闭您的应用程序。挂起和终止应用程序由 Windows 代表用户进行处理，以维护系统性能和电池寿命。如果用户想要关闭您的应用程序，他们可以通过从屏幕顶部向屏幕底部滑动或者按 Alt＋F4 来实现。</p>
<h3>结束语</h3>
<p>通过使用 <strong>suspending</strong>、<strong>resuming</strong> 和 <strong>activated</strong> 这三个事件，对用户而言，您的应用程序看起来始终处于活动状态。但与此同时，在用户不使用应用程序时，它永远不会不必要地耗尽电池电量或降低系统性能。在设备越来越紧凑、移动性越来越强的世界里，新的 Metro 风格应用程序生命周期使您的应用程序在任何设备上都能大放异彩。</p>
<p>转自：<a href="http://blogs.msdn.com/b/windowsappdev_cn/archive/2012/04/16/managing-app-lifecycle.aspx">http://blogs.msdn.com/b/windowsappdev_cn/archive/2012/04/16/managing-app-lifecycle.aspx</a></p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=764</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows 8 Metro 应用开发入门(二)：Metro App的几个新控件</title>
		<link>https://www.softwareace.cn/?p=762</link>
		<comments>https://www.softwareace.cn/?p=762#comments</comments>
		<pubDate>Wed, 02 Apr 2014 01:51:49 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[开发经验]]></category>
		<category><![CDATA[metro]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=762</guid>
		<description><![CDATA[摘 要 基于Silverlight开发Metro App可以使用Silverlight原生的控件，为了更好的开 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>摘 要</div>
<div>
<p>基于Silverlight开发Metro App可以使用Silverlight原生的控件，为了更好的开发Metro App，控件库又专门增加了几个新的控件，如：GridView、Flipview、ProgressRing、SemanticZoom和VariableSizedWrapGrid等，这些控件为平板设备提供了良好的触控体验，这一章我们来介绍一下这几个控件的简单用法。</p>
</div>
<div>
<div>第1节 GridView</div>
<p>GridView是以网格样式展现一组数据，在Web开发中就已经存在，主要用于多行多列的数据显示中。Metro中以分组形式表达数据使用GridView更得心应手，在Silverlight 5及以前版本中，如果想实现分组数据展现要先写一堆数据模板，而在Metro中，这种展现方式得到了增强，GridView 是专门用于分组数据的，如果仅仅是列表数据，则建议使用ListView。</p>
<p>GridView控件有几个非常重要的常用成员：</p>
<p>（1） 数据源</p>
<p>如果是以分组形式展示数据，则数据源必须是可分组的，也即是有主从关系，通常是主列表项中每一项可能存在着某一子列表。GridView的数据源依托于CollectionViewSource，CollectionViewSource有一个属性IsSourceGrouped指明数据源是否是分组源数据集合，还有一个属性ItemsPath指明查找子数据项的路径，通常将可分组的源数据指定给CollectionViewSource对象的Source属性，如下定义了年级与学生的主从关系，年级包含了学生的数据列表：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">public class Grade
    {
        public Grade()
        {
            Students = new ObservableCollection&amp;lt;Student&amp;gt;();
        }
        public string Name { get; set; }
        public ObservableCollection&amp;lt;Student&amp;gt; Students { get; private set; }
    }

    public class Student
    {
        public string Name { get; set; }
        public DateTime Birthday { get; set; }
        public bool IsClassLeader { get; set; }
        public string Grade { get; set; }
    }</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>以下代码来模拟生成三个年级的学生：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">private List&amp;lt;Grade&amp;gt; CreateGrades()
        {
            List&amp;lt;Grade&amp;gt; Grades = new List&amp;lt;Grade&amp;gt;();
            for (int i = 1; i &amp;lt;= 3; i++)
            {
                Grade grade = new Grade();
                grade.Name = &quot;年级 &quot; + i;
                for (int j = 1; j &amp;lt;= 5; j++)
                {
                    grade.Students.Add(new Student()
                    {
                        Name = &quot;王学生 &quot; + j,
                        IsClassLeader = true,
                        Birthday = startDate.AddDays(j + 1),
                        Grade = grade.Name
                    });
                }
                Grades.Add(grade);
            }
            //MyGrades.Source = Grades;
            return Grades;
        }</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>那么，对于这个方法生成的数据源即是可分组的。对于CollectionViewSource，既可以使用静态资源的形式绑定到视图，也可以以后台代码的形式绑定。</p>
<p>（2）使用GridView展示数据源</p>
<p>a)、项样式</p>
<p>如果要展示个性化的数据视图，需要自定义DataTemplate来规划每组下的每个数据项的布局，如下是对每个学生信息的展示布局：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">&amp;lt;GridView.ItemTemplate&amp;gt;
                &amp;lt;DataTemplate&amp;gt;
                    &amp;lt;StackPanel Margin=&quot;20&quot;&amp;gt;
                        &amp;lt;TextBlock Text=&quot;{Binding Name}&quot; FontWeight=&quot;Bold&quot; Style=&quot;{StaticResource ItemTextStyle}&quot;/&amp;gt;
                        &amp;lt;TextBlock Text=&quot;{Binding Birthday}&quot; TextWrapping=&quot;NoWrap&quot; Style=&quot;{StaticResource BodyTextStyle}&quot; /&amp;gt;
                        &amp;lt;CheckBox Content=&quot;班干部&quot; IsChecked=&quot;{Binding IsClassLeader}&quot; IsEnabled=&quot;False&quot;/&amp;gt;
                    &amp;lt;/StackPanel&amp;gt;
                &amp;lt;/DataTemplate&amp;gt;
            &amp;lt;/GridView.ItemTemplate&amp;gt;</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>b)、组样式</p>
<p>也可以对每个分组的展示布局及样式自定义，通过GroupStyle进行设定，如下是对每个年级分组的样式定义：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">&amp;lt;GridView.GroupStyle&amp;gt;
                &amp;lt;GroupStyle HidesIfEmpty=&quot;False&quot;&amp;gt;
                    &amp;lt;GroupStyle.HeaderTemplate&amp;gt;
                        &amp;lt;DataTemplate&amp;gt;
                            &amp;lt;Grid Background=&quot;Yellow&quot; Margin=&quot;0&quot;&amp;gt;
                                &amp;lt;TextBlock Text=&quot;{Binding Name}&quot; Foreground=&quot;Black&quot; Margin=&quot;30&quot; Style=&quot;{StaticResource HeaderTextStyle}&quot;/&amp;gt;
                            &amp;lt;/Grid&amp;gt;
                        &amp;lt;/DataTemplate&amp;gt;
                    &amp;lt;/GroupStyle.HeaderTemplate&amp;gt;
                    &amp;lt;GroupStyle.ContainerStyle&amp;gt;
                        &amp;lt;Style TargetType=&quot;GroupItem&quot;&amp;gt;
                            &amp;lt;Setter Property=&quot;MinWidth&quot; Value=&quot;300&quot;/&amp;gt;
                            &amp;lt;Setter Property=&quot;BorderBrush&quot; Value=&quot;Blue&quot;/&amp;gt;
                            &amp;lt;Setter Property=&quot;BorderThickness&quot; Value=&quot;2&quot;/&amp;gt;
                            &amp;lt;Setter Property=&quot;Margin&quot; Value=&quot;3,0&quot;/&amp;gt;
                            &amp;lt;Setter Property=&quot;Background&quot; Value=&quot;Silver&quot;/&amp;gt;
                        &amp;lt;/Style&amp;gt;
                    &amp;lt;/GroupStyle.ContainerStyle&amp;gt;
                &amp;lt;/GroupStyle&amp;gt;
            &amp;lt;/GridView.GroupStyle&amp;gt;</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>HidesIfEmpty属性指定当子项为空时是否隐藏组。</p>
<p>HeaderTemplate 定义组头样式。</p>
<p>效果图：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091521535987.png" /></p>
<p>c)、选定项事件</p>
<p>当选定项改变时触发事件SelectionChanged，与Listview、DropDownlist等控件的效果差不多，在事件处理程序中可以做相应处理，如下：</p>
<div>
<pre class="crayon-plain-tag">private void GridView_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
        {
            Student student = ((GridView)sender).SelectedItem as Student;
            Debug.WriteLine(student.Name);
        }</pre>
</div>
<p>以下是完整的示例代码：</p>
<p>XAML：</p>
<div><img id="code_img_closed_f961a8c2-cdc3-4ea3-afc6-aada8103683e" alt="" src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" />View Code</div>
<p>C# 绑定数据：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">private List&amp;lt;Grade&amp;gt; CreateGrades()
        {
            List&amp;lt;Grade&amp;gt; Grades = new List&amp;lt;Grade&amp;gt;();
            for (int i = 1; i &amp;lt;= 3; i++)
            {
                Grade grade = new Grade();
                grade.Name = &quot;年级 &quot; + i;
                for (int j = 1; j &amp;lt;= 5; j++)
                {
                    grade.Students.Add(new Student()
                    {
                        Name = &quot;王学生 &quot; + j,
                        IsClassLeader = true,
                        Birthday = startDate.AddDays(j + 1),
                        Grade = grade.Name
                    });
                }
                Grades.Add(grade);
            }
            MyGrades.Source = Grades;
            return Grades;
        }</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>在基于横向排列分组时建议使用GridView，在基于纵向排列分组时建议使用ListView，关于ListView的使用请参考相关文档，这里不再介绍。下面给一个ListView的分组效果图：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091521573542.png" /></p>
<p>&nbsp;</p>
<div>第2节 Flipview</div>
<p>Flipview允许基于“上一页”“下一页”的方式浏览一系列视图，视图可以是图片，也可以是其他的自定义布局。现在很多网站上都有对图片的类似浏览方式，如网易的图片新闻，上一页的导航在整个视图的左侧，下一页的导航在右侧，这种导航非常适合在触摸设备中使用。如下：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091521582368.png" /></p>
<p>Flipview控件来源于ItemsControl，它的使用比较简单，类似于一个容器，只需要往里塞视图即可，至于如何处理上下页的翻转，内部都已经完全实现好了，不仅可以往里面旋转图片，还可以放置其他的视图。如下：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">&amp;lt;FlipView HorizontalAlignment=&quot;Left&quot; SelectionChanged=&quot;FlipView_SelectionChanged_1&quot;  Margin=&quot;12&quot;
 VerticalAlignment=&quot;Top&quot; Grid.Row=&quot;1&quot; Width=&quot;500&quot;&amp;gt;
            &amp;lt;Image Source=&quot;Assets/bg0.jpg&quot; /&amp;gt;
            &amp;lt;Image Source=&quot;Assets/bg1.jpg&quot; /&amp;gt;
            &amp;lt;Image Source=&quot;Assets/bg2.jpg&quot; /&amp;gt;
            &amp;lt;Image Source=&quot;Assets/bg3.jpg&quot; /&amp;gt;
            &amp;lt;Image Source=&quot;Assets/bg4.jpg&quot; /&amp;gt;
            &amp;lt;Grid&amp;gt;
                &amp;lt;TextBlock Text=&quot;12312313&quot; FontSize=&quot;30&quot;/&amp;gt;
            &amp;lt;/Grid&amp;gt;
        &amp;lt;/FlipView&amp;gt;</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>Image可以与Grid共存。Flipview同样有SelectionChanged事件，在事件处理程序中可以获取导航到当前的视图项。</p>
<p>&nbsp;</p>
<div>第3节 ProgressRing</div>
<p>在Windows 8 中有一个新的进度条，就是几个点围绕一个圆旋转（当用户登录到Windows8系统时可以看到）。Metro应用程序也提供了这一效果的控件。如下：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091522010839.png" /></p>
<p>它的使用非常的简单：</p>
<div>
<pre class="crayon-plain-tag">&amp;lt;ProgressRing x:Name=&quot;pr&quot; Grid.Row=&quot;1&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;500,231,0,0&quot; 
VerticalAlignment=&quot;Top&quot; Height=&quot;108&quot; Width=&quot;108&quot; IsActive=&quot;True&quot;/&amp;gt;</pre>
</div>
<p>它有一个很重要的属性IsActive来控制它的活动与休眠。</p>
<p>&nbsp;</p>
<div>第4节 SemanticZoom</div>
<p>SemanticZoom控件提供了同一个数据源两种视图的展现形式，这是一个很有意思的控件，也可以说一个是近景视图ZoomedInView一个是远景视图ZoomedOutView，我们暂且称它人近景、远景吧。在近景视图中可以浏览每个项的详细信息，远景视图类似预览图，一般是浏览项的简略数据，如下分别是视图ZoomedInView和视图ZoomedOutView：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091522025611.png" /></p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091522032546.png" /></p>
<p>注意看视图ZoomedInView的右下角有个红圈围起来的一个“一”字按钮，点它可以切换到远景视图，当点击远景视图中的一个项时又切换回近景视图。这通常在快速预览数据列表时很有用，可以向用户隐藏一些不必要的数据。</p>
<p>SemanticZoom有两个非常重要的属性ZoomedInView和ZoomedOutView，当向这两个视图提供布局时该控件才可进行近远景视图的切换。如下：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">&amp;lt;SemanticZoom HorizontalAlignment=&quot;Left&quot; Margin=&quot;10&quot; Grid.Row=&quot;1&quot; VerticalAlignment=&quot;Top&quot;&amp;gt;
            &amp;lt;SemanticZoom.ZoomedInView&amp;gt;
                &amp;lt;GridView x:Name=&quot;gv1&quot; ScrollViewer.IsHorizontalScrollChainingEnabled=&quot;False&quot; ScrollViewer.IsVerticalScrollChainingEnabled=&quot;False&quot;&amp;gt;
                    &amp;lt;GridView.ItemTemplate&amp;gt;
                        &amp;lt;DataTemplate&amp;gt;
                            &amp;lt;StackPanel Margin=&quot;20&quot;&amp;gt;
                                &amp;lt;TextBlock Text=&quot;{Binding Name}&quot; FontWeight=&quot;Bold&quot; Style=&quot;{StaticResource ItemTextStyle}&quot;/&amp;gt;
                                &amp;lt;TextBlock Text=&quot;{Binding DueDate}&quot; TextWrapping=&quot;NoWrap&quot; Style=&quot;{StaticResource BodyTextStyle}&quot; /&amp;gt;
                                &amp;lt;CheckBox Content=&quot;Complete&quot; IsChecked=&quot;{Binding Complete}&quot; IsEnabled=&quot;False&quot;/&amp;gt;
                            &amp;lt;/StackPanel&amp;gt;
                        &amp;lt;/DataTemplate&amp;gt;
                    &amp;lt;/GridView.ItemTemplate&amp;gt;
                &amp;lt;/GridView&amp;gt;
            &amp;lt;/SemanticZoom.ZoomedInView&amp;gt;
            &amp;lt;SemanticZoom.ZoomedOutView&amp;gt;
                &amp;lt;GridView x:Name=&quot;gv2&quot; ScrollViewer.IsHorizontalScrollChainingEnabled=&quot;False&quot; ScrollViewer.IsVerticalScrollChainingEnabled=&quot;False&quot;&amp;gt;
                    &amp;lt;GridView.ItemTemplate&amp;gt;
                        &amp;lt;DataTemplate&amp;gt;
                            &amp;lt;StackPanel Margin=&quot;20&quot;&amp;gt;
                                &amp;lt;TextBlock Text=&quot;{Binding Name}&quot; Width=&quot;100&quot; FontWeight=&quot;Bold&quot; Foreground=&quot;Red&quot; Style=&quot;{StaticResource ItemTextStyle}&quot; FontSize=&quot;26&quot;/&amp;gt;
                            &amp;lt;/StackPanel&amp;gt;
                        &amp;lt;/DataTemplate&amp;gt;
                    &amp;lt;/GridView.ItemTemplate&amp;gt;
                &amp;lt;/GridView&amp;gt;
            &amp;lt;/SemanticZoom.ZoomedOutView&amp;gt;
        &amp;lt;/SemanticZoom&amp;gt;</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>bool CanChangeViews 指明是否可以进行视图切换</p>
<p>bool IsZoomedInViewActive 指明近景视图ZoomedInView是否为活动视图</p>
<p>在视图切换时会触发两个事件：ViewChangeStarted和ViewChangeCompleted。</p>
<p>代码：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">public class SemanticItem
        {
            public string Name { get; set; }
            public DateTime DueDate { get; set; }
            public bool Complete { get; set; }
        }
        private void InitDataSource()
        {
            List&amp;lt;SemanticItem&amp;gt; ds = new List&amp;lt;SemanticItem&amp;gt;();
            for (int i = 0; i &amp;lt; 20; i++)
            {
                ds.Add(new SemanticItem() { Name = &quot;S &quot; + i, DueDate = DateTime.Now, Complete = true });
            }
            this.gv1.ItemsSource = this.gv2.ItemsSource = ds;
        }</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>如果你想向用户提供两个非常修改化的视图，当然可以发挥你的丰富想象力来实现布局。</p>
<p>&nbsp;</p>
<div>第5节 VariableSizedWrapGrid</div>
<p>在Silverlight/WPF有一个扩展控件WrapPanel，它是根据自身的宽高和子元素的宽高对子元素进行“换行”排列，当指定子元素横排列优先时，如果横向布局不足容纳全部子元素，则会自动从下一行开始排列，纵向排列优先时类似。Metro应用提供了一个类似的控件VariableSizedWrapGrid，它比WrapPanel有更多的控制，比如，它可以指定子元素的宽和高，还可以指定当前用于布局子元素的行和列数，并且它还能指定某个子元素占用几行或几列，非常强大！如下图：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091522060550.png" /></p>
<p>XAML：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">&amp;lt;VariableSizedWrapGrid Grid.Row=&quot;1&quot; MaximumRowsOrColumns=&quot;5&quot; ItemHeight=&quot;44&quot; ItemWidth=&quot;44&quot; HorizontalAlignment=&quot;Left&quot;
 Height=&quot;262&quot; Margin=&quot;10,10,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;396&quot;&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Blue&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;White&quot; Height=&quot;80&quot; VariableSizedWrapGrid.RowSpan=&quot;2&quot;/&amp;gt;
            &amp;lt;Rectangle Fill=&quot;Green&quot; Width=&quot;80&quot; VariableSizedWrapGrid.ColumnSpan=&quot;2&quot;/&amp;gt;

        &amp;lt;/VariableSizedWrapGrid&amp;gt;</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>VariableSizedWrapGrid有几个非常重要的属性：</p>
<p>double ItemHeight 设置每个子项的高</p>
<p>double ItemWidth 设置每个子项的宽</p>
<p>Orientation Orientation 子元素的排列方向</p>
<p>int MaximumRowsOrColumns获取或设置影响换行点同时说明 Orientation 的值。</p>
<p>DependencyProperty RowSpanProperty 子元素占据的行数，如上图中的白色块。</p>
<p>DependencyProperty ColumnSpanProperty 子元素占据的列数，如上图中的绿色块。</p>
<p>http://www.cnblogs.com/solan/archive/2012/09/17/Win8Metro02.html</p>
</div>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=762</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows 8 Metro 应用开发入门(一)：开发环境介绍</title>
		<link>https://www.softwareace.cn/?p=761</link>
		<comments>https://www.softwareace.cn/?p=761#comments</comments>
		<pubDate>Wed, 02 Apr 2014 01:50:19 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[开发经验]]></category>
		<category><![CDATA[metro]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=761</guid>
		<description><![CDATA[摘 要 Windows8已经发布，随之而来的基于WinRT的Metro应用也正向我们走来，正像它所宣传的：光滑 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>摘 要</div>
<div>
<p>Windows8已经发布，随之而来的基于WinRT的Metro应用也正向我们走来，正像它所宣传的：光滑、快、现代。看习惯了玻璃、立体风格的应用，或许Metro的简洁能给你留下不一样的体验。Visual Studio 2012为Metro应用提供了强有力的开发支持。磨刀不误砍柴工！这一章我们先来介绍一下开发环境的搭建及可能遇到的问题，最后再来一个简单的应用体验一下Metro的开发。</p>
</div>
<div>
<div>第1节 搭建开发环境</div>
<p>Windows8不但支持传统的桌面应用，并且推出一个专为触摸而设计的最新Metro风格应用，对于Metro应用必须要求在Visual Studio 2012下开发，随之一起发布的是.NET Framework 4.5。所以，为了开发及调试方便，我们推荐的开发环境是：Windows8 + Visual Studio 2012。</p>
<p>Metro支持三种开发模式：</p>
<p>如果你有Web前台开发功底，你可以选择HTML5+CSS3+JavaScript进行开发；</p>
<p>如果你熟悉Silverlight或WPF开发，可以选择XAML+C#/VB.NET/C++进行开发；</p>
<p>如果你比较关注渲染性能，当然可以选择C++和DirectX进行开发。</p>
<p>本入门系列会以XAML+C#为基于进行演示，当然在后文中也可能会进行其他另两个开发模型的演示。在安装Visual Studio 2012过程中，可以选择安装相应版本的Blend For Visual Studio为XAML提供可视化设计，不过我个人的习惯是在VS中手写XAML，毕竟VS中也提供了对XAML的智能感知，在调色或动画部分会借助Blend进行辅助工作。</p>
<p>我的测试开发环境是部署在虚拟机中，如果你还没有安装Windows8和Visual Studio 2012，可以去微软网站上下载相应的预览及试用版。至于安装，这里就不再演示了，提醒一下，在安装Windows8时，一定要创建一个新用户，另外还要提前注册一个Windows Live ID，现在已被更名为Microsoft 帐户。正确安装，启动后，可以看到如下两个分别是VS2012和Blend的界面，怎么样？有没有Metro的感觉？</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214372859.png" /></p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214381920.png" /></p>
<p>&nbsp;</p>
<div>第2节 创建项目</div>
<p>在新建项目中是以Windows应用商店表示Metro应用，选择Windows应用商店项目类型，默认是.NET Framework 4.5版本。</p>
<p>在首次创建Windows应用商店项目时候，VS会要求你先获取Windows8应用开发许可证，现在这个许可证可用期限是一个月，以后不知道会不会收费。</p>
<p>选择某一项目类型后，点击“确定”按钮，在创建过程中，会弹出如下询问：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214401213.png" /></p>
<p>很明显，义无反顾地选择“我同意”，接着是连接许可证服务器，然后是要求输入可用的Microsoft账户信息：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214410549.png" /></p>
<p>输入完了之后，点击“登录”，如果账户可用，正常情况下会提示获取许可证成功，如下：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214414461.png" /></p>
<p>我是2012年9月12日获取的，许可证到期日期是2012年10月12日。到此一系列的身份认证表示你已经得到创建Windows8 Metro应用的许可，点击“关闭”按钮，接着才是真正的创建项目。以后再创建Windows商店项目就不会再弹出这些获取许可证消息的窗口了，当然要看微软对许可证策略。如果你是以Administrator登录，还有麻烦，在VS中打开xaml文件设计器时可能会收到如下设计器异常：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214421959.png" /></p>
<p>明确指出了不能用内置管理员激活此应用，如果你是很固执地尝试调试程序，可能会收到以下异常：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214424885.png" /></p>
<p>所以，同志，请切换到其他系统账户吧，这就是在上一节中提到的，在安装Windows8时一定要创建一个新用户，以这个新用户登录Windows然后是进行Metro应用开发。</p>
<p>&nbsp;</p>
<div>第3节 项目类型</div>
<p>在Windows8商店项目类型中有几个模板，如下：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214445555.png" /></p>
<p>创建任何一个模板的应用，都会默认创建几个必要的文件夹及目录，如下图是创建空白应用程序模板的项目：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214453993.png" /></p>
<p>Assets 文件夹，放置图片等资源文件，默认里面有四个与Windows商店应用程序相关的必须的图片，也可以将自己的资源文件放进去。</p>
<p>Common 文件夹，默认里面有一个样式文件StandardStyles.xaml，是Windows商店应用程序的基础样式，强烈建议不要修改它，因为它与一些控件有关联，如果有自己的样式，可以在这里新建一个自己的样式，然后在App.xaml 里做引用即可。</p>
<p>App.xaml/App.xaml.cs 熟悉Silverlight开发的都知道这个是应用程序的初始入点。App.xaml里仅仅有一个对标准样式的引用：</p>
<div>
<pre class="crayon-plain-tag">&amp;lt;ResourceDictionary Source=&quot;Common/StandardStyles.xaml&quot;/&amp;gt;</pre>
</div>
<p>App类与Silverlight里的App类相似，这里有一个重要的方法：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            Frame rootFrame = Window.Current.Content as Frame;
            if (rootFrame == null)
            {
                rootFrame = new Frame();
                if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: 从之前挂起的应用程序加载状态
                }
                Window.Current.Content = rootFrame;
            }
            if (rootFrame.Content == null)
            {
                if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
                {
                    throw new Exception(&quot;Failed to create initial page&quot;);
                }
            }
            Window.Current.Activate();
        }</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>应用程序启动时会进入这个方法，然后导航到第一个主页面，Frame的Navigate方法很有意思，它只是接收一个目标页的类型，在其内部创建目标页的实例进而加载可视。这里还会涉及到程序挂起、恢复等，建议参考应用程序生命周期的相关资料。</p>
<p>AppXXX_TemporaryKey.pfx 应用程序签名证书</p>
<p>Package.appxmanifest 应用程序配置相关，比如Logo、应用程序名等，如果你的程序将来要提交到Windows商店，可得好好配置一下这里面的东西，在VS中可以双击打开它进行可视化编辑，也可以用记事本打开它进行编辑，其实它就是一个XML文档。</p>
<p>以上是项目的基础配置，对于Windows商店项目有几个模板可供选择。</p>
<p>（1） 空白应用程序（XAML） 创建没有预定义的控件或布局的Windows应用商店应用程序的单页项目，该模板会创建一个空的主页面MainPage.xaml，如下：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">&amp;lt;Page
    x:Class=&quot;App1.MainPage&quot;
    xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
    xmlns:local=&quot;using:App1&quot;
    xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
    xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
    mc:Ignorable=&quot;d&quot;&amp;gt;

    &amp;lt;Grid Background=&quot;{StaticResource ApplicationPageBackgroundThemeBrush}&quot;&amp;gt;

    &amp;lt;/Grid&amp;gt;
&amp;lt;/Page&amp;gt;</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>是一个空的页面，可以在其Grid里放置总局及控件。这一模板是最基础的模板，我们可以根据需要自定义各种各样的页面。</p>
<p>（2） 网络应用程序（XAML）创建在以网格形式排列的分组项之间导航的Windows商店应用程序的三页项目，专用页将显示组合项的详细信息。如下图分别对应：GroupedItemsPage，GroupDetailPage和ItemDetailPage页，这些页都已经有相应的总局元素。</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214484213.png" /></p>
<p>基于组、项、详细的导航可以加快我们的开发速度，当然如果这些页达不到我们项目的要求，也可以自定义其他页面布局。此模板的项目会在Common文件夹下创建几个支持导航和消息通知等类，并且在DataModel文件夹下创建一个示例数据源SampleDataSource。</p>
<p>（3） 拆分布局应用程序（XAML）在已分组的项之间导航的Windows商店应用程序的两页项目，如下图分别表示组页ItemsPage，和项及选择列表项页SplitPage：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214495943.png" /></p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214504361.png" /></p>
<p>如果你的应用程序有类似主-从（包含列表项）展现应用，这个模板非常适合。</p>
<p>（4） 类库项目（Windows应用商店应用程序）这个基于Metro应用的托管项目，这个项目大家都很熟悉了，里面通常就是放一些Class。</p>
<p>（5） 还有两个Windows运行时组件和单元测试项目模板就不再介绍了，有需要可以参考相关资料。</p>
<p>在每个项目中可以添加对应的项：空白页BlankPage、基本页BasicPage、拆分页SplitPage、项页ItemsPage、项详细信息页ItemDetailPage、分组项页GroupedItemPage、组详细信息页GroupDetailPage、资源字典Dictionary、模板化控制CustomControl、用户控件MyUserControl、文件打开选取器协定FileOpenPickerPage、搜索协定SearchResultsPage、共享目标协定ShareTargetPage。</p>
<p>&nbsp;</p>
<div>第4节 示例项目及调试</div>
<p>接下来我们创建一个经典的HelloWorld项目。首先我们创建一个空的HelloWorld项目，如下：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214524972.png" /></p>
<p>编辑主页面MainPage，放置一个TextBox和一个Button，当我们点击按钮时，弹出对话框，来显示用户输入和其他字符。编辑完成的MainPage页如下：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<p></p><pre class="crayon-plain-tag">&amp;lt;Page
    x:Class=&quot;HelloWorld.MainPage&quot;
    xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
    xmlns:local=&quot;using:HelloWorld&quot;
    xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
    xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
    mc:Ignorable=&quot;d&quot;&amp;gt;
    &amp;lt;Grid Background=&quot;{StaticResource ApplicationPageBackgroundThemeBrush}&quot;&amp;gt;
        &amp;lt;StackPanel Orientation=&quot;Horizontal&quot; Height=&quot;100&quot; HorizontalAlignment=&quot;Center&quot; Margin=&quot;0,120,0,0&quot; VerticalAlignment=&quot;Top&quot;&amp;gt;
            &amp;lt;TextBox x:Name=&quot;tbInput&quot; TextWrapping=&quot;Wrap&quot; Text=&quot;&quot; Width=&quot;380&quot; Height=&quot;60&quot; FontSize=&quot;26&quot; /&amp;gt;
            &amp;lt;Button x:Name=&quot;btnOK&quot; Content=&quot;确定&quot; Width=&quot;100&quot; Height=&quot;64&quot; Click=&quot;btnOK_Click_1&quot; FontSize=&quot;22&quot;/&amp;gt;
        &amp;lt;/StackPanel&amp;gt;
    &amp;lt;/Grid&amp;gt;
&amp;lt;/Page&amp;gt;</pre><p></p>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>确定按钮事件如下：</p>
<div>
<pre class="crayon-plain-tag">private void btnOK_Click_1(object sender, RoutedEventArgs e)
        {
            string msg = string.Format(&quot;You say: {0}.&quot;, this.tbInput.Text);
            MessageDialog dialg = new MessageDialog(msg, &quot;Hello world&quot;);
            dialg.ShowAsync();
        }</pre>
</div>
<p>调试Metro项目有三种方式：模拟器、本发计算机和远程计算机。对于模拟器运行效果如下：</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2012/48455/2012091214543914.png" /></p>
<p>模拟器模式下是一个单独的窗体，所以对于调试比较方便，但是对于本地计算机模式下调试，由于是全屏幕且在Metro风格下运行，所以调试比较不方便，通常当运行起来后，有三种方式可以切换：</p>
<p>（1） 可以使用快捷键Alt+F4退出当前程序；</p>
<p>（2） 将鼠标移动屏幕左上角位置，然后在左上角会出现其他程序界面的缩略图，点击即可切换；</p>
<p>（3） Alt+Tab进行切换。</p>
<p>如果在代码窗口中有断点，在程序运行到断点位置会自动切换到VS代码窗口的断点命中位置。</p>
<p>http://www.cnblogs.com/solan/archive/2012/09/12/Win8Metro01.html</p>
</div>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=761</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
