我有一个使用模板的标准拆分页面,尽管我使用的是GridView
而不是ListView
。
<Page
x:Name="pageRoot"
x:Class="App1.Pages.SplitPage1"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1.Pages"
xmlns:common="using:App1.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<!-- Collection of items displayed by this page -->
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding Items}"/>
</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 Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="primaryColumn" Width="420"/>
<ColumnDefinition x:Name="secondaryColumn" Width="*"/>
</Grid.ColumnDefinitions>
<!-- Back button and page title -->
<Grid x:Name="titlePanel">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Margin="39,59,39,0" Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
Style="{StaticResource NavigationBackButtonNormalStyle}"
VerticalAlignment="Top"
AutomationProperties.Name="Back"
AutomationProperties.AutomationId="BackButton"
AutomationProperties.ItemType="Navigation Button"/>
<TextBlock x:Name="pageTitle" Text="{Binding Title}" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1"
IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,0,40"/>
</Grid>
<!-- Vertical scrolling item list -->
<GridView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemsListView"
AutomationProperties.Name="Items"
TabIndex="1"
Grid.Row="1"
Margin="-10,-10,0,0"
Padding="120,0,0,60"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
IsSwipeEnabled="False"
SelectionChanged="ItemListView_SelectionChanged">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="60" Height="60">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel Grid.Column="1" Margin="10,0,0,0">
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap" MaxHeight="40"/>
<TextBlock Text="{Binding Subtitle}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="FrameworkElement">
<Setter Property="Margin" Value="0,0,0,10"/>
</Style>
</ListView.ItemContainerStyle>
</GridView>
<!-- Details for selected item -->
<ScrollViewer
x:Name="itemDetail"
AutomationProperties.AutomationId="ItemDetailScrollViewer"
Grid.Column="1"
Grid.RowSpan="2"
Padding="60,0,66,0"
DataContext="{Binding SelectedItem, ElementName=itemListView}"
HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollMode="Disabled" ScrollViewer.VerticalScrollMode="Enabled"
ScrollViewer.ZoomMode="Disabled">
<Grid x:Name="itemDetailGrid" Margin="0,60,0,50">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Row="1" Margin="0,0,20,0" Width="180" Height="180" Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
<StackPanel x:Name="itemDetailTitlePanel" Grid.Row="1" Grid.Column="1">
<TextBlock x:Name="itemTitle" Margin="0,-10,0,0" Text="{Binding Title}" Style="{StaticResource SubheaderTextBlockStyle}"/>
<TextBlock x:Name="itemSubtitle" Margin="0,0,0,20" Text="{Binding Subtitle}" Style="{StaticResource SubtitleTextBlockStyle}"/>
</StackPanel>
<TextBlock Grid.Row="2" Grid.ColumnSpan="2" Margin="0,20,0,0" Text="{Binding Content}" Style="{StaticResource BodyTextBlockStyle}"/>
</Grid>
</ScrollViewer>
<VisualStateManager.VisualStateGroups>
<!-- Visual states reflect the application's view state -->
<VisualStateGroup x:Name="ViewStates">
<VisualState x:Name="PrimaryView" />
<VisualState x:Name="SinglePane">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="primaryColumn" Storyboard.TargetProperty="Width">
<DiscreteObjectKeyFrame KeyTime="0" Value="*"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="secondaryColumn" Storyboard.TargetProperty="Width">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetail" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="Padding">
<DiscreteObjectKeyFrame KeyTime="0" Value="120,0,90,60"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<!--
When an item is selected and only one pane is shown the details display requires more extensive changes:
* Hide the master list and the column it was in
* Move item details down a row to make room for the title
* Move the title directly above the details
* Adjust padding for details
-->
<VisualState x:Name="SinglePane_Detail">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="primaryColumn" Storyboard.TargetProperty="Width">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetail" Storyboard.TargetProperty="(Grid.Row)">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetail" Storyboard.TargetProperty="(Grid.RowSpan)">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="titlePanel" Storyboard.TargetProperty="(Grid.Column)">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetailGrid" Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0" Value="0,0,0,60"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetail" Storyboard.TargetProperty="Padding">
<DiscreteObjectKeyFrame KeyTime="0" Value="120,0,90,0"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
它工作得很好,虽然我的问题是GridView
和itemDetail
是在单独的滚动条上,我希望它们在同一个滚动条上,所以细节与GridView
一起移动。
我的第一个想法是使用分组GridView
,一个项目组有一个不同的项目模板(细节模板),虽然这似乎是一个很长的路要走,以解决一个简单的问题。
这是一种更简单的方法吗?
详细需求:
页面必须适合尽可能多的"任务"(项目)在它上(因此
GridView
)。Page必须考虑到它们是一个任务还是多个任务
基于这些要求,我必须确保如果列表中只有一个任务,则任务的详细信息填充屏幕上的其余空间,以便没有加载"空白"。同样,如果有很多任务,我必须尽可能多地把它们放在页面上,这样用户才能看到它们。
使用组是一种方法,但我认为即使使用DataTemplateSelector
,您也可能无法获得不同大小的项目。
Hub
控件可能是你最好的选择(它在VS的一个基本应用模板中)。
另一种选择是将GridView
和你的细节网格都放在水平方向的StackPanel
中,并将其放在ScrollViewer
中。只要确保你的GridView
只显示有限数量的项目。横向滚动查看所有项目的细节可能不是最好的用户体验。我还是用ListView
吧
我找到了一个比我认为需要的简单得多的解决方案。
如果我用<ScrollViewer/>
(类似于Filip Skakun建议的)包装我的基础<Grid/>
,我可以滚动页面上的所有内容。然而,正如我的评论所说,GridView
然后没有垂直边界。
为了解决这个问题,我可以将GridView.MaxHeight
设置为我的页面实例化时的窗口高度(减去标题栏),如果窗口大小发生变化,则再次设置。
public SplitPage1()
{
itemListView.MaxHeight = Window.Current.Bounds.Height - 140; // 140 being the height of the titlbar.
// Start listening for Window size changes
// Change the itemListView.MaxHeight when it does.
Window.Current.SizeChanged += Window_SizeChanged;
}
这是Window_SizeChanged方法
private void Window_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
// Set the MaxHeight of the girdview.
itemListView.MaxHeight = Window.Current.Bounds.Height - 140;
this.InvalidateVisualState();
}