學習目標
- TableView 的屬性和寫法
- 客製化 Cell
此章介紹 Xamarin.Forms 最後一個 Collection Views - TableView
TableView 通常拿來顯示 不同類型 的項目,而項目就是類別下的各屬性。
換個方式說,每個項目就是由屬性所呈現出來的 Cell
- Intent - type of TableIntent
- Root - type of TableRoot
- RowHeight - type of int
- HasUnevenRows - type of bool
Intent 屬性可以設定為 (也可不設定) 底下四個值,表示此 TableView 的用途是什麼:
- Data - 用於顯示資料時
- Form - 用於需要輸入資料時
- Settings - 與 Form 很像,但通常會有預設值
- Menu - 通常用於點選項目來觸發動作
Root 屬性對應的 XAML 為 TableRoot,底下會包一個或多個 TableSection,而 TableSection 底下會包一個或多個 Cell:
<TableView Intent="Settings"> <TableRoot> <TableSection Title="Ring"> <SwitchCell Text="New Voice Mail" /> <SwitchCell Text="New Mail" On="true" /> </TableSection> </TableRoot> </TableView>
但其實啊... TableView 與一個 用 ScrollView 包起來的 StackLayout,兩者之間沒有太大的差異,StackLayout 內也可以放置被綁定的 Visual Element。
不過,TableView 在規劃和安排要顯示的資訊或表單時,會更加的方便。
來看一個 Form 型態的 TableView:
一個 Form
這個 TableView 有一個 TableSection,包括五個 Cell - 四個 EntryCell 和一個 SwitchCell。
那這五個 Cell 分別綁定 PersonalInformation 類別的五個屬性 Name、EmailAddress、PhoneNumber、Age、IsProgrammer。
TableRoot 物件的 Title 屬性,只有 Windows 10 Moblie 會顯示
'OnPlatform 寫法已更改,請參考此篇文章
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:EntryForm" x:Class="EntryForm.EntryFormPage"> <ContentPage.Padding> <OnPlatform x:TypeArguments="Thickness" iOS="0, 20, 0, 0" /> </ContentPage.Padding> <StackLayout> <TableView x:Name="tableView" Intent="Form"> <!-- BindingContext --> <TableView.BindingContext> <local:PersonalInformation /> </TableView.BindingContext> <TableRoot Title="Data Form"> <TableSection Title="Personal Information"> <EntryCell Label="Name:" Text="{Binding Name}" Placeholder="Enter name" Keyboard="Text" /> <EntryCell Label="Email:" Text="{Binding EmailAddress}" Placeholder="Enter email address" Keyboard="Email" /> <EntryCell Label="Phone:" Text="{Binding PhoneNumber}" Placeholder="Enter phone number" Keyboard="Telephone" /> <EntryCell Label="Age:" Text="{Binding Age}" Placeholder="Enter age" Keyboard="Numeric" /> <SwitchCell Text="Are you a programmer?" On="{Binding IsProgrammer}" /> </TableSection> </TableRoot> </TableView> <Label x:Name="summaryLabel" VerticalOptions="CenterAndExpand" /> <Button Text="Submit" HorizontalOptions="Center" Clicked="OnSubmitButtonClicked" /> </StackLayout> </ContentPage>
PersonalInformation.cs
class PersonalInformation : ViewModelBase { string name, emailAddress, phoneNumber; int age; bool isProgrammer; public string Name { set { SetProperty(ref name, value); } get { return name; } } public string EmailAddress { set { SetProperty(ref emailAddress, value); } get { return emailAddress; } } public string PhoneNumber { set { SetProperty(ref phoneNumber, value); } get { return phoneNumber; } } public int Age { set { SetProperty(ref age, value); } get { return age; } } public bool IsProgrammer { set { SetProperty(ref isProgrammer, value); } get { return isProgrammer; } } }
執行結果:
Submit 點下去時的動作,會在畫面最下方出現一串文字:
public partial class EntryFormPage : ContentPage { public EntryFormPage() { InitializeComponent(); } void OnSubmitButtonClicked(object sender, EventArgs args) { PersonalInformation personalInfo = (PersonalInformation)tableView.BindingContext; summaryLabel.Text = String.Format($"{personalInfo.Name} is { personalInfo.Age} years old, and has an email address " + $"of {personalInfo.EmailAddress}, and a phone number of {personalInfo.PhoneNumber}, and is {(personalInfo.IsProgrammer ? "" : "not ")}" + "a programmer."); } }*注意下取得資料的方式,是使用 tableView.BindingContext 轉成的類別去取值
同樣的方式也可以用在一般 StackLayout 的 BindingContext,做資料處理時會方便許多,不用一個一個從畫面把物件撈出來。
執行結果:
第一個範例上的表單欄位其實相當單純,當然,會有許多不純的時候...
就會需要用到底下介紹的 客製化 Cell
客製化 Cell
或許客戶需求沒那麼單純時,例如 輸入年齡 變成 挑選年齡範圍
就會需要從 Entry 的輸入方式變成 Picker 的挑選方式
以這個範例來說,讓我們先在 PersonalInformation 新增三個屬性,挑選年齡 (AgeRange),以及 挑選語言 (Language) 和 挑選平台 (Platform)
class ProgrammerInformation : ViewModelBase { string name, emailAddress, phoneNumber, ageRange; bool isProgrammer; string language, platform; public string Name { set { SetProperty(ref name, value); } get { return name; } } public string EmailAddress { set { SetProperty(ref emailAddress, value); } get { return emailAddress; } } public string PhoneNumber { set { SetProperty(ref phoneNumber, value); } get { return phoneNumber; } } public string AgeRange { set { SetProperty(ref ageRange, value); } get { return ageRange; } } public bool IsProgrammer { set { SetProperty(ref isProgrammer, value); } get { return isProgrammer; } } public string Language { set { SetProperty(ref language, value); } get { return language; } } public string Platform { set { SetProperty(ref platform, value); } get { return platform; } } }
今天客戶加入了三個新的需求,挑選年齡範圍、挑選平台和挑選語言,這三個需求都是要做 挑選!!
看來我們需要 Picker 的功能,但 Xamarin 在 TableView 沒給 PickerCell 這種東西怎辦?
自己刻一個出來啊!!
先把類別準備好,PickerCell 繼承自 ViewCell:
namespace Xamarin.FormsBook.Toolkit { [ContentProperty("Items")] public partial class PickerCell : ViewCell { public static readonly BindableProperty LabelProperty = BindableProperty.Create( "Label", typeof(string), typeof(PickerCell), default(string)); public static readonly BindableProperty TitleProperty = BindableProperty.Create( "Title", typeof(string), typeof(PickerCell), default(string)); public static readonly BindableProperty SelectedValueProperty = BindableProperty.Create( "SelectedValue", typeof(string), typeof(PickerCell), null, BindingMode.TwoWay, propertyChanged: (sender, oldValue, newValue) => { PickerCell pickerCell = (PickerCell)sender; if (String.IsNullOrEmpty(newValue)) { pickerCell.picker.SelectedIndex = -1; } else { pickerCell.picker.SelectedIndex = pickerCell.Items.IndexOf(newValue); } }); public PickerCell() { InitializeComponent(); } public string Label { set { SetValue(LabelProperty, value); } get { return (string)GetValue(LabelProperty); } } public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public string SelectedValue { get { return (string)GetValue(SelectedValueProperty); } set { SetValue(SelectedValueProperty, value); } } // Items property. public IListItems { get { return picker.Items; } } void OnPickerSelectedIndexChanged(object sender, EventArgs args) { if (picker.SelectedIndex == -1) { SelectedValue = null; } else { SelectedValue = Items[picker.SelectedIndex]; } } } }
接著刻 XAML:
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.FormsBook.Toolkit.PickerCell" x:Name="cell"> <ViewCell.View> <StackLayout Orientation="Horizontal" BindingContext="{x:Reference cell}" Padding="16, 0"> <Label Text="{Binding Label}" VerticalOptions="Center" /> <Picker x:Name="picker" Title="{Binding Title}" VerticalOptions="Center" HorizontalOptions="FillAndExpand" SelectedIndexChanged="OnPickerSelectedIndexChanged" /> </StackLayout> </ViewCell.View> </ViewCell>
燈燈,獲得 PickerCell 一枚...
最後來使用他,當然分別綁定我們新增的三個屬性:
*OnPlatform 寫法已更改,請參考此篇文章
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:ConditionalCells" xmlns:toolkit="clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit" x:Class="ConditionalCells.ConditionalCellsPage"> <ContentPage.Padding> <OnPlatform x:TypeArguments="Thickness" iOS="0, 20, 0, 0" /> </ContentPage.Padding> <StackLayout> <TableView Intent="Form"> <TableView.BindingContext> <local:ProgrammerInformation /> </TableView.BindingContext> <TableRoot Title="Data Form"> <TableSection Title="Personal Information"> <EntryCell Label="Name:" Text="{Binding Name}" Placeholder="Enter name" Keyboard="Text" /> <EntryCell Label="Email:" Text="{Binding EmailAddress}" Placeholder="Enter email address" Keyboard="Email" /> <EntryCell Label="Phone:" Text="{Binding PhoneNumber}" Placeholder="Enter phone number" Keyboard="Telephone" /> <!--第一個 PickerCell--> <toolkit:PickerCell Label="Age Range:" Title="Age Range" SelectedValue="{Binding AgeRange}"> <x:String>10 - 19</x:String> <x:String>20 - 29</x:String> <x:String>30 - 39</x:String> <x:String>40 - 49</x:String> <x:String>50 - 59</x:String> <x:String>60 - 99</x:String> </toolkit:PickerCell> <SwitchCell Text="Are you a programmer?" On="{Binding IsProgrammer}" /> <!--第二個 PickerCell--> <toolkit:PickerCell Label="Language:" Title="Language" IsEnabled="{Binding IsProgrammer}" SelectedValue="{Binding Language}"> <x:String>C</x:String> <x:String>C++</x:String> <x:String>C#</x:String> <x:String>Objective C</x:String> <x:String>Java</x:String> <x:String>Other</x:String> </toolkit:PickerCell> <!--第三個 PickerCell--> <toolkit:PickerCell Label="Platform:" Title="Platform" IsEnabled="{Binding IsProgrammer}" SelectedValue="{Binding Platform}"> <x:String>iPhone</x:String> <x:String>Android</x:String> <x:String>Windows Phone</x:String> <x:String>Other</x:String> </toolkit:PickerCell> </TableSection> </TableRoot> </TableView> </StackLayout> </ContentPage>
執行結果:
有仔細看 Code 的讀者應該會發現,每個 PickerCell 的 IsEnable 都有綁定 IsProgrammer 這個屬性,
目的就是當你選擇是 Programmer 時,才能去挑選 Language 和 Platform
但執行後會發現,即使 Programmer switch 關閉,PickerCell 還是能點選...
不要問我為什麼...書上也沒寫
不過,有另一個更好的方法可以達到我們的目的,讓我們下一小節見~
赞
回覆刪除謝啦!
刪除