选择和绑定上下文
StudentBody课程没有所选学生的属性。如果是这样,您可以在ListView的SelectedItem属性和StudentBody中的selected-student属性之间创建数据绑定。与MVVM一样,视图的属性是数据绑定目标,ViewModel中的属性是数据绑定源。
但是,如果您想直接查看学生的详细视图,而不需要ViewModel的中介,则ListView的SelectedItem属性可以是绑定源。 SelectedStudentDetail程序显示了如何完成此操作。 ListView现在与包含详细视图的StackLayout共享屏幕。为了适应横向和纵向方向,ListView和StackLayout是在代码隐藏文件中操作的Grid的子代。代码隐藏文件还将页面的BindingContext设置为SchoolViewModel类的实例。
名为“detailLayout”的StackLayout的BindingContext绑定到ListView的SelectedItem属性。因为SelectedItem属性是Student类型,所以StackLayout中的绑定可以简单地引用Student类的属性:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SelectedStudentDetail.SelectedStudentDetailPage"
SizeChanged="OnPageSizeChanged">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<Grid x:Name="mainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0" />
</Grid.ColumnDefinitions>
<ListView x:Name="listView"
Grid.Row="0"
Grid.Column="0"
ItemsSource="{Binding StudentBody.Students}">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell ImageSource="{Binding PhotoFilename}"
Text="{Binding FullName}"
Detail="{Binding GradePointAverage,
StringFormat='G.P.A. = {0:F2}'}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout x:Name="detailLayout"
Grid.Row="1"
Grid.Column="0"
BindingContext="{Binding Source={x:Reference listView},
Path=SelectedItem}">
<StackLayout Orientation="Horizontal"
HorizontalOptions="Center"
Spacing="0">
<StackLayout.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="FontSize" Value="Large" />
<Setter Property="FontAttributes" Value="Bold" />
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Label Text="{Binding LastName}" />
<Label Text="{Binding FirstName, StringFormat=', {0}'}" />
<Label Text="{Binding MiddleName, StringFormat=' {0}'}" />
</StackLayout>
<Image Source="{Binding PhotoFilename}"
VerticalOptions="FillAndExpand" />
<Label Text="{Binding Sex, StringFormat='Sex = {0}'}"
HorizontalOptions="Center" />
<Label Text="{Binding GradePointAverage, StringFormat='G.P.A. = {0:F2}'}"
HorizontalOptions="Center" />
</StackLayout>
</Grid>
</ContentPage>
AI 代码解读
首次运行程序时,ListView占据页面的上半部分,整个页面的下半部分为空。 当您选择其中一个学生时,下半部分显示名称的不同格式,较大的照片(Windows Phone除外)和其他信息:
请注意,名为“detailLayout”的StackLayout中的所有Label元素都将其Text属性设置为Student类属性的绑定。 例如,以下是三个Label元素,它们在水平StackLayout中显示全名:
<Label Text="{Binding LastName}" />
<Label Text="{Binding FirstName, StringFormat=', {0}'}" />
<Label Text="{Binding MiddleName, StringFormat=' {0}'}" />
AI 代码解读
另一种方法是为分隔姓氏和名字以及名字和中间名的文本使用单独的Label元素:
<Label Text="{Binding LastName}" />
<Label Text=", " />
<Label Text="{Binding FirstName}" />
<Label Text=" " />
<Label Text="{Binding MiddleName}" />
AI 代码解读
表面上看,这两种方法看起来在视觉上是相同的。 但是,如果当前没有选择学生,则第二种方法会在屏幕上显示一个看起来像奇怪斑点的迷路逗号。 使用StringFormat绑定的优点是,如果BindingContext为null,则Label根本不会出现。
有时,当细节视图没有显示任何内容时,一些虚假文本出现在细节视图中是不可避免的。 在这种情况下,您可能希望将详细布局对象的IsVisible属性绑定到ListView的SelectedItem属性,并使用绑定转换器将null转换为false,将非null转换为true。
SelectedStudentDetail程序中的代码隐藏文件负责为页面设置BindingContext,还负责处理页面的SizeChanged事件以调整Grid和detailLayout对象以获得横向:
public partial class SelectedStudentDetailPage : ContentPage
{
public SelectedStudentDetailPage()
{
InitializeComponent();
// Set BindingContext.
BindingContext = new SchoolViewModel();
}
void OnPageSizeChanged(object sender, EventArgs args)
{
// Portrait mode.
if (Width < Height)
{
mainGrid.ColumnDefinitions[0].Width = new GridLength(1, GridUnitType.Star);
mainGrid.ColumnDefinitions[1].Width = new GridLength(0);
mainGrid.RowDefinitions[0].Height = new GridLength(1, GridUnitType.Star);
mainGrid.RowDefinitions[1].Height = new GridLength(1, GridUnitType.Star);
Grid.SetRow(detailLayout, 1);
Grid.SetColumn(detailLayout, 0);
}
// Landscape mode.
else
{
mainGrid.ColumnDefinitions[0].Width = new GridLength(1, GridUnitType.Star);
mainGrid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star);
mainGrid.RowDefinitions[0].Height = new GridLength(1, GridUnitType.Star);
mainGrid.RowDefinitions[1].Height = new GridLength(0);
Grid.SetRow(detailLayout, 0);
Grid.SetColumn(detailLayout, 1);
}
}
}
AI 代码解读
这是一个风景视图:
不幸的是,Windows 10 Mobile上的ListView中的大图像挤出了文本。
将页面划分为ListView和详细视图并不是唯一的方法。 当用户选择ListView中的项目时,您的程序可以导航到单独的页面以显示详细信息视图。 或者您可以使用专门为此类场景设计的MasterDetailPage。 您将在前面的章节中看到这些解决方案的示例。