双窗格视图是一种布局控件,可帮助你管理具有 2 个不同内容区域的应用的显示,例如列表/详细信息视图。
这是正确的控件吗?
当你拥有两个不同但相关的内容区域时,请使用双窗格视图:
- 内容会自动重新排列,并根据窗口大小调整大小。
- 内容的辅助区域会根据可用空间进行显示/隐藏。
如果需要显示两个内容区域,但不需要双窗格视图提供的大小调整和重新排列,请考虑改用 拆分视图 。
对于导航选项,请使用 导航视图。
工作原理
双窗格视图有两个窗格,可以在其中放置内容。 它根据可供窗口使用的空间调整窗格的大小和排列方式。 可能的窗格布局通过 TwoPaneViewMode 枚举来定义:
枚举值 | 说明 |
---|---|
SinglePane |
仅显示一个窗格,通过 PanePriority 属性指定。 |
Wide |
以并排方式显示窗格,或者显示单个窗格,通过 WideModeConfiguration 属性指定。 |
Tall |
以上下方式显示窗格,或者显示单个窗格,通过 TallModeConfiguration 属性指定。 |
宽模式下的应用。
高模式下的应用。
可以通过设置 PanePriority 来配置双窗格视图,指定在空间只允许显示一个窗格的情况下显示哪个窗格。 然后,指定将 Pane1
显示在纵向窗口的顶部还是底部,或者显示在横向窗口的左侧还是右侧。
双窗格视图处理窗格的大小和排列,但你仍需使窗格内的内容适应大小和方向上的变化。 请参阅采用 XAML 的响应式布局和布局面板,详细了解如何创建自适应 UI。
创建双窗格视图
- 重要 API:TwoPaneView 类
此 XAML 演示如何创建基本 TwoPaneView
。
<TwoPaneView>
<TwoPaneView.Pane1>
<Grid Background="{ThemeResource LayerFillColorDefaultBrush}">
<TextBlock Text="Pane 1" Margin="24"
Style="{ThemeResource HeaderTextBlockStyle}"/>
</Grid>
</TwoPaneView.Pane1>
<TwoPaneView.Pane2>
<Grid Background="{ThemeResource LayerFillColorAltBrush}">
<TextBlock Text="Pane 2" Margin="24"
Style="{ThemeResource HeaderTextBlockStyle}"/>
</Grid>
</TwoPaneView.Pane2>
</TwoPaneView>
TwoPaneView 不需要是页面布局的根元素。 事实上,我们通常会将它用在为应用提供整体导航的 NavigationView 控件中。 TwoPaneView
可以根据其在 XAML 树中的位置进行相应调整。
将内容添加到窗格
双窗格视图的每个窗格都可以保存单个 XAML UIElement
。 要添加内容,通常将 XAML 布局面板置于每个窗格中,然后将其他控件和内容添加到面板。 窗格可以更改大小并在横向模式和纵向模式间切换,因此需确保每个窗格中的内容能够适应这些更改。 请参阅采用 XAML 的响应式布局和布局面板,详细了解如何创建自适应 UI。
此示例创建前面显示的简单图片/信息应用 UI。 内容可以显示在两个窗格中,也可以组合成一个窗格,具体取决于可用空间。 (当只有一个窗格的空间时,可将 Pane2 的内容移到 Pane1 中,并让用户滚动以查看任何隐藏的内容。稍后你将在应对模式变化部分看到相关代码。)
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<CommandBar DefaultLabelPosition="Right">
<AppBarButton x:Name="Share" Icon="Share" Label="Share" Click="Share_Click"/>
<AppBarButton x:Name="Print" Icon="Print" Label="Print" Click="Print_Click"/>
</CommandBar>
<TwoPaneView
x:Name="MyTwoPaneView"
Grid.Row="1"
MinWideModeWidth="959"
MinTallModeHeight="863"
ModeChanged="TwoPaneView_ModeChanged">
<TwoPaneView.Pane1>
<Grid x:Name="Pane1Root">
<ScrollViewer>
<StackPanel x:Name="Pane1StackPanel">
<Image Source="Assets\LandscapeImage8.jpg"
VerticalAlignment="Top" HorizontalAlignment="Center"
Margin="16,0"/>
</StackPanel>
</ScrollViewer>
</Grid>
</TwoPaneView.Pane1>
<TwoPaneView.Pane2
<Grid x:Name="Pane2Root">
<ScrollViewer x:Name="DetailsContent">
<StackPanel Padding="16">
<TextBlock Text="Mountain.jpg" MaxLines="1"
Style="{ThemeResource HeaderTextBlockStyle}"/>
<TextBlock Text="Date Taken:"
Style="{ThemeResource SubheaderTextBlockStyle}"
Margin="0,24,0,0"/>
<TextBlock Text="8/29/2019 9:55am"
Style="{ThemeResource SubtitleTextBlockStyle}"/>
<TextBlock Text="Dimensions:"
Style="{ThemeResource SubheaderTextBlockStyle}"
Margin="0,24,0,0"/>
<TextBlock Text="800x536"
Style="{ThemeResource SubtitleTextBlockStyle}"/>
<TextBlock Text="Resolution:"
Style="{ThemeResource SubheaderTextBlockStyle}"
Margin="0,24,0,0"/>
<TextBlock Text="96 dpi"
Style="{ThemeResource SubtitleTextBlockStyle}"/>
<TextBlock Text="Description:"
Style="{ThemeResource SubheaderTextBlockStyle}"
Margin="0,24,0,0"/>
<TextBlock Text="Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna."
Style="{ThemeResource SubtitleTextBlockStyle}"
TextWrapping="Wrap"/>
</StackPanel>
</ScrollViewer>
</Grid>
</TwoPaneView.Pane2>
</TwoPaneView>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="TwoPaneViewStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Wide">
<VisualState.Setters>
<Setter Target="MyTwoPaneView.Pane1Length"
Value="2*"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
指定要显示的窗格
双窗格视图在只能显示单个窗格时会使用 PanePriority 属性来确定要显示的窗格。 默认情况下,PanePriority 设置为“Pane1”。 下面介绍了如何在 XAML 或代码中设置此属性。
<TwoPaneView x:Name="MyTwoPaneView" PanePriority="Pane2">
MyTwoPaneView.PanePriority = TwoPaneViewPriority.Pane2;
窗格大小设置
窗格的大小由 Pane1Length 和 Pane2Length 属性确定。 它们使用支持 auto 和 star(*) 大小设置的 GridLength 值。 有关 auto 和 star 大小设置的说明,请参阅采用 XAML 的响应式布局中的“布局属性”部分。
默认情况下,Pane1Length
设置为 Auto
,可根据内容自行调整大小。 Pane2Length
设置为 *
,使用所有剩余空间。
使用默认大小设置的窗格
默认值适用于典型的列表/细节布局,其中包含 Pane1
中的项列表以及 Pane2
中的大量详细信息。 但是,你可能更愿意以其他方式划分空间,具体取决于内容。 在这里,Pane1Length
设置为 2*
,因此它获取的空间是 Pane2
的两倍。
<TwoPaneView x:Name="MyTwoPaneView" Pane1Length="2*">
大小为 2* 和 * 的窗格
如果将窗格设置为使用自动大小调整,可以通过设置包含窗格内容的高度和宽度 Panel
来控制大小。 在这种情况下,可能需要处理 ModeChanged
事件,并设置内容的高度和宽度约束,以适合当前模式。
以横向模式或纵向模式显示
在单屏上,双窗格视图的显示模式取决于 MinWideModeWidth 和 MinTallModeHeight 属性。 这两个属性的默认值均为 641px,与 NavigationView.CompactThresholdWidth 的相同。
下表显示了Height
和Width
的TwoPaneView
如何决定使用哪种显示模式。
TwoPaneView 条件 | 模式 |
---|---|
Width > MinWideModeWidth |
使用 Wide 模式 |
Width <= MinWideModeWidth 和 Height >MinTallModeHeight |
使用 Tall 模式 |
Width <= MinWideModeWidth 和 Height <= MinTallModeHeight |
使用 SinglePane 模式 |
横向模式配置选项
MinWideModeWidth
控制双窗格视图何时进入横向模式。 当可用空间大于MinWideModeWidth
属性时,双窗格视图进入Wide
模式。 默认值为 641px,但可以将其更改为所需的值。 通常情况下,应将此属性设置为窗格所需的最小宽度。
当双窗格视图处于横向模式时,WideModeConfiguration 属性决定了要显示的内容:
枚举值 | 说明 |
---|---|
SinglePane |
单个窗格(由 PanePriority 决定)。 该窗格占用 TwoPaneView 的整个大小(即,在两个方向上将大小设置为 *)。 |
LeftRight |
Pane1 在左/Pane2 在右。 两个窗格在垂直方向的大小均设置为 *,Pane1 的宽度设置为 auto,Pane2 的宽度设置为 *。 |
RightLeft |
Pane1 在右/Pane2 在左。 两个窗格在垂直方向的大小均设置为 *,Pane2 的宽度设置为 auto,Pane1 的宽度设置为 *。 |
默认设置为 LeftRight
。
左右 | 右左 |
---|---|
![]() |
![]() |
注意
当设备使用从右到左(RTL)语言时,双窗格视图会自动交换顺序:RightLeft
显示为 LeftRight
,LeftRight
显示为 RightLeft
。
纵向模式配置选项
当可用空间的宽度小于MinWideModeWidth
且高度大于MinTallModeHeight
时,双窗格视图进入Tall
模式。 默认值为 641px,但可以将其更改为所需的值。 通常情况下,应将此属性设置为窗格所需的最小高度。
当双窗格视图处于纵向模式时,TallModeConfiguration 属性决定了要显示的内容:
枚举值 | 说明 |
---|---|
SinglePane |
单个窗格(由 PanePriority 决定)。 该窗格占用 TwoPaneView 的整个大小(即,在两个方向上将大小设置为 *)。 |
TopBottom |
Pane1 在上/Pane2 在下。 两个窗格在水平方向的大小均设置为 *,Pane1 的高度设置为 auto,Pane2 的高度设置为 *。 |
BottomTop |
Pane1 在下/Pane2 在上。 两个窗格在水平方向的大小均设置为 *,Pane2 的高度设置为 auto,Pane1 的高度设置为 *。 |
默认为 TopBottom
。
上下 | 自下而上 |
---|---|
![]() |
![]() |
MinWideModeWidth 和 MinTallModeHeight 的特殊值
可以使用该 MinWideModeWidth
属性阻止双窗格视图进入 Wide
模式 - 只需设置为 MinWideModeWidth
Double.PositiveInfinity 即可。
如果将 MinTallModeHeight
设置为 Double.PositiveInfinity,这将阻止双窗格视图进入 Tall
模式。
如果将 MinTallModeHeight
设置为 0,则会阻止双窗格视图进入 SinglePane
模式。
响应模式更改
可以使用只读的 Mode 属性获取当前显示模式。 当双窗格视图更改其显示的窗格时,会等到 ModeChanged 事件发生后才呈现更新的内容。 可以处理事件以响应显示模式的更改。
重要
初次加载页面时不会发生 ModeChanged
事件,因此,默认 XAML 呈现的 UI 应该与首次加载时显示的 UI 相同。
使用此事件的一种方式是更新应用的 UI,使用户能够在 SinglePane
模式下查看所有内容。 例如,示例应用有一个主窗格(图像)和一个信息窗格。
纵向模式
如果只有显示一个窗格的空间,则可将 Pane2
的内容移到 Pane1
中,让用户可以滚动查看所有内容。 它的外观如下所示。
SinglePane 模式
请记住,MinWideModeWidth
和 MinTallModeHeight
属性决定显示模式何时变化。因此,可以通过调整这些属性的值来更改内容何时在窗格之间移动。
下面是 ModeChanged
事件处理程序代码,用于在 Pane1
和 Pane2
之间移动内容。 它还设置一个 VisualState 以在模式下限制图像 Wide
的宽度。
private void TwoPaneView_ModeChanged(TwoPaneView sender, object args)
{
// Remove details content from it's parent panel.
((Panel)DetailsContent.Parent).Children.Remove(DetailsContent);
// Set Normal visual state.
VisualStateManager.GoToState(this, "Normal", true);
// Single pane
if (sender.Mode == TwoPaneViewMode.SinglePane)
{
// Add the details content to Pane1.
Pane1StackPanel.Children.Add(DetailsContent);
}
// Dual pane.
else
{
// Put details content in Pane2.
Pane2Root.Children.Add(DetailsContent);
// If also in Wide mode, set Wide visual state
// to constrain the width of the image to 2*.
if (sender.Mode == TwoPaneViewMode.Wide)
{
VisualStateManager.GoToState(this, "Wide", true);
}
}
}
UWP 和 WinUI 2
重要
本文中的信息和示例是针对使用 Windows App SDK 和 WinUI 3 的应用优化的,但通常适用于使用 WinUI 2 的 UWP 应用。 有关特定于平台的信息和示例,请参阅 UWP API 参考。
本部分包含在 UWP 或 WinUI 2 应用中使用该控件所需的信息。
适用于 UWP 应用的 TwoPaneView 需要 WinUI 2。 有关详细信息(包括安装说明),请参阅 WinUI 2。 此控件的 API 存在于 Microsoft.UI.Xaml.Controls 命名空间中。
- WinUI 2 Apis:TwoPaneView 类
若要将本文中的代码与 WinUI 2 配合使用,请使用 XAML 中的别名(我们使用 muxc
)来表示项目中包括的 Windows UI 库 API。 有关详细信息,请参阅 WinUI 2 入门。
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
<muxc:TwoPaneView />