XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2018/04/06

Prism 使用 Unity 在 Xamarin.Forms 中,進行三種注入實作物件練習

了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式

當我們使用 Prism 來開發 Xamarin.Forms 專案的時候,可以選擇不同 DI 容器 Container 的開發框架,不論您選擇的是哪一個,這些 DI 容器都可以支援 1.建構函式注入 Constructor Injection 2. 屬性注入 Property Injection 3. 方法注入 Method Injection ,這三種相依性注入途徑。在這篇文章中,我們將來練習與研究,我們如何使用 Visual Studio 2017 擴充功能的 Prism Template Pack 這個套件所提供的專案樣板,建立起一個 Xamarin.Forms 的專案,接著,我們在這個專案內的 ViewModel 來練習這三種相依性注入的用法,不過,在這裡,我們選擇的 IoC 套件是 Unity。

準備測試環境

  • 首先,我們先要使用 Prism Template Pack 建立一個 Xamarin.Forms 跨平台行動專案
  • 接著,請打開 App.xaml.cs 檔案,依照底下程式碼替換掉
  • 在新的 App.xaml.cs 檔案中,我們建立了兩個介面 IServiceA, IServiceB ,並且使用這兩個介面時做出這兩個類別 ServiceA, ServiceB
  • 為了要能夠讓 Unity IoC 容器可以自動注入 IServiceA, IServiceB 的實作物件,我們在 App.RegisterTypes 方法內,使用 containerRegistry.Register<IServiceA, ServiceA>(); , containerRegistry.Register<IServiceB, ServiceB>(); 敘述,註冊了這兩個介面與具體實作類別間的關係。
C# CSharp
public partial class App : PrismApplication
{
    /* 
     * The Xamarin Forms XAML Previewer in Visual Studio uses System.Activator.CreateInstance.
     * This imposes a limitation in which the App class must have a default constructor. 
     * App(IPlatformInitializer initializer = null) cannot be handled by the Activator.
     */
    public App() : this(null) { }

    public App(IPlatformInitializer initializer) : base(initializer) { }

    protected override async void OnInitialized()
    {
        InitializeComponent();

        await NavigationService.NavigateAsync("NavigationPage/MainPage");
    }

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.RegisterForNavigation<NavigationPage>();
        containerRegistry.RegisterForNavigation<MainPage>();

        containerRegistry.Register<IServiceA, ServiceA>();
        containerRegistry.Register<IServiceB, ServiceB>();
    }
}
public interface IServiceA
{
    string MethodA1();
}

public interface IServiceB
{
    string MethodB1();
}

public class ServiceA : IServiceA
{
    public string MethodA1()
    {
        return "MethodA1() " ;
    }
}

public class ServiceB : IServiceB
{
    public string MethodB1()
    {
        return "MethodB1() ";
    }
}
  • 現在,我們打開 MVVM 中的 View 檢視,也就是 MainPage.xaml 檔案,並且使用底下 XAML 宣告標記,替換到原先檔案內容;在這裡,我們在頁面宣告了三個文字控制項,將分別用來顯示 建構式注入、屬性注入、方法注入後的執行結果。
MainPage
<?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="XFPropInject.Views.MainPage"
             Title="Unity IoC 三種相依性注入用法">

    <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
        <Label Text="{Binding ConstructorInjection}" />
        <Label Text="{Binding PropertyInjection}" />
        <Label Text="{Binding MethodInjection}" />
    </StackLayout>

</ContentPage>
  • 最後,請使用底下 C# 程式碼,將 MainPageViewModel 使用底下程式碼來替換掉
  • 在這裡,_ServiceA 的實作具體物件,將會透過 Unity IoC 的建構式注入方式,將其注入到建構函式內,而到底要由 IoC 幫我們產生哪個具體實作型別物件呢?其實,在上面的步驟中,我們在 App.RegisterTypes 方法內,就有宣告這個介面與具體實作型別間的關聯
  • 另外,_ServiceB 這個介面物件,由於在其 C# 屬性 (Property) 上宣告了 [Dependency] 這個屬性 (Attribute),這個屬性可以參考 DependencyAttribute Class 文件,做進一步的深入了解;因為我們在這個 C# 屬性(Property)上宣告了 [Dependency] 這個屬性 (Attribute),所以,當使用到這個屬性的時候,將會透過屬性注入的方式,來取得這個抽象介面的具體實作物件。
  • 最後一個注入具體實作物件的方式,那就是方法注入,在這裡,我們宣告了一個方法 Initialize(IServiceB serviceMethodB),由於我們在這個方法前面,使用了 [InjectionMethod] 屬性 (Aattribute);更多關於這個屬性的說明,可以參考 InjectionMethodAttribute 文件。因為 Initialize 方法標記了 [InjectionMethod] 屬性 (Aattribute),因此,在 IoC 建立該物件之後,也會執行這個方法,也就是會幫我們注入了 IServiceB 的具體實作物件進來。
C# CSharp
public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
{
    public event PropertyChangedEventHandler PropertyChanged;

    private readonly INavigationService _navigationService;
    public string ConstructorInjection { get; set; }
    public string PropertyInjection { get; set; }
    IServiceA _ServiceA;
    public string MethodInjection { get; set; }
    [Dependency]
    public IServiceB _ServiceB { get; set; }
    [Dependency]
    public IPageDialogService _dialogService { get; set; }
    IServiceB _ServiceMethodB;
    public MainPageViewModel(INavigationService navigationService, IServiceA serviceA)
    {
        _navigationService = navigationService;
        _ServiceA = serviceA;
    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }

    public void OnNavigatingTo(NavigationParameters parameters)
    {
        ConstructorInjection = $"建構式注入 {_ServiceA.MethodA1()} Hash:{_ServiceA.GetHashCode()}";
        PropertyInjection = $"屬性注入 {_ServiceB.MethodB1()} Hash:{_ServiceB.GetHashCode()}";
        MethodInjection = $"方法注入 {_ServiceMethodB.MethodB1()} Hash:{_ServiceMethodB.GetHashCode()}";
        //await _dialogService.DisplayAlertAsync("通知", "完成相依性注入練習", "打完收工");
    }
    public void OnNavigatedTo(NavigationParameters parameters)
    {

    }

    [InjectionMethod]
    public void Initialize(IServiceB serviceMethodB)
    {
        _ServiceMethodB = serviceMethodB;
    }

}

執行結果

  • 下圖為在 Android 模擬器下執行的結果。
  • 其中我們也觀察到了,透過 屬性注入與方法注入的 IServiceB 介面之具體實作物件,並不是同一個。
Unity IoC for Xamarin.Forms

沒有留言:

張貼留言