XAML in Xamarin.Forms 基礎篇 電子書

XAML in Xamarin.Forms 基礎篇 電子書
XAML in Xamarin.Forms 基礎篇 電子書

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書

2016/07/08

Xamarin.Forms 標籤式頁面 Tabbed Page

標籤式頁面

在這一章節,要來說明 Xamarin.Forms 的另外一種頁面 TabbedPage 標籤頁面 (另外四種分別為ContentPage 內容頁面, MasterDetailPage 導航抽屜頁面, NavigationPage 導航頁面, CarouselPage 旋轉木馬頁面,其中,前三者在前面的章節中已經出現過了,而且有展示如何使用,最後一個旋轉木馬頁面,將會於下一個章節來介紹); Xamarin.Forms 提供的 TabbedPage 標籤頁面是由許多標籤與其要顯示的明細內容所組成,因此,透過標籤頁面可以讓使用者自行切換查看不同的內容,但是卻不需要做任何頁面切換的導航,並且可以自訂每個標籤頁面所要出現內容與控制項。
這裡將會提供兩種標籤頁面的實作說明,一個是透過了 TabbedPage.ItemTemplate 來自訂每個子標籤頁面要出現的內容,透過了資料繫結與 Converter 轉換器的實作,讓每個子標籤頁面顯示不同的內容;透過這樣的設計,每個子標籤頁面的內容與控制項都是一樣的,只不過可以顯示出多筆資料到不同的標籤頁面上。
另外一種標籤頁面的專案實作說明,將會著重在每個子標籤頁面的明細部分,都會有屬於自己專屬的 XAML 控制項,所以,每個子標籤頁面就會長的不一樣,甚至可以做更多豐富的控制與顯示效果。
在這個範例中,將會繼續使用 Font Awesome 功能,若不知道如何設定與使用 Font Awesome,請參考 使用者登入

建立標籤式的樣板式頁面方案

  1. 首先,開啟您的 Visual Studio 2015
  2. 接著透過 Visual Studio 2015 功能表,選擇這些項目 檔案 > 新增 > 專案 準備新增一個專案。
  3. 接著,Visual Studio 2015 會顯示 新增專案 對話窗,請在這個對話窗上,進行選擇 Visual C# >Cross-Platform > Blank Xaml App (Xamarin.Forms Portable)
  4. 接著,在最下方的 名稱 文字輸入盒處,輸入 TabPage1 這個名稱,最後使用滑鼠右擊右下方的 確定按鈕。
  5. 當專案建立到一半,若您的開發環境還沒有建置與設定完成 Mac 電腦與 Xamarin Studio for Mac 系統,此時會看到 Xamarin Mac Agent Instructions 對話窗出現,這個對話窗是要提醒您進行與 Mac 電腦連線設定,這是因為,您無法在 Windows 作業系統進行 iOS 相關應用程式的建立與設計工作,而是需要透過 Mac 電腦安裝的 XCode 來協助您完成這些 iOS 應用程式的建立工作。不過,這不影響您繼續開發 Xamarin.Forms 的應用程式,只不過此時,您無法編譯與執行 iOS 的應用程式。
  6. 接著會看到 新的通用Windows專案 對話視窗,此時,您只需要按下 確定 按鈕即可,此時,專案精靈會繼續完成相關平台的專案建立工作。
  7. 最後,整個新的 Xamarin.Forms 專案就建立完成了。

開始開發 籤式的樣板式頁面

請參考底下說明,依序實作相關指示內容,以便完成該專案實作。

建立 籤式的樣板式頁面 主畫面 (MainPage.xaml)

打開 核心PCL 專案內的 MainPage.xaml 檔案,依據底下 XAML 宣告,置換所有 XAML 宣告內容。
新建立的 MainPage.xaml 的宣告定義中,可以看到該頁面的根視覺控制項已經從 ContentPage 變換成為TabbedPage,這表示這個頁面將會是一個標籤式頁面。
在這個 TabPage1.MainPage 標籤事頁面定義內容中,有兩個節點:
  • TabbedPage.Resources
    在這裡,將會宣告定義這個標籤式頁面需要用到的 XAML 資源 (Resource),在這裡,定義了一個名為booleanConverter 的轉換器資源 (Converter Resource),在後面的 XAML 定義中,將會透過資料繫結與這個轉換器,依據當時綁定的資料,決定那些版面配置與視覺控制項是否要顯示出來;因此,透過這樣的技巧,可以讓不同的標籤子頁面,顯示出不同的內容與效果。
  • TabbedPage.ItemTemplate
    這個節點,將會用來定義每個子標籤頁面要顯示那些視覺控制項。每個子標籤頁面會垂直依序顯示出名稱、圖片、家族、該圖片的明細介紹(這部分會依據當時資料的定義,顯示不同的 StackLayout 版面配置、Genus值。
    在 DataTemplate 節點中,可以看到,每個標籤頁面,都是使用 ContentPage 這個物件,在ContentPage 物件內,有許多 StackLayout 版面配置控制項,用來顯示出更多明細資訊。

MainPage.xaml 的宣告定義內容

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:TabPage1"
             x:Class="TabPage1.MainPage"
            Title="標籤頁面"
            >

  <TabbedPage.Resources>
    <ResourceDictionary>
      <local:NonNullToBooleanConverter x:Key="booleanConverter" />
    </ResourceDictionary>
  </TabbedPage.Resources>
  <TabbedPage.ItemTemplate>
    <DataTemplate>
      <ContentPage Title="{Binding Name}" 
                   BackgroundColor="{Binding Color}"
                   >
        <StackLayout Padding="5, 25">
          <Label Text="{Binding Name}"
                 Font="Bold,Large"
                 HorizontalOptions="Center" />
          <Image Source="{Binding PhotoUrl}"
                 WidthRequest="200"
                 HeightRequest="200" />
          <StackLayout Padding="50, 10">
            <StackLayout Orientation="Horizontal">
              <Label Text="Family:"
                     HorizontalOptions="FillAndExpand" />
              <Label Text="{Binding Family}"
                     Font="Bold,Medium" />
            </StackLayout>
            <StackLayout Orientation="Horizontal"
                         IsVisible="{Binding Subfamily,
                            Converter={StaticResource booleanConverter}}">
              <Label Text="Subfamily:"
                     HorizontalOptions="FillAndExpand" />
              <Label Text="{Binding Subfamily}"
                     Font="Bold,Medium" />
            </StackLayout>
            <StackLayout Orientation="Horizontal"
                         IsVisible="{Binding Tribe,
                            Converter={StaticResource booleanConverter}}">
              <Label Text="Tribe:"
                      HorizontalOptions="FillAndExpand" />
              <Label Text="{Binding Tribe}"
                     Font="Bold,Medium" />
            </StackLayout>
            <StackLayout Orientation="Horizontal">
              <Label Text="Genus:"
                     HorizontalOptions="FillAndExpand" />
              <Label Text="{Binding Genus}"
                     Font="Bold,Medium" />
            </StackLayout>
          </StackLayout>
        </StackLayout>
      </ContentPage>
    </DataTemplate>
  </TabbedPage.ItemTemplate>

</TabbedPage>
接著來修改這個 MainPage.xaml 的 code-behind 的 C# 程式碼,打開 MainPage.xaml.cs 檔案,依照底下列出程式碼,進行修正。
在這裡,您僅僅需要在建構式中,將 MonkeyDataModel.All 的值,指定給 TabbedPage 這個控制項的屬性ItemSource,這樣,這個標籤頁面控制項,就會知道要顯示那些資料了。
其中,[assembly: XamlCompilation(XamlCompilationOptions.Compile)] 這個在 namespace 關鍵字前的宣告,在開發 Xamarin.Forms 上是相當重要的,因為,當您加入了底下這行宣告,則該 .xaml 檔案內的 XAML 內容,就會在編譯時期進行檢查;當有錯誤的語法或者內容在編譯時期發現到之後,就不會讓這個應用程式繼續執行,直到您將這些有錯誤的 XAML 內修正完成後,才能夠正確執行。反過來說,預設 XAML 語法或者內容有錯誤的時候,往往必須要到執行時期,並且開啟這個頁面的時候,應用程式才會顯示例外異常訊息,這將會造成您的應用程式閃退。
最後,請記得要將 MainPage 這個類別,要繼承這個類別 TabbedPage 。

MainPage.xaml.cs 的 code-behind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace TabPage1
{
    public partial class MainPage : TabbedPage
    {
        public MainPage()
        {
            InitializeComponent();

            ItemsSource = MonkeyDataModel.All;
        }
    }
}

建立 MonkeyDataModel 資料模型

請在 核心PCL 專案節點上,使用滑鼠右擊該節點,在彈出功能表中,點選 加入 > 類別,在 加入新項目 TabPage1 對話窗內,選擇 Visual C# > 類別,接著在底下 名稱 欄位中,輸入 MonkeyDataModel.cs,以便建立一個新的類別檔案。
在這個類別中,定義了六個屬性,與一個靜態 IList 的屬性 All;接著,在靜態建構式內,進行 All 這個屬性的初始化,這個 All 的屬性值內容,將會出現在每個標籤頁面內。
在每個頁面物件中,Color 這個屬性,表示該標籤頁面的背景顏色,這個值會透過資料繫結 (Data Binding)的方式,綁定到 XAML 的背景顏色屬性內。

MonkeyDataModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace TabPage1
{
    public class MonkeyDataModel
    {
        public string Name { set; get; }

        public string Family { set; get; }

        public string Subfamily { set; get; }

        public string Tribe { set; get; }

        public string Genus { set; get; }

        public string PhotoUrl { set; get; }
        public Color Color { set; get; }

        public static IList<MonkeyDataModel> All { set; get; }

        static MonkeyDataModel()
        {
            All = new ObservableCollection<MonkeyDataModel> {
                new MonkeyDataModel {
                    Name = "Chimpanzee",
                    Family = "Hominidae",
                    Subfamily = "Homininae",
                    Tribe = "Panini",
                    Genus = "Pan",
                    PhotoUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/6/62/Schimpanse_Zoo_Leipzig.jpg/640px-Schimpanse_Zoo_Leipzig.jpg",
                    Color = Color.Green
                },
                new MonkeyDataModel {
                    Name = "Orangutan",
                    Family = "Hominidae",
                    Subfamily = "Ponginae",
                    Genus = "Pongo",
                    PhotoUrl = "http://upload.wikimedia.org/wikipedia/commons/b/be/Orang_Utan%2C_Semenggok_Forest_Reserve%2C_Sarawak%2C_Borneo%2C_Malaysia.JPG",
                    Color = Color.Yellow
                },
                new MonkeyDataModel {
                    Name = "Tamarin",
                    Family = "Callitrichidae",
                    Genus = "Saguinus",
                    PhotoUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/85/Tamarin_portrait_2_edit3.jpg/640px-Tamarin_portrait_2_edit3.jpg",
                    Color = Color.Pink
                }
            };
        }
    }
}

建立 NonNullToBooleanConverter 轉換器

請在 核心PCL 專案節點上,使用滑鼠右擊該節點,在彈出功能表中,點選 加入 > 類別,在 加入新項目 TabPage1 對話窗內,選擇 Visual C# > 類別,接著在底下 名稱 欄位中,輸入NonNullToBooleanConverter.cs,以便建立一個新的類別檔案。 將底下的 C# 程式碼,這換掉NonNullToBooleanConverter.cs 的內容。
在底下的 C# 程式碼,是一個非常典型的 XAML 轉換器的應用做法;當您需要在 XAML 裡面,想將一個物件,轉換成為另外一種物件,就可以使用轉換器這樣的作法。
首先,產生一個類別,該類別需要實作出 IValueConverter 這個介面,該介面裡面有兩個方法 Convert,ConvertBack,通常來說,大部分的程式設計師僅會用到前者,因此,在這裡也是一樣。在 Convert 這個方法中,會接收到 XAML 傳送過來的物件,此時,在這裡判斷該物件是否為 string 類型,若為 string類型且字串物件有字串存在,也就是不是 null 或者空字串,該方法就會回傳 true,也就是在 XAML 中,需要顯示相對應的 StackLayout

NonNullToBooleanConverter.cs

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace TabPage1
{
    class NonNullToBooleanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is string)
            {
                return !string.IsNullOrEmpty((string)value);
            }

            return value != null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }
}

建立

建立

執行結果

底下分別來查看在不同平台下,執行這個應用程式所看到的成果是甚麼?

Android 執行結果

請在方案總管內,滑鼠右擊 TabPage1.Droid 專案,選擇 設定為起始專案,接著按下 F5 開始執行。
Android_TabPage1_1
Android_TabPage1_2
Android_TabPage1_3

iOS 執行結果

請在方案總管內,滑鼠右擊 TabPage1.iOS 專案,選擇 設定為起始專案,接著按下 F5 開始執行。

參考


建立標籤式的可導航頁面方案

  1. 首先,開啟您的 Visual Studio 2015
  2. 接著透過 Visual Studio 2015 功能表,選擇這些項目 檔案 > 新增 > 專案 準備新增一個專案。
  3. 接著,Visual Studio 2015 會顯示 新增專案 對話窗,請在這個對話窗上,進行選擇 Visual C# >Cross-Platform > Blank Xaml App (Xamarin.Forms Portable)
  4. 接著,在最下方的 名稱 文字輸入盒處,輸入 TabPage2 這個名稱,最後使用滑鼠右擊右下方的 確定按鈕。
  5. 當專案建立到一半,若您的開發環境還沒有建置與設定完成 Mac 電腦與 Xamarin Studio for Mac 系統,此時會看到 Xamarin Mac Agent Instructions 對話窗出現,這個對話窗是要提醒您進行與 Mac 電腦連線設定,這是因為,您無法在 Windows 作業系統進行 iOS 相關應用程式的建立與設計工作,而是需要透過 Mac 電腦安裝的 XCode 來協助您完成這些 iOS 應用程式的建立工作。不過,這不影響您繼續開發 Xamarin.Forms 的應用程式,只不過此時,您無法編譯與執行 iOS 的應用程式。
  6. 接著會看到 新的通用Windows專案 對話視窗,此時,您只需要按下 確定 按鈕即可,此時,專案精靈會繼續完成相關平台的專案建立工作。
  7. 最後,整個新的 Xamarin.Forms 專案就建立完成了。

開始開發 籤式的樣板式頁面

請參考底下說明,依序實作相關指示內容,以便完成該專案實作。

建立 籤式的樣板式頁面 主畫面 (MainPage.xaml)

打開 核心PCL 專案內的 MainPage.xaml 檔案,依據底下 XAML 宣告,置換所有 XAML 宣告內容。
新建立的 MainPage.xaml 的宣告定義中,可以看到該頁面的根視覺控制項已經從 ContentPage 變換成為TabbedPage,這表示這個頁面將會是一個標籤式頁面。
在這個 TabPage2.MainPage 標籤事頁面定義,使用 XAML 節點,定義了三個標籤子頁面,分別為:ContentPageNavigationPageContentPage

MainPage.xaml 的宣告定義內容

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:TabPage2"
             x:Class="TabPage2.MainPage">

  <local:TodayPage />
  <NavigationPage Title="Schedule" >
    <x:Arguments>
      <local:SchedulePage />
    </x:Arguments>
  </NavigationPage>
  <local:SettingsPage />

</TabbedPage>

建立 TodayPage.xaml 頁面

使用滑鼠右擊 核心PCL 專案,從彈出功能表中,點選 加入 > 新增項目;接著,在 加入新項目 - TabPage2 對話窗內,點選 Visual C# > Cross-Platform > Forms Xaml Page,最後,在底下名稱欄位的文字輸入盒中,輸入 TodayPage
接著,請將下列 XAML 定義替換掉新建立的 .xaml 檔案內容。

TodayPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TabPage2.TodayPage"
              Title="Today">

  <ContentPage.Content>
    <StackLayout>
      <Label Text="Today's appointments go here" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
    </StackLayout>
  </ContentPage.Content>
</ContentPage>

建立 SchedulePage.xaml 頁面

使用滑鼠右擊 核心PCL 專案,從彈出功能表中,點選 加入 > 新增項目;接著,在 加入新項目 - TabPage2 對話窗內,點選 Visual C# > Cross-Platform > Forms Xaml Page,最後,在底下名稱欄位的文字輸入盒中,輸入 SchedulePage
接著,請將下列 XAML 定義替換掉新建立的 .xaml 檔案內容。
在這個頁面,只有包含 Label 文字標籤 與 Button 按鈕 兩個控制項,因為在 Button 控制項中有定義了 Clicked 事件,因此,需要在 code-behind 內定義該點擊事件該做甚麼事情。

SchedulePage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TabPage2.SchedulePage"
             Title="This Week">

  <ContentPage.Content>
    <StackLayout>
      <Label 
        Text="This week's appointments go here" 
        HorizontalOptions="Center" 
        VerticalOptions="CenterAndExpand" />
      <Button 
        Text="Upcoming Appointments" 
        Clicked="OnUpcomingAppointmentsButtonClicked" 
        VerticalOptions="CenterAndExpand" />
    </StackLayout>
  </ContentPage.Content>

</ContentPage>

SchedulePage.xaml.cs

請打開 SchedulePage.xaml 的 code-behind 檔案 SchedulePage.xaml.cs,並請將下列 C# 程式碼換掉現在內容。
在這個 code-behind 內,按鈕事件只有做一件事情,那就是通知導航頁面 (NavigationPage),切換到UpcomingAppointmentsPage 新頁面。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace TabPage2
{
    public partial class SchedulePage : ContentPage
    {
        public SchedulePage()
        {
            InitializeComponent();
        }

        async void OnUpcomingAppointmentsButtonClicked(object sender, EventArgs e)
        {
            await Navigation.PushAsync(new UpcomingAppointmentsPage());
        }
    }
}

建立 UpcomingAppointmentsPage.xaml 頁面

使用滑鼠右擊 核心PCL 專案,從彈出功能表中,點選 加入 > 新增項目;接著,在 加入新項目 - TabPage2 對話窗內,點選 Visual C# > Cross-Platform > Forms Xaml Page,最後,在底下名稱欄位的文字輸入盒中,輸入 UpcomingAppointmentsPage
接著,請將下列 XAML 定義替換掉新建立的 .xaml 檔案內容。
在這個頁面,只有包含 Label 文字標籤 與 Button 按鈕 兩個控制項,因為在 Button 控制項中有定義了 Clicked 事件,因此,需要在 code-behind 內定義該點擊事件該做甚麼事情。

UpcomingAppointmentsPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TabPage2.UpcomingAppointmentsPage"
             Title="Upcoming">

  <ContentPage.Content>
    <StackLayout>
      <Label 
        Text="Upcoming appointments go here" 
        HorizontalOptions="Center" 
        VerticalOptions="CenterAndExpand" />
      <Button 
        Text="Back" 
        Clicked="OnBackButtonClicked"
        VerticalOptions="CenterAndExpand" />
    </StackLayout>
  </ContentPage.Content>

</ContentPage>

UpcomingAppointmentsPage.xaml.cs

請打開 UpcomingAppointmentsPage.xaml 的 code-behind 檔案 UpcomingAppointmentsPage.xaml.cs,並請將下列 C# 程式碼換掉現在內容。
在這個 code-behind 內,按鈕事件只有做一件事情,那就是通知導航頁面 (NavigationPage),返回到上衣個頁面。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace TabPage2
{
    public partial class UpcomingAppointmentsPage : ContentPage
    {
        public UpcomingAppointmentsPage()
        {
            InitializeComponent();
        }

        async void OnBackButtonClicked(object sender, EventArgs e)
        {
            await Navigation.PopAsync();
        }
    }
}

建立 SettingsPage.xaml 頁面

使用滑鼠右擊 核心PCL 專案,從彈出功能表中,點選 加入 > 新增項目;接著,在 加入新項目 - TabPage2 對話窗內,點選 Visual C# > Cross-Platform > Forms Xaml Page,最後,在底下名稱欄位的文字輸入盒中,輸入 SettingsPage
接著,請將下列 XAML 定義替換掉新建立的 .xaml 檔案內容。

SettingsPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TabPage2.SettingsPage"
             Title="Settings">

  <ContentPage.Content>
    <StackLayout>
      <Label 
        Text="Settings go here" 
        HorizontalOptions="Center" 
        VerticalOptions="CenterAndExpand" />
    </StackLayout>
  </ContentPage.Content>

</ContentPage>

執行結果

底下分別來查看在不同平台下,執行這個應用程式所看到的成果是甚麼?

Android 執行結果

請在方案總管內,滑鼠右擊 TabPage2.Droid 專案,選擇 設定為起始專案,接著按下 F5 開始執行。
Android_TabPage2_1
Android_TabPage2_2
Android_TabPage2_3
Android_TabPage2_4

iOS 執行結果

請在方案總管內,滑鼠右擊 TabPage2.iOS 專案,選擇 設定為起始專案,接著按下 F5 開始執行。

參考

沒有留言:

張貼留言