XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2019/11/04

Xamarin.Forms 客製化導航服務 Navigation Service 與檢視模型定位器 ViewModel Locator

Xamarin.Forms 客製化導航服務 Navigation Service 與檢視模型定位器 ViewModel Locator

該文件的專案原始碼可以透過 GitHub 來取得

設定 MyGet 的可用套件來源

現在,已經把 檢視模型定位器 ViewModel Locator 與 客製化的導航服務推送到 MyGet 站台上,因此,可以透過底下方式是,來安裝這個 NuGet 套件
  • 點選 Visual Studio 2019 功能表 [工具] > [選項]
  • 當 [選項] 對話出現的時候,從左邊清單選項找到 [NuGet 套件管理員]
  • 在左方 [名稱] 欄位中輸入適當的名字,這裡將會輸入 上課練習或者體驗專案會使用到的常用功能
  • 在左方 [來源] 欄位中輸入 [上課練習或者體驗專案會使用到的常用功能](https://www.myget.org/F/course-lab/api/v3/index.json) 這個 URL
  • 點選 [更新] 按鈕
    )
  • 記得要確認 [可用套件來源] 選項中,剛剛建立的套件來源項目有被勾選
現在可以建立一個練習測試用的專案

建立測試用的專案

  • 請啟動 Visual Studio 2019
  • 在啟動後的對話窗內,選擇右下方的 [建立新的專案] 選項
  • 當顯示出 [建立新專案] 對話窗,請在中間上方的文字輸入盒內,輸入 Xamarin 這個關鍵字
  • 此時將會在中間清單區域,找到 [行動應用程式 (Xamarin.Forms)] 這個選項,請點選這個項目
  • 在 [設定新的專案] 對話窗內,請在專案名稱欄位內,輸入 CustNaviService
  • 請點選右下方的 [建立] 按鈕
  • 現在將會跳出一個 [New Cross Platform App - CustNaviService] 對話窗
  • 請選擇 選取範本 區域內的 [空白] 項目
  • 在下方的 [平台] 區域,請記得勾選 Android , iOS , Windows (UWP) 這三個檢查盒 Checkbox
  • 點選右下方的 [OK] 按鈕
  • 開始建立 Xamarin.Forms 開發方案

加入 檢視模型定位器 ViewModel Locator 與 客製化的導航服務 套件

  • 滑鼠右擊 CustNaviService 核心專案節點
  • 選擇管理 NuGet 套件選項
  • 當 [NuGet: CustNaviService] 視窗 出現後,請在右上方的 [套件來源] 下拉選單中,選擇 [上課練習或者體驗專案會使用到的常用功能] 這個項目
  • 在 [NuGet: CustNaviService] 視窗中,點選瀏覽頁次
    )
  • 現在將會看到這裡擁有兩個 NuGet 套件,請選擇 [Vulcan.Courses.XamarinForms] 這個套件
    )
  • 點選 [安裝] 按鈕,安裝這個套件到核心專案內

使用 MVVM 命名慣例來建立所需要用到的方案資料夾

  • 滑鼠右擊 CustNaviService 核心專案節點
  • 選擇 [加入] > [新增資料夾] 選項
  • 請輸入 ViewModels 這個文字做為該資料夾的名稱
  • 滑鼠右擊 CustNaviService 核心專案節點
  • 選擇 [加入] > [新增資料夾] 選項
  • 請輸入 Views 這個文字做為該資料夾的名稱

建立導航頁面 NavigationPage 與導航抽屜頁面 MasterDetailPage

這裡需要先建立起這兩個頁面,因此,請在 [Views] 資料夾內,建立這兩種類型的頁面
在這裡將會建立一個名為 NaviPage 的導航頁面
在這裡將會建立一個名為 MDPage 的導航頁面

建立會用到的其他內容頁面 ContentPage 與 相對應的 檢視模型 ViewModel 類別

請在 [Views] 資料夾內,建立 HomePage AboutPage LoginPage 這三個頁面
請在 [ViewModels] 資料夾內,建立 HomePageViewModel AboutPageViewModel LoginPageViewModel MDPageViewModel MDPageMasterViewModel 這五個檢視模型類別
最後完成的結果如底下螢幕截圖
)

使用 檢視模型定位器 ViewModel Locator

想要使用這項服務,對於頁面 ( 檢視 ) 檔案 與 檢視模型 檔案,需要遵守底下的命名慣例
  • 對於 頁面 ( 檢視 View ) 的 XAML 文件檔案,需要建立在 Views 這個方案資料夾內
  • 每個頁面檔案名稱,最後需要使用 Page 作為結為,例如,這裡有建立一個 HomePage.xaml 這樣的 XAML 頁面文件檔案
接著,需要在每個頁面中,建立一個命名空間,這個命名空間要指向 服務定位器所在的 .NET 命名空間內 Namespace
在底下的 XAML 文件中,將會使用 xmlns 來宣告一個新的 viewmodelLocator 命名空間,其中, viewmodelLocator 稱之為 前置詞 prefix
有了這個前置詞,就可以使用 AutoWireViewModel 這個附加屬性,依據所規範的命名慣例,自動找出該頁面所匹配的檢視模型,當然,該檢視模型將會位於該專案的 ViewModel 方案資料夾內。
xmlns:viewmodelLocator="clr-namespace:Vulcan.Courses.XamarinForms.NaviServices;assembly=Vulcan.Courses.XamarinForms"
viewmodelLocator:ViewModelLocator.AutoWireViewModel="True"

使用 客製化導航服務

為了要能夠使用這裡所設計的 客製化導航服務,每個檢視模型 ViewModel 類別,需要繼承 ViewModelBase 這個基底類別,該類別是在之前所安裝的 NuGet 內所定義的。
另外,還需要在每個檢視模型類別的建構函式內,呼叫基底類別的建構函式,這裡需要傳入一個導航服務物件。不過,這裡的導航服務物件將會位於此 Xamarin.Forms 專案內的程式進入點,也就是在 App 這個類別內有宣告,稍後,將會交代如何做這一的設計。
從底下的範例程式碼可以看出,透過 Application.Current 這個靜態變數,取得了一個 App 型別的物件,就可以取出 NavigationService 這個變數物件值。
public class AboutPageViewModel : ViewModelBase
{
    public AboutPageViewModel() : base((Application.Current as App).NavigationService)
    {
    }
}
現在,請打開 App.xaml.cs 這個檔案節點,在 App 這個類別內,加入一個公開屬性 public INaviService NavigationService { get; set; } ,接著在該 App 類別的建構函式內,建立 NavigationService 這個物件,這裡使用了 NavigationService = new NaviService( () => { return Application.Current.MainPage as NaviPage; }, page => { return new NaviPage(page); }, () => { return (Application.Current.MainPage as MDPage)?.Detail as NaviPage; }, () => { return Application.Current.MainPage as MDPage; }, () => { return new MDPage(); });
對於 NaviService 的建構函式,將會需要傳遞五個委派方法,分別是要取得導航頁面的委派方法、產生一個新的導航頁面的委派方法、取得一個導航抽屜頁面+導航頁面的委派方法、取得一個導航抽屜的委派方法、產生一個導航抽屜的委派方法;所以,請將上面的所列的表示式,放到這個 App 類別內的建構函式內即可。
在這個 App 類別內的建構函式,將會看到如何使用客製化導航服務的頁面導航的程式設計程式碼,NavigationService.NavigateToAsync<LoginPageViewModel>(NavigateMode.Absolute); ;這裡將會需要使用 NavigateToAsync 這個泛型方法,在泛型型別參數內,指定要導航過去的檢視模型型別名稱即可,而在這個方法內,可以指定一個導航模式,也就是 NavigateMode 這裡列舉型別。這裡使用到了 NavigateMode.Absolute 這個列舉值,表示將會使用沒有導航頁面的模式,切換到指定的內容頁面上。
public partial class App : Application
{
    public INaviService NavigationService { get; set; }
    public App()
    {
        InitializeComponent();

        NavigationService = new NaviService(
            () => { return Application.Current.MainPage as NaviPage; },
            page => { return new NaviPage(page); },
            () => { return (Application.Current.MainPage as MDPage)?.Detail as NaviPage; },
            () => { return Application.Current.MainPage as MDPage; },
            () => { return new MDPage(); });

        //MainPage = new MainPage();

        NavigationService.NavigateToAsync<LoginPageViewModel>(NavigateMode.Absolute);
    }

    protected override void OnStart()
    {
        // Handle when your app starts
    }

    protected override void OnSleep()
    {
        // Handle when your app sleeps
    }

    protected override void OnResume()
    {
        // Handle when your app resumes
    }
}

其他的頁面導航操作

若想要使用具有導航頁面的模式的頁面,可以使用 NavigationService.NavigateToAsync<LoginPageViewModel>(NavigateMode.Absolute); 這樣的用法
而要使用具有導航抽屜的頁面模式(一定會使用到導航頁面),可以使用 NavigationService.NavigateToAsync<HomePageViewModel>(NavigateMode.Master);
若在導航抽屜頁面下,想要切換到僅有導航頁面(沒有抽屜)的模式下,可以使用 NavigationService.NavigateToAsync<LoginPageViewModel>(NavigateMode.RestartRelative);

實際執行結果

底下是應用程式一起動要顯示的頁面,沒有任何導航頁面與導航抽屜頁面,這裡是使用 NavigationService.NavigateToAsync<LoginPageViewModel>(NavigateMode.Absolute);
)
當在上面畫面點選了 [登入] 按鈕,出現底下畫面(有導航抽屜),這裡使用的是 NavigationService.NavigateToAsync<HomePageViewModel>(NavigateMode.Master);
)
在 [首頁] 頁面下方,點選 [關於] 按鈕,將會使用導航頁面功能,切換到關於頁面,這裡使用的是 NavigationService.NavigateToAsync<AboutPageViewModel>();
)
在關於頁面左上方,將會看到一個箭頭,這表示現在這個頁面在導航堆疊結構中,前面至少還有一個頁面,此時,點選左上方箭頭(或者點選下方實體回上頁按鈕),便可以回到上一頁頁面。
)
在 [關於] 頁面內,從裝置外部左方往右滑動,將會看到導航抽屜出現,這裡的 Page 1 ~ Page 4 都會有建置功能,可以分批測試看看。
首先點選 Page 1,將會直接回到 [首頁] 頁面, 並且清空導航堆疊內的所有頁面,這裡使用的是 NavigationService.NavigateToAsync<HomePageViewModel>(NavigateMode.Master);
)
再度滑出導航抽屜,點選 Page 2,將會直接回到 [關於] 頁面, 並且清空導航堆疊內的所有頁面,這裡使用的是 NavigationService.NavigateToAsync<AboutPageViewModel>(NavigateMode.Master);
)
滑出導航抽屜,點選 Page 3,將會直接回到 [登入] 頁面,此時沒有導航抽屜頁面,也沒有導航頁面的存在,這裡使用的是 NavigationService.NavigateToAsync<LoginPageViewModel>(NavigateMode.Absolute);
)
請點選 [登入] 按鈕,進入到有導航抽屜頁面的首頁內,滑出導航抽屜,點選 Page 4,將進入到 [登入] 頁面,不過,此時沒有導航抽屜頁面,但卻有導航頁面的存在,這裡使用的是 NavigationService.NavigateToAsync<LoginPageViewModel>(NavigateMode.RestartRelative);
)







沒有留言:

張貼留言