此教程指导你如何结合使用可扩展应用程序标记语言 (XAML) 和 Microsoft Visual Basic 或 C# 创建简单的“Hello, world”Metro 风格应用。此为系列中的第一个教程,指导你构建所需任何类型的 Metro 风格应用所需了解的事项。
在本教程中,你将了解如何:
- 创建新项目
- 向开始页面中添加 XAML 内容
- 处理触控、笔以及鼠标输入
- 在浅色主题和深色主题之间切换
- 创建自己的自定义样式
我们说明如何使用 XAML 和 Visual Basic 或 C# 创建 Metro 风格应用。
- 有关这些教程的 JavaScript、HTML 以及 CSS 版本,请参阅使用 JavaScript 创建你的第一个 Metro 风格应用。
- 有关 C++ 和 XAML 教程,请参阅使用 C++ 创建你的第一个 Metro 风格应用。
- 有关 DirectX 和 C++ 教程,请参阅使用 DirectX 创建你的第一个 Metro 风格应用。
开始之前...
- 若要完成本教程,你需要具备 Windows 8 Release Preview 和 Microsoft Visual Studio Express 2012 RC for Windows 8。若要下载以上内容,请参阅获取工具。
- 你还需要具备开发者许可证。有关说明,请参阅获取开发者许可证。
步骤 1:在 Microsoft Visual Studio 中创建新项目
- 启动 Visual Studio Express 2012 RC for Windows 8。
会出现 Visual Studio Express 2012 RC for Windows 8 开始屏幕。
(继续操作,我们将参考 Visual Studio Express 2012 RC for Windows 8,正如 "Visual Studio" 一样。)
- 选择“文件”>“新建项目”。
会出现“新建项目”对话框。可以在对话框的左侧窗格中选择要显示模板的类型。
-
在左侧窗格中,展开“已安装”,然后展开 Visual Basic 或 Visual C# 并选择“Windows Metro 风格”模板类型。对话框的中心窗格显示用于 Metro 风格应用的项目模板列表。
在本教程中,我们使用“空白应用”模板。“空白应用”模板创建一个最基本的 Metro 风格应用,该应用可以编译和运行,但不包含任何用户界面控件或数据。你使用这些教程课程向应用中添加控件和数据。
- 在中心窗格中,选择“空白应用”模板。
- 在“名称”文本框中,输入 "HelloWorld"。
- 单击“确定”可创建项目。
Visual Studio 创建项目并在“解决方案资源管理器”中显示该项目。
尽管“空白应用”为最基本的模板,但该模板仍包含很多文件:
- 清单文件 (package.appxmanifest) 介绍应用(它的名称、介绍、磁贴、开始页面等等)并列出应用包含的文件。
- 要在开始屏幕中显示的一组大的和小的徽标图像(logo.png 和 smalllogo.png)。
- 表示应用位于 Windows 应用商店的图像 (storelogo.png)。
- 显示应用启动时间的初始屏幕 (splashscreen.png)。
- 应用的 XAML 和代码文件(App.xaml 和 App.xaml.cs/.vb)。
- 开始页面 (MainPage.xaml) 和附带的代码文件 (MainPage.xaml.cs/.vb),这些文件在应用启动时运行。
这些文件是使用 Visual Basic 或 C# 的所有 Metro 风格应用必不可少的文件。在 Visual Studio 中创建的所有项目都包含这些文件。
替换 MainPage
“空白应用”项目模板中的 MainPage 基于“空白页”模板。该模板包含实例化 Page 的最少数量的 XAML 和代码。Visual Studio 中的其他项目和 Page 模板包含一些其他代码和帮助程序类,这些内容有助于开始创建 Metro 风格应用。使用“空白应用”项目模板时,可以使用其他 Page模板之一替换空白 MainPage来利用它们提供的布局和帮助程序类。在本示例中,使用“基本页”替换默认的 MainPage。此系列的后面教程取决于“基本页”模板使用的帮助程序类。
在空白应用中替换 MainPage
- 在“解决方案资源管理器”中,右键单击 MainPage.xaml,然后选择“删除”。
- 单击“确定”确认删除操作。
- 选择“项目”>“添加新项”。将打开“添加新项目”对话框。该对话框的外观类似于“新建项目”对话框。
- 在“已安装”窗格中,展开 Visual C# 或 Visual Basic。
- 选择“Windows Metro 风格”模板类型。
- 在中心窗格中,选择要添加到项目中的页面类型。对于本示例,请选择“基本页”。
- 为该页面输入一个名称。对于本示例,请输入 "MainPage"。
- 单击“添加”。你的页面的 XAML 和代码隐藏文件即被添加到项目中。
- 首次向“空白应用”模板添加新页面(“空白页”除外)时,Visual Studio 会显示含有消息的对话框,告知你添加操作取决于项目缺失的文件。单击“是”可添加这些文件。将用于多种实用工具类的文件添加到 Common 文件夹中的项目中。
- 按 F7 可构建应用。新页会显示设计器中的错误,直至你构建该设计器依赖的帮助程序类。
步骤 2:启动应用
此时,我们创建了非常简单的应用。如果你想看它的外观,按 F5 可在调试模式下构建、部署并启动应用。首先会出现默认的初始屏幕,然后会出现应用。它包含黑屏和标题“我的应用程序”""。
没有关闭应用的按钮或命令。你可以使用关闭手势或 Alt+F4 来关闭应用,但通常不会关闭 Metro 风格应用,正如我们在部分 2:应用生命周期和状态中讨论的详细信息。按 Windows 键可转到“开始”屏幕;请注意,部署应用会将应用的磁贴添加到“开始”屏幕的最后一组。若要再次运行应用,请在开始屏幕上点击或单击应用的磁贴,或在 Visual Studio 中按 F5 在调试模式下运行该应用。
该过程不会执行很多操作——,只是祝贺你已构建第一个 Metro 风格应用!
若要停止调试应用,请按 Alt+Tab 来返回到 Visual Studio。在 Visual Studio 中,单击“调试”>“停止调试”可关闭应用。当你在调试过程中时,无法在 Visual Studio 中编辑。
有关详细信息,请参阅从 Visual Studio 运行 Metro 风格应用。
步骤 3:修改你的开始页面
文件中包含哪些内容?
创建使用“空白应用”模板的新项目时,Visual Studio 会创建含有少数文件的应用。若要查看和编辑文件,请双击“解决方案资源管理器”中的文件。可以像展开文件夹一样展开 XAML 文件来查看其关联的代码文件。默认情况下,XAML 文件在拆分视图中打开,该视图显示设计界面和 XAML 编辑器。
在本教程中,我们只使用少量以前列出的文件:App.xaml、App.xaml.cs/.vb、MainPage.xaml 以及 MainPage.xaml.cs/.vb。
App.xaml 为声明在应用中所使用资源的位置。此文件包含 ResourceDictionary,它含有对位于 Common 文件夹中的 StandardStyles.xaml ResourceDictionary 的引用。StandardStyles.xaml 提供了一组默认样式,它们为应用提供 Windows 8 外观和感觉。
<Application x:Class="HelloWorld.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HelloWorld"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <!-- Styles that define common aspects of the platform look and feel Required by Visual Studio project and item templates --> <ResourceDictionary Source="Common/StandardStyles.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
App.xaml.cs/.vb 为 App.xaml 的代码隐藏文件。代码隐藏为与 XAML 页的部分类结合的代码。同时,XAML 和代码隐藏成为完整的类。App.xaml.cs/.vb 为应用的入口点。与所有代码隐藏页面一样,它包含一个调用 InitializeComponent
方法的构造函数。你未编写InitializeComponent
方法。它由 Visual Studio 生成,且其主要作用为初始化在 XAML 文件中声明的元素。App.xaml.cs/.vb 还包含处理应用激活和挂起的方法。在部分 2:应用生命周期和状态中,向这些方法添加一些代码。
using System; using Windows.ApplicationModel; using Windows.ApplicationModel.Activation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; // The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227 namespace HelloWorld { /// <summary> /// Provides application-specific behavior to supplement the default Application class. /// </summary> sealed partial class App : Application { /// <summary> /// Initializes the singleton application object. This is the first line of authored code /// executed, and as such is the logical equivalent of main() or WinMain(). /// </summary> public App() { this.InitializeComponent(); this.Suspending += OnSuspending; } /// <summary> /// Invoked when the application is launched normally by the end user. Other entry points /// will be used when the application is launched to open a specific file, to display /// search results, and so forth. /// </summary> /// <param name="args">Details about the launch request and process.</param> protected override void OnLaunched(LaunchActivatedEventArgs args) { // Do not repeat app initialization when already running, just ensure that // the window is active if (args.PreviousExecutionState == ApplicationExecutionState.Running) { Window.Current.Activate(); return; } if (args.PreviousExecutionState == ApplicationExecutionState.Terminated) { //TODO: Load state from previously suspended application } // Create a Frame to act navigation context and navigate to the first page var rootFrame = new Frame(); if (!rootFrame.Navigate(typeof(MainPage))) { throw new Exception("Failed to create initial page"); } // Place the frame in the current Window and ensure that it is active Window.Current.Content = rootFrame; Window.Current.Activate(); } /// <summary> /// Invoked when application execution is being suspended. Application state is saved /// without knowing whether the application will be terminated or resumed with the contents /// of memory still intact. /// </summary> /// <param name="sender">The source of the suspend request.</param> /// <param name="e">Details about the suspend request.</param> private void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); //TODO: Save application state and stop any background activity deferral.Complete(); } } }
在 MainPage.xaml 文件中,为应用定义 UI。你可以直接使用 XAML 标记添加元素,也可以使用 Visual Studio 提供的设计工具。“基本页”模板使用 LayoutAwarePage
。此类扩展了基本的 Page 类并提供导航方法、状态管理以及视图管理。“基本页”还包含一些简单的内容,如后退按钮和页面标题。
<common:LayoutAwarePage x:Name="pageRoot" x:Class="HelloWorld.MainPage" DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}" IsTabStop="false" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HelloWorld" xmlns:common="using:HelloWorld.Common" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <!-- TODO: Delete this line if the key AppName is declared in App.xaml --> <x:String x:Key="AppName">My Application</x:String> </Page.Resources> <!-- This grid acts as a root panel for the page that defines two rows: * Row 0 contains the back button and page title * Row 1 contains the rest of the page layout --> <Grid Style="{StaticResource LayoutRootStyle}"> <Grid.RowDefinitions> <RowDefinition Height="140"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!-- Back button and page title --> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/> <TextBlock x:Name="pageTitle" Grid.Column="1" Text="{StaticResource AppName}" Style="{StaticResource PageHeaderTextStyle}"/> </Grid> <VisualStateManager.VisualStateGroups> <!-- Visual states reflect the application's view state --> <VisualStateGroup x:Name="ApplicationViewStates"> <VisualState x:Name="FullScreenLandscape"/> <VisualState x:Name="Filled"/> <!-- The entire page respects the narrower 100-pixel margin convention for portrait --> <VisualState x:Name="FullScreenPortrait"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <!-- The back button and title have different styles when snapped --> <VisualState x:Name="Snapped"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedBackButtonStyle}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </Grid> </common:LayoutAwarePage>
MainPage.xaml.cs/.vb 为 MainPage.xaml 的代码隐藏页面。在此,你添加应用逻辑和事件处理程序。“基本页”模板包含 2 个方法,你可以保存和加载页面状态至其中。
using System; using System.Collections.Generic; using Windows.UI.Xaml.Controls; // The Basic Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234237 namespace HelloWorld { /// <summary> /// A basic page that provides characteristics common to most applications. /// </summary> public sealed partial class MainPage : HelloWorld.Common.LayoutAwarePage { public MainPage() { this.InitializeComponent(); } /// <summary> /// Populates the page with content passed during navigation. Any saved state is also /// provided when recreating a page from a prior session. /// </summary> /// <param name="navigationParameter">The parameter value passed to /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested. /// </param> /// <param name="pageState">A dictionary of state preserved by this page during an earlier /// session. This will be null the first time a page is visited.</param> protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState) { } /// <summary> /// Preserves state associated with this page in case the application is suspended or the /// page is discarded from the navigation cache. Values must conform to the serialization /// requirements of <see cref="SuspensionManager.SessionState"/>. /// </summary> /// <param name="pageState">An empty dictionary to be populated with serializable state.</param> protected override void SaveState(Dictionary<String, Object> pageState) { } } }
修改开始页面
我们来向 MainPage.xaml 文件添加一些内容。
修改开始页面
- 若要更改页面标题,请查找页面顶部附近的
AppName
资源。将值从“我的应用程序”""更改为 "Hello, world!"。<x:String x:Key="AppName">Hello, world!</x:String>
- 在根 Grid 中,紧挨
<VisualStateManager.VisualStateGroups>
标记之前,添加带有 TextBlock 的 StackPanel,它询问用户名、接受用户名的 TextBox 元素、Button 以及另一 TextBlock 元素。有关 XAML 布局的详细信息,请参阅快速入门:定义布局。<StackPanel Grid.Row="1" Margin="120,30,0,0"> <TextBlock Text="What's your name?"/> <StackPanel Orientation="Horizontal" Margin="0,20,0,20"> <TextBox x:Name="nameInput" Width="300" HorizontalAlignment="Left"/> <Button Content="Say "Hello""/> </StackPanel> <TextBlock x:Name="greetingOutput"/> </StackPanel>
-
按 F5 以运行应用。它的外观如下所示。
你可以在 TextBox 中键入,但此时,单击 Button 不会有任何作用。在接下来的步骤中,你为按钮的 Click 事件创建事件处理程序,该事件显示了个性化问候。向 MainPage.xaml.cs/.vb 文件添加事件处理程序代码。
步骤 4:创建事件处理程序
XAML 元素可以在出现某些事件时发送消息。这些事件消息为你提供了机会,可以采取一些操作响应事件处理程序方法中的事件。 多个应用中最常见事件之一为用户单击 Button。
我们来为按钮的 Click 事件创建事件处理程序。 事件处理程序会从 nameInput
TextBox 控件获取用户名并使用该用户名向 greetingOutput
TextBlock 输出问候。
使用用于触控、鼠标和笔输入的事件
你应处理什么事件?由于事件可以运行在各种设备上,请牢记设计具有触控输入的 Metro 风格应用。应用还必须可以处理来自鼠标或触笔的输入。幸运的是,诸如 Click 和 DoubleTapped 的事件与设备无关。如果你熟悉 Microsoft .NET 编程,你可能已分离用于鼠标、触控以及触笔输入的事件,如 MouseMove、TouchMove 以及 StylusMove。在 Metro 风格应用中,这些事件使用单个的 PointerMoved 事件替换,该事件同样适用于触控、鼠标以及触笔输入。
添加事件处理程序的步骤
- 在 XAML 或设计视图中,选择已添加到 MainPage.xaml 的 Button。
- 在“属性窗口”中,单击“事件”按钮 (
)。
提示 如果你没有看到“属性窗口”,则按 Alt+Enter 将其打开。
- 在事件列表的顶部查找 Click 事件。在事件的文本框中,键入处理 Click 事件的函数名称。对于本示例,请键入 "Button_Click"。
- 按 Enter。事件处理程序方法在代码编辑器中创建和打开,因此你可以添加在事件出现时执行的代码。
在 XAML 编辑器中,Button 的 XAML 随 Click 事件进行更新。
<Button Content="Say "Hello"" Click="Button_Click"/>
- 向在代码隐藏页面中创建的事件处理程序添加代码。在事件处理程序中,从
nameInput
TextBox 控件检索用户名并使用该控件创建问候。使用greetingOutput
TextBlock 显示结果。 - 按 F5 可构建并运行应用。当你在文本框中输入姓名并单击按钮后,应用会显示个性化问候。
部分 5:设置开始页面的样式
选择主题
轻松自定义应用的外观和感觉。默认情况下,应用使用深色样式的资源。系统资源还包含浅色主题。我们来尝试一下并看看它的外观。
切换到浅色主题
- 双击 App.xaml 可打开它。
- 在打开 Application 标记中,添加 RequestedTheme 属性,并将其值设置为“浅色”:
RequestedTheme="Light"
。<Application x:Class="HelloWorld.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HelloWorld" RequestedTheme="Light">
- 运行应用。现在它使用浅色主题。
你应使用哪个主题?你需要的任何一个。对于主要显示图像或视频的应用,我们建议使用深色主题;对于包含大量文本的应用,我们建议使用浅色主题。(如果你使用的是自定义配色方案,则使用最适合应用外观和感觉的主题。)
使用标准样式
在本教程的前面部分,我们已指出 App.xaml 文件包含对 StandardStyles.xaml ResourceDictionary 的参考:
<ResourceDictionary.MergedDictionaries> <!-- Styles that define common aspects of the platform look and feel Required by Visual Studio project and item templates --> <ResourceDictionary Source="Common/StandardStyles.xaml"/> </ResourceDictionary.MergedDictionaries>
此时,所有文本都非常小,因此很难阅读。你可以轻松将标准样式应用到应用中的元素以使其美观。
设置元素的样式
- 在 XAML 或设计视图中,选择添加到 MainPage.xaml 的第一个 TextBlock。
- 在“属性窗口”中,单击“属性”按钮 (
)。
提示 如果你没有看到“属性窗口”,则按 Alt+Enter 将其打开。
- 展开“其他”组并查找“样式”属性。
- 单击“样式”属性旁边的小正方形可打开菜单。
- 在菜单中,选择“本地资源”> BasicTextStyle。
BasicTextStyle 为在 StandardStyles.xaml ResourceDictionary 中定义的资源。
在设计器中,文本外观会更改。在 XAML 编辑器中,TextBlock 的 XAML 会进行更新。
<TextBlock Text="What's your name?" Style="{StaticResource BasicTextStyle}"/>
- 重复该过程可将 BasicTextStyle 分配至
greetingOutput
TextBlock 元素。现在你的 XAML 如下所示。
<StackPanel Grid.Row="1" Margin="120,30,0,0"> <TextBlock Text="What's your name?" Style="{StaticResource BasicTextStyle}"/> <StackPanel Orientation="Horizontal" Margin="0,20,0,20"> <TextBox x:Name="nameInput" Width="300" HorizontalAlignment="Left"/> <Button Content="Say "Hello"" Click="Button_Click"/> </StackPanel> <TextBlock x:Name="greetingOutput" Style="{StaticResource BasicTextStyle}"/> </StackPanel>
- 按 F5 可构建并运行应用。现在它的外观如下所示。
创建自己的样式
如果要自定义应用的外观和感觉,不必去除系统样式而从头开始。通过替代要更改的样式来进行递增更改会非常方便。
实际上,替代标准样式比创建自己的样式要好。当你的应用在高对比度模式下运行时,对默认样式中的颜色进行的任何更改都会由支持高对比度的配色方案自动替代。
你可以替代标准样式中的任何样式,方法是创建自己的样式并将其包含在 StandardStyles.xaml ResourceDictionary 后。有关详细信息,请参阅快速入门:设置控件样式。
使用自己的样式
- 在 XAML 或设计视图中,选择已添加到 MainPage.xaml 的
greetingOutput
TextBlock。 - 展开“其他”组并查找“样式”属性。
- 单击“样式”属性旁边的小正方形可打开菜单。
- 在菜单中,选择“转换为新资源...”。会打开“创建样式资源”对话框。
注意 要修改的样式必须已被选中。在本示例中,BasicTextStyle 可能从前面步骤中选中。
- 在“创建样式资源”对话框中,输入 "BigGreenTextStyle" 作为资源键,并选择选项来定义应用程序中的资源。
- 单击“确定”。新样式会在 App.xaml 中创建且 TextBlock 会更新以使用新的样式资源。
<TextBlock x:Name="greetingOutput" Style="{StaticResource BigGreenTextStyle}"/>
- 单击“样式”属性旁边的小正方形可再次打开菜单。
- 在菜单中,选择“编辑资源”。App.xaml 会在编辑器中打开。
注意 要修改的样式必须已被选中。在本示例中,BasicTextStyle 可能从前面步骤中选中。
- 在 "BigGreenTextStyle" 资源中,将 Foreground 值更改为"“绿色”",将 FontSize 值更改为 "36"。
<Style x:Key="BigGreenTextStyle" TargetType="TextBlock"> <Setter Property="Foreground" Value="Green"/> <Setter Property="FontSize" Value="36"/> <Setter Property="FontFamily" Value="{StaticResource ContentControlThemeFontFamily}"/> <Setter Property="TextTrimming" Value="WordEllipsis"/> <Setter Property="TextWrapping" Value="Wrap"/> <Setter Property="Typography.StylisticSet20" Value="True"/> <Setter Property="Typography.DiscretionaryLigatures" Value="True"/> </Style>
- 按 F5 可构建并运行应用。问候语现在以较大的绿色字母显示。