编程 Windows 10 桌面:UWP 焦点(第 4 章)
UWP 入门(从 WinForm 迁移) 第 4 章 添加 Windows 控件(构建 DailyJournal 应用程序)
引言
这是我继续讲述 UWP 范式下桌面开发(以及检验其可行性)的故事的努力。
请从第一部分开始,查看其他条目
编程 Windows 10:UWP 焦点 (N 的第 1 部分)[^]
编程 Windows 10:UWP 焦点 (N 的第 2 部分)[^]
编程 Windows 10:UWP 焦点 (N 的第 3 部分)[^]
背景
正如上一章(关于“兔子洞”的章节)中所承诺的,让我们开始为我们的应用程序添加一些控件并编写一些代码。
注意:我们正在创建的 DailyJournal 应用程序的更多细节请参阅本文的第 3 部分。您也可以获取包含应用程序图标的 DailyJournal 项目的步骤 1。
请在 Visual Studio 中打开 DailyJournal 项目。您可以在我上一篇文章(第 3 部分)的开头找到我们将要开始使用的代码。
考虑基本布局
我们需要稍微考虑一下我们的布局,正如我在上一章向您展示的,我们的主页面基本上会按照以下方式布局
考虑到这一点,以及项目模板最初向我们的主页面添加了一个 Grid XAML 元素的事实,我们将修改 Grid 元素,以便它能为我们提供该布局。
我们通过向 Grid 元素添加一些额外的定义来实现这一点。
修改 Grid 布局
为了开始,我将从 Microsoft 的 UWP 文档中复制一些示例代码,并将其粘贴到我的 MainPage.xaml
中。
这是我们应该如何做。
看看当前的 Grid 元素。
它现在只是一个单独的标签。但是,我们需要它打开,以便它是一个容器类型的标签。
请注意,该元素目前带有结束的斜杠 /。要进行我们想要的更改,请继续
-
删除那个斜杠 /
-
在下面两行添加一个 Grid 结束标签
</Grid>
*。
* 我们添加了一个空行,以便在我们粘贴代码时更容易。
它看起来会像下面这样
现在,我们将点击 Grid 标签之间的空行,并将下面的代码粘贴进去
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="44"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Fill="Red" Width="44"/>
<Rectangle Fill="Blue" Grid.Row="1"/>
<Rectangle Fill="Green" Grid.Column="1"/>
<Rectangle Fill="Orange" Grid.Row="1" Grid.Column="1"/>
它看起来会像
代码来源: https://docs.microsoft.com/en-us/windows/uwp/design/layout/layout-panels
#############################################################################
侧边栏:可能的 Visual Studio 设计视图错误
我注意到,如果我的设计视图太小,那么不知何故,设计视图将呈现为主页面背景透明的样子。上一张图片中的任何矩形形状都不会显示出来。
如果您没有看到上一张图片中显示的颜色,请尝试调整设计视图的大小,直到您看到它们。
#############################################################################
Grid:行和列
我认为这段代码很有帮助,因为它能让我们轻松地看到我们的网格现在被分成了两行两列。
现在,我们应该能够调整这些值以达到我们想要的效果。我们实际上想要左边有两列,右边只有一列。
基本上,我们希望右边的列跨越左边的两列,而且我们实际上不需要橙色列,所以让我们删除它,看看会发生什么。
为此,转到那一行,高亮显示它,然后按 [Delete] 键。
当您这样做时,它看起来会像下面这样
底行变白
请注意,底部的列现在是默认颜色(白色——即 ApplicationBackgroundThemeBrush)。然而,该列仍然存在。我们希望右边的列跨越整个页面高度。换句话说,该列应该跨越所有行。为了实现这一点,我们需要在该列中添加一个属性,该属性恰好命名为 Grid.RowSpan。
Grid.RowSpan
当我们添加这个新属性时,我们只需提供一个整数,指示它应该跨越多少行。在我们的例子中,值为二。以下是添加到当前填充绿色颜色的 Rectangle 中的代码。
Grid.RowSpan="2"
当您添加这段代码时,它看起来会像下面这样
DesignView 自动更新
当您进行更改时,DesignView 会自动更新,底部列也变成绿色,因为我们右边的列现在跨越了两行。
RowDefinitions 解释
让我们关注 RowDefinitions
以及它们的含义。当前的 XAML 用于 RowDefinitions
如下所示
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="44"/>
</Grid.RowDefinitions>
这定义了两行。
第一行的高度或宽度是未确定的,因为它没有属性。这意味着它将由其他行的影响来定义。
第二行的高度只有 44 像素。我们可以看到底部蓝绿相间的行非常窄,因为它只有 44 像素。
更改 Height 属性
让我们继续并将该值更改为 250,这样该行就会稍微大一些。
当您进行更改时,它看起来会像下面这样
运行应用程序 - CTRL-F5
进行此更改后,继续运行应用程序。您可以按 CTRL-F5,这将生成应用程序并在关闭调试的情况下运行它。
应用程序运行时调整窗口大小
如果您调整窗口大小,您将看到右侧尺寸将始终占据两行。您还将看到左上角块(红色)是成比例的,而蓝色区域的高度始终为 250 像素。
但是,我们需要的是红色部分刚好足以容纳我们的 CalendarView,而蓝色区域刚好足以容纳我们的 ListView。让我们看看是否能做一些修改来使其看起来像那样。关闭应用程序,回到 Visual Studio,我们将做一些修改。
拖放控件
我基本上使用了带有颜色的示例代码,以便在本教程中更容易地定位行和列。
现在,我们想将一个 CalendarView 拖放到我们的页面*上。
* 从现在开始,我将把我们的应用程序窗口称为页面,因为 XAML 元素就是这样命名的。
添加 CalendarView
从工具箱的 [所有 XAML 控件] 中抓取一个 CalendarView
,将其拖到页面上,然后将其放在红色框中。
检查 XAML
您可以看到它将 CalendarView 元素添加到 XAML 中 Grid 元素的末尾。
此外,请注意 CalendarView
认为我们是以绝对坐标将其拖放的,并且该元素包含 HorizontalAlignment 和 Margin 标签,这些标签将其放置在页面的其他项的相对位置。在这种情况下,我们不希望控件这样定位。
这使得一切看起来有点混乱。我们需要在 CalendarView
上设置一些 XAML 属性,使其真正成为 Grid 的列和行之一。
首先,删除 Margin
属性及其值。
设置 GridColumn / GridRow
现在,让我们告诉布局 CalendarView
实际上是网格的一部分,并且是 GridColumn
零和行零。
渲染顺序
我将更改 XAML 中的两项内容,然后向您展示图片。但首先,仔细看看上一张图片中的红色矩形。它实际上并不仅仅是您看到的那么小一块。它实际上延伸到了 CalendarView 的后面。
目前,矩形位于 CalendarView
后面,因为对象在屏幕上的渲染顺序。如果没有额外的 XAML 来更改 Z-Order
,元素(对象)将按照它们在 XAML 中出现的顺序绘制。这意味着红色矩形先绘制,然后是蓝色,然后是绿色。最后,CalendarView
绘制在红色矩形之上。当我说将 XAML 改为将 CalendarView 移到上面时,您将看到红色矩形将以更高的 Z-Order
号绘制,它将位于 CalendarView
之上。
将您的 CalendarView
XAML 更改为如下所示
<CalendarView HorizontalAlignment="Left" Grid.Row="0" Grid.Column="0" VerticalAlignment="Top"/>
进行此更改后,将其移动到 <Grid.ColumnDefinitions>
之后的第一个项目
当您进行此更改并移动该行时,一切都会像这样
出现空格(行)
另外请注意,它现在认为有第三行的空间(空白)。我们需要解决这个问题。
我认为开始解决这个问题的方法是将我们的 ListView
控件拖放到蓝色区域。
添加 ListView
我刚刚拖放了一个新的 ListView,它实际上并没有显示在 DesignView 中。不过它在 XAML 中,位于 Grid 的底部。
编辑 ListView XAML
我们将采取相同的步骤来尝试修复此控件。
-
删除 Margin 属性及其值。
-
将其移到 XAML 中,使其成为 CalendarView 之后的下一个控件
-
添加适当的 Grid.Row 和 Grid.Column 值。
我还会删除蓝色 Rectangle 元素。
这是 Grid XAML 的当前状态。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" >
<Grid.RowDefinitions >
<RowDefinition Height="Auto" />
<RowDefinition Height="250"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CalendarView HorizontalAlignment="Left" Grid.Row="0" Grid.Column="0" VerticalAlignment="Top"/>
<ListView HorizontalAlignment="Left" Height="100" Grid.Row="1" Grid.Column="0" VerticalAlignment="Top" Width="100"/>
<Rectangle Fill="Red" Width="44"/>
<Rectangle Fill="Green" Grid.RowSpan="2" Grid.Column="1"/>
</Grid>
XAML 设计中的更多挑战
但我们仍然有那个奇怪的最后一行,它在做奇怪的事情。另外,ListView
的背景色是白色的,所以您很难分辨它的位置。
我将采取的修复措施
- 我正在删除红色 Rectangle 元素,因为现在我们不需要它来进行对齐。
- 我还会将 RichEditBox 拖放到绿色矩形区域,并尝试将其正确调整。
VerticalAlignment 和 HorizontalAlignment Stretch
我不得不进行一些搜索,以发现如何让 ListView 占据其外部容器(Grid.Row 和 Grid.Column)中的所有可用空间。为此,我必须更改 VerticalAlignment
和 HorizontalAlignment
并将其设置为“Stretch”值。
我对 RichEditBox
做了同样的处理。这是修改后的 XAML,以便您可以跟上。
修改后的 XAML 遵循教程
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" >
<Grid.RowDefinitions >
<RowDefinition Height="Auto" />
<RowDefinition Height="400"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CalendarView HorizontalAlignment="Left" Grid.Row="0" Grid.Column="0" VerticalAlignment="Top"/>
<ListView Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<RichEditBox Grid.Column="1" Grid.Row="0" Grid.RowSpan="2"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
如果您将鼠标悬停在 Visual Studio 中的 DesignView 区域上,它将突出显示控件的边界。您可以看到 RichEditBox 跨越了行并拉伸到了边缘。
设计器中难以看到控件
那些未被选中、没有背景色或数据内容的控件在设计器中很难看到,而我们的 ListView 目前就是这种情况。
您也可以点击代表某个项目的 XAML,该项目将在 Visual Studio 的 DesignView 中被激活。
以编程方式添加模拟数据以供查看
现在,让我们以编程方式向 ListView 和 RichEditBox 添加一些模拟数据,然后运行应用程序看看会得到什么。
当页面加载完成后,我们将添加模拟数据。为此,请点击 XAML 中的 <Page>
元素(这是访问它的最简单方法,因为 DesignView
有控件和容器的多层嵌套)。
单击 <Page>
元素后,转到属性窗口,然后单击[闪电]图标。该图标允许您访问可以为其编写处理程序的系统事件。在我们的例子中,我们正在寻找 Loaded 事件,所以向下滚动直到看到该事件。
双击 TextBox 添加事件
当您找到 Loaded
事件时,只需双击 Loaded 事件旁边的 TextBox
。如果您正确双击,您将知道,因为屏幕会闪烁,Visual Studio 会将您移至 MainPage.xaml.cs
,在那里它已自动添加了一个名为 Page_Loaded()
的新方法。
您的光标将闪烁在 { } 括号内,这是 Visual Studio 表示它已准备好您输入代码的方式。
添加事件会更改 XAML
当然,就像我们在第 2 章中学到的关于 Button 一样,添加一个事件会在关联的 XAML 元素中添加一个属性。如果您看一下 XAML 中的 <Page>
元素,您会看到以下内容
注意:我还没有命名 XAML Page
元素,所以 Visual Studio 会自行引用 Page
对象为 Page。如果我们命名了它,那会更好一些,因为它会将此方法命名为 <NAME>_Loaded
,其中 <NAME>
等于 Name 属性的值。这样会更清楚。
我已为 RichEditBox
和 ListView 分别命名,以便更容易使用它们,方法是向它们添加 Name=”” 属性。这是 MainPage.xaml 文件的更新 XAML。如果您正在跟随,请替换您的整个文件,您将拥有一个可以继续使用的良好 XAML 文件。
<Page
x:Class="DailyJournal.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DailyJournal"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Loaded="Page_Loaded">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" >
<Grid.RowDefinitions >
<RowDefinition Height="Auto" />
<RowDefinition Height="400"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CalendarView HorizontalAlignment="Left" Grid.Row="0" Grid.Column="0" VerticalAlignment="Top"/>
<ListView Name="EntriesListView" Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<RichEditBox Name="MainRichEdit" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
</Page>
完成之后,您可以将以下代码添加到 Page_Loaded()
方法(在 MainPage.xaml.cs
中),以便 EntriesListView
现在包含一些数据。这将与上面的 XAML 一起工作,因为我将 ListView 命名为 EntriesListView。
EntriesListView.Items.Add("super");
EntriesListView.Items.Add("extra");
EntriesListView.Items.Add("maximum");
EntriesListView.Items.Add("advanced");
EntriesListView.Items.Add("efficient");
构建和运行
生成并运行应用程序 (CTRL-F5),以便我们可以开始了解它的外观。
我的看起来像
值出现在 ListView 中
现在这些值出现在 ListView 中了。对我来说,CalendarView 占用的空间有多大,ListView 中每个项目的大小有多大,这有点令人震惊。
但是请注意,您已经可以使用 RichEditBox
进行输入了。当然,没有什么被保存,它几乎没有其他功能,但如果您按 Ctrl-Shift-L
,它将允许您在编号/项目符号选项之间循环以更改文本。
结论
一天的工作已经很不错了。您已经学会了很多关于使用 Grid
进行布局的知识,而且它确实不那么痛苦,而且看起来与我最初的 WinForm 应用程序非常相似。
我在这里暂停一下,让您喘口气(我也一样),思考一下您学到的东西。
下次我们将开始为应用程序添加更多功能,并希望能将其保存为条目,然后这些条目将显示在我们的 ListView 中。
历史
2017-11-27 - 首次发布