在上一章中,我们向您介绍了出色的 Grid 面板,并向您展示了一些有关如何使用它的基本示例。在本章中,我们将进行一些更高级的布局,因为这是 Grid 真正闪耀的地方。首先,让我们加入更多的列甚至一些行,以获得真正的表格布局:
<Window x:Class="WpfTutorialSamples.Panels.TabularGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TabularGrid" Height="300" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>
<Button Grid.Column="2">Button 3</Button>
<Button Grid.Row="1">Button 4</Button>
<Button Grid.Column="1" Grid.Row="1">Button 5</Button>
<Button Grid.Column="2" Grid.Row="1">Button 6</Button>
<Button Grid.Row="2">Button 7</Button>
<Button Grid.Column="1" Grid.Row="2">Button 8</Button>
<Button Grid.Column="2" Grid.Row="2">Button 9</Button>
</Grid>
</Window>
总共九个按钮,每个按钮都放置在自己的单元格中,包含三行和三列。我们再次使用基于星号的宽度,但这次我们也分配了一个数字 - 第一行和第一列的宽度为 2*,这基本上意味着它使用的空间量是行和列的两倍宽度为 1*(或只是 * - 相同)。
您还会注意到我使用附加属性 Grid.Row 和 Grid.Column 将控件放置在网格中,并且您会再次注意到我在要使用第一行或第一行的控件上省略了这些属性第一列(或两者)。这基本上与指定零相同。这可以节省一些打字的时间,但您可能更喜欢分配它们以获得更好的概览。
到目前为止,我们主要使用星形宽度/高度,它指定一行或一列应占据组合空间的一定百分比。但是,还有另外两种指定列或行的宽度或高度的方法:绝对单位和自动宽度/高度。让我们尝试创建一个混合这些的网格:
<Window x:Class="WpfTutorialSamples.Panels.GridUnits"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridUnits" Height="200" Width="400">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2 with long text</Button>
<Button Grid.Column="2">Button 3</Button>
</Grid>
</Window>
在此示例中,第一个按钮的宽度为星形,第二个按钮的宽度设置为“自动”,最后一个按钮的静态宽度为 100 像素。
结果可以在屏幕截图上看到,其中第二个按钮只占用渲染较长文本所需的空间量,第三个按钮正好占用它承诺的 100 像素,第一个按钮的宽度可变其余的部分。
在一个或多个列(或行)具有可变(星形)宽度的网格中,它们会自动共享使用绝对或自动宽度/高度的列/行尚未使用的宽度/高度。当我们调整窗口大小时,这变得更加明显:
在第一个屏幕截图中,您将看到 Grid 为最后两个按钮保留了空间,即使这意味着第一个按钮没有获得正确渲染所需的所有空间。在第二个屏幕截图中,您将看到最后两个按钮保持完全相同的空间量,将剩余空间留给第一个按钮。
在设计各种对话框时,这可能是一项非常有用的技术。例如,考虑一个简单的联系表单,用户在其中输入姓名、电子邮件地址和评论。前两个字段通常具有固定的高度,而最后一个字段可能会占用尽可能多的空间,从而为输入更长的注释留出空间。在下一章中,我们将尝试使用网格以及不同高度和宽度的行和列来构建联系表单。
默认的 Grid 行为是每个控件占用一个单元格,但有时您希望某个控件占用更多行或列。幸运的是,Grid 通过附加属性 ColumnSpan 和 RowSpan 使这变得非常容易。此属性的默认值显然是 1,但您可以指定更大的数字,以使控件跨越更多行或列。
这是一个非常简单的示例,我们使用 ColumnSpan 属性:
<Window x:Class="WpfTutorialSamples.Panels.GridColRowSpan"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridColRowSpan" Height="110" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>
<Button Grid.Row="1" Grid.ColumnSpan="2">Button 3</Button>
</Grid>
</Window>
我们只定义了两列和两行,它们都占据了相同的位置。前两个按钮只是正常使用列,但是对于第三个按钮,我们使用 ColumnSpan 属性让它在第二行占据两列空间。
这一切都非常简单,我们可以只使用面板的组合来实现相同的效果,但对于稍微更高级的情况,这真的很有用。让我们尝试一些可以更好地展示它的强大的东西:
<Window x:Class="WpfTutorialSamples.Panels.GridColRowSpanAdvanced"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridColRowSpanAdvanced" Height="300" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.ColumnSpan="2">Button 1</Button>
<Button Grid.Column="3">Button 2</Button>
<Button Grid.Row="1">Button 3</Button>
<Button Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="2">Button 4</Button>
<Button Grid.Column="0" Grid.Row="2">Button 5</Button>
</Grid>
</Window>
对于三列三行,我们通常会有九个单元格,但在此示例中,我们使用行和列跨度的组合来仅用五个按钮填充所有可用空间。如您所见,控件可以跨越额外的列、额外的行,或者在按钮 4 的情况下:两者。
如您所见,在 Grid 中跨越多个列和/或行非常容易。在后面的文章中,我们将在更实际的示例中使用跨度以及所有其他网格技术。
在本章中,我们将把迄今为止所学的关于 Grid 的知识结合到一个可以在现实世界中使用的示例:一个简单的联系表单。
联系表单的好处在于它只是常用对话框的一个示例 - 您可以采用所使用的技术并将它们应用于几乎任何您需要创建的对话框类型。
此任务的第一步非常简单,它将向您展示一个非常基本的联系表格。它使用三行,其中两行具有自动高度,最后一行具有星形高度,因此它消耗了剩余的可用空间:
<Window x:Class="WpfTutorialSamples.Panels.GridContactForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridContactForm" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox>Name</TextBox>
<TextBox Grid.Row="1">E-mail</TextBox>
<TextBox Grid.Row="2" AcceptsReturn="True">Comment</TextBox>
</Grid>
</Window>
如您所见,最后一个 TextBox 只占用了剩余空间,而前两个只占用了它们需要的空间。尝试调整窗口大小,您将看到注释 TextBox 随之调整大小。
在这个非常简单的示例中,没有标签来指定每个字段的用途。相反,解释性文本位于 TextBox 内,但这通常不是 Windows 对话框的外观。让我们尝试稍微改进一下外观和可用性:
<Window x:Class="WpfTutorialSamples.Panels.GridContactFormTake2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridContactFormTake2" Height="300" Width="300">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label>Name: </Label>
<TextBox Grid.Column="1" Margin="0,0,0,10" />
<Label Grid.Row="1">E-mail: </Label>
<TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" />
<Label Grid.Row="2">Comment: </Label>
<TextBox Grid.Row="2" Grid.Column="1" AcceptsReturn="True" />
</Grid>
</Window>
但也许您正处于评论字段不言自明的情况?在这种情况下,让我们跳过标签并使用 ColumnSpan 为注释 TextBox 获得更多空间:
<TextBox Grid.ColumnSpan="2" Grid.Row="2" AcceptsReturn="True" />
如您所见,Grid 是一个非常强大的面板。希望您在设计自己的对话框时可以使用所有这些技术。