第十九章:集合视图(一)
Xamarin.Forms中的许多视图对应于基本的C#和.NET数据类型:Slider和Stepper是double的可视化表示,Switch是bool,Entry允许用户编辑作为字符串公开的文本。但这种对应关系是否也适用于C#和.NET中的集合类型?
各种类型的集合在数字计算中一直是必不可少的。即使是最古老的高级编程语言也支持数组和结构。这两个原型集合相互补充:数组是通常具有相同类型的值或对象的集合,而结构是通常具有各种类型的相关数据项的集合。
为了补充这些基本集合类型,.NET在System.Collections和System.Collections.Generic命名空间中添加了几个有用的类,最着名的是List和List ,它们是相同类型的对象的可扩展集合。这些集合类的基础是本章中您将遇到的三个重要接口:
- IEnumerable允许迭代集合中的项目。
- ICollection派生自IEnumerable,并添加集合中项目的计数。
- IList派生自ICollection并支持索引以及添加和删除项目。
Xamarin.Forms定义了三个视图,用于维护各种类型的集合,有时还允许用户从集合中选择项目或与项目交互。本章讨论的三种观点是:
- Picker:允许用户选择一个文本项的列表。 Picker通常会保留一个简短的项目列表,通常不超过十几个。
- ListView:通常是以统一(或几乎统一)方式呈现的相同类型的长数据项列表,由称为单元格的对象描述的可视树指定。
- TableView:一组单元格,通常是各种类型的单元格,用于显示数据或管理用户输入。 TableView可以采用菜单,填写表单或应用程序设置集合的形式。
所有这三个视图都提供内置滚动。
起初遇到这三种观点可能看起来有些相似。本章的目的是提供足够的示例,说明如何使用这些视图,以便您在为工作选择正确的工具时不会有任何困难。
Picker和ListView都允许选择,但Picker仅限于字符串,而ListView可以显示以您想要的任何方式呈现的任何对象。 Picker通常是一个短列表,而ListView可以维护必须更长的列表。
ListView和TableView之间的关系可能令人困惑,因为两者都涉及
使用细胞,它是Cell类的衍生物。 Cell派生自Element而非VisualElement。单元格本身不是可视元素,而是提供可视元素的描述。 ListView和TableView以两种不同的方式使用这些单元格:ListView通常显示相同类型的对象列表,其显示由单个单元格指定。 TableView是多个单元格的集合,每个单元格在相关项目的集合中显示单个项目。
如果您想将Xamarin.Forms视图与C#和.NET数据类型等同,那么:
- Picker是字符串数组的直观表示。
- ListView是一个更通用的对象数组,通常是List 集合。此集合中的各个项目通常实现INotifyPropertyChanged接口。
- TableView可以是一个结构,但它更可能是一个类,可能是一个实现INotifyPropertyChanged的类,也称为ViewModel。
让我们从这三个中最简单的一个开始,即Picker。
带Picker的程序选项
当您需要一个允许用户在几个项目的小集合中选择一个项目的视图时,Picker是一个不错的选择。 Picker以特定于平台的方式实现,并且具有仅通过文本字符串标识每个项目的限制。
选择器和事件处理
这是一个名为PickerDemo的程序,它实现了一个Picker,允许您为Entry视图选择专用键盘。 在XAML文件中,Entry和Picker是StackLayout的子项,并且Picker被初始化为包含Keyboard类支持的各种键盘类型的列表:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PickerDemo.PickerDemoPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<StackLayout Padding="20"
Spacing="50">
<Entry x:Name="entry"
Placeholder="Type something, type anything" />
<Picker Title="Keyboard Type"
SelectedIndexChanged="OnPickerSelectedIndexChanged">
<Picker.Items>
<x:String>Default</x:String>
<x:String>Text</x:String>
<x:String>Chat</x:String>
<x:String>Url</x:String>
<x:String>Email</x:String>
<x:String>Telephone</x:String>
<x:String>Numeric</x:String>
</Picker.Items>
</Picker>
</StackLayout>
</ContentPage>
该程序设置了Picker的两个属性:Title属性是一个标识Picker功能的字符串。 Items属性的类型为IList ,通常使用XAML文件中的x:String标记列表对其进行初始化。 (Picker没有content属性,因此需要显式的Picker.Items标记。)在代码中,您可以使用IList 定义的Add或Insert方法将字符串项放入集合中。
这是您第一次运行程序时会看到的内容:
Picker的可视化表示与Entry非常相似,但显示了Title属性。 点击Picker会调用特定于平台的可滚动项目列表:
当您在iOS屏幕上按“完成”或在Android屏幕上按“确定”,或者只需点击Windows列表中的某个项目时,Picker将触发SelectedIndexChanged事件。 Picker的SelectedIndex属性是一个从零开始的数字,表示用户选择的特定项目。 如果没有选择项目 - 首次创建Picker并初始化时的情况 - SelectedIndex等于-1。
PickerDemo程序处理代码隐藏文件中的SelectedIndexChanged事件。 它从Picker中获取SelectedIndex,使用该数字索引Picker的Items集合,然后使用反射获取相应的Keyboard对象,并将其设置为Entry的Keyboard属性:
public partial class PickerDemoPage : ContentPage
{
public PickerDemoPage()
{
InitializeComponent();
}
void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
if (entry == null)
return;
Picker picker = (Picker)sender;
int selectedIndex = picker.SelectedIndex;
if (selectedIndex == -1)
return;
string selectedItem = picker.Items[selectedIndex];
PropertyInfo propertyInfo = typeof(Keyboard).GetRuntimeProperty(selectedItem);
entry.Keyboard = (Keyboard)propertyInfo.GetValue(null);
}
}
同时,交互式Picker显示被取消,Picker现在显示所选项目:
在iOS和Android上,选择会替换Title属性,因此在现实生活中,您可能希望在这两个平台上提供一个简单的Label来提醒用户Picker的功能。
您可以通过设置SelectedIndex属性来初始化Picker以显示特定项目。 但是,您必须在填充Items集合后设置SelectedIndex,因此您可能会从代码中执行此操作或使用property-element语法:
<Picker Title="Keyboard Type"
SelectedIndexChanged="OnPickerSelectedIndexChanged">
<Picker.Items>
<x:String>Default</x:String>
<x:String>Text</x:String>
<x:String>Chat</x:String>
<x:String>Url</x:String>
<x:String>Email</x:String>
<x:String>Telephone</x:String>
<x:String>Numeric</x:String>
</Picker.Items>
<Picker.SelectedIndex>
6
</Picker.SelectedIndex>
</Picker>