XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2016/09/02

Xamarin.Forms 啟動初始化之 Splash 頁面

啟動初始化之 Splash 頁面

目的

當在進行 Xamarin.Forms 專案開發的時候,可能會需要在應用程式一開始啟動的時候,進行下載網路資源、取得本機內的資源檔案資訊等相關系統初始化的執行動作,這個時候,您可以建立一個 Splash 頁面,並且設定應用程式一啟動的時候,也就是核心PCL專案的 Xamarin.Forms 的進入點,需要開始顯示這個頁面。
在這個頁面上,可以顯示您的應用程式識別品牌名稱、版本資訊、處理進度,讓使用者可以知道,現在系統正在進行大量的初始化工作。

學習重點

在這個練習專案中,將會讓您學會底下技能與方法的使用:
  • 使用 C# 非同步工作處理方法,避免 UI Thread 被鎖住,造成頁面畫面無法正常更新。
  • 如何變更 Xamarin.Forms 進入點的第一個頁面
  • 使用 Prism 專案樣板,建立第一個 Xamarin.Forms 專案、檢視、檢視模型
  • 學習如何使用 MVVM 設計模型來開發 Xamarin.Forms 應用程式。
  • 如何使用 Unity 結構式相依性注入方式,取得 INavigationService 執行案例物件
  • 如何使用 INavigationService 導航切換頁面
  • 了解與操作 INavigationAware 提供的導航事件
  • 學會如何建立 檢視模型與相關屬性的方法
  • 學習如何在 XAML 內,使用資料繫節來綁定檢視模型內的屬性
  • 如何在 Xamarin.Forms 中使用圖片資源檔案的方法
  • 在 XAML 內,針對不同原生平台,使用 OnPlatform 指定不同屬性值
  • Image 控制項的使用與指定不同平台的來源檔案
  • LayoutOptions 的 XAML 項目(Element)定位用法

專案原始碼

專案使用到的圖片

實作方法

建立專案

  1. 在 Visual Studio 2015,點選功能表 檔案 > 新增 > 專案
  2. 在 新增專案 對話窗內,點選 範本 > Visual C# > Prism > Prism Unity App (Forms)
  3. 在底下名稱欄位中,輸入 XFSplash 最後,點選 確定 按鈕。
    Prism新增專案
  4. 當出現 Prism for Xamarin.Forms - Project Wizard 對話窗,請勾選 AndroidiOSUWP 這三個選項,表示您想要產生使用 Prism 框架的這三種原生 Xamarin.Forms 專案,最後點選 Create 按鈕。
    PrismWizard
當專案建立到一半,若您的開發環境還沒有建置與設定完成 Mac 電腦與 Xamarin Studio for Mac 系統,此時會看到 Xamarin Mac Agent Instructions 對話窗出現,這個對話窗是要提醒您進行與 Mac 電腦連線設定,這是因為,您無法在 Windows 作業系統進行 iOS 相關應用程式的建立與設計工作,而是需要透過 Mac 電腦安裝的 XCode 來協助您完成這些 iOS 應用程式的建立工作。不過,這不影響您繼續開發 Xamarin.Forms 的應用程式,只不過此時,您無法編譯與執行 iOS 的應用程式。
  1. 接著會看到 新的通用Windows專案 對話視窗,此時,您只需要按下 確定 按鈕即可,此時,專案精靈會繼續完成相關平台的專案建立工作。
  2. 最後,整個新的 Xamarin.Forms 專案就建立完成了。
若您無法看到 Prism 項目,用來建立 Prism 類型專案,那可能是您的 Visual Studio 2015 內沒有安裝Prism Template Pack 擴充功能,請參考 附件 : 使用 Visual Studio 2015 增加 Prism 專案樣版
  1. 滑鼠右擊 XFSplash.Droid,選擇 設定為起始專案
  2. 展開 XFSplash.Droid > Properties,滑鼠雙擊 Properties 這個節點
  3. 在標籤頁次 Application,選擇項目 Minimum Android to target的下拉選單,選擇值為 Android 4.4 (API Level 19 - Kit Kat) 這個選項,接著按下 Ctrl + S 組合案件,儲存此次修改設定。
  4. 滑鼠右擊 XFSplash.Droid,選擇 建置 進行專案編譯

開發前準備工作

建立資料夾

複製專案使用的圖片檔案

  1. 請從底下網址取得所要用到的圖片檔案到電腦的硬碟某個目錄下
  2. 使用檔案總管選擇剛剛下載完成的圖檔
  3. 利用檔案總管,拖拉這些圖檔到 Android 專案內的 Resources/drawable 資料夾內
  4. 利用檔案總管,拖拉這些圖檔到 iOS 專案內的 Resources 資料夾內
  5. 利用檔案總管,拖拉這些圖檔到 UWP 專案內的 Assets 資料夾內

專案開發

建立 SplashPage 檢視 (View)

  1. 滑鼠右擊核心PCL專案的 Views 資料夾,選擇 加入 > 新增項目
  2. 在對話窗點選 Visual C# > Prism > Prism ContentPage (Forms)
  3. 在名稱欄位輸入 SplashPage,接著點選 新增 按鈕
  4. 將底下 XAML 標記宣告複製到剛剛建立的檔案內

SplashPage.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"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFSplash.Views.SplashPage">

  <ContentPage.Padding>
    <OnPlatform
      x:TypeArguments="Thickness"
      iOS="0,20,0,0"
      Android="0"
      WinPhone="0,0"
      />
  </ContentPage.Padding>

  <Grid
    >
    <Image
      Aspect="AspectFill"
      >
      <Image.Source>
        <OnPlatform
          x:TypeArguments="ImageSource"
          iOS="SplashBG.jpg"
          Android="SplashBG.jpg"
          WinPhone="Assets/SplashBG.jpg"
          />
      </Image.Source>
    </Image>

    <Grid
      Margin="20,50,20,30"
      >
      <Grid.RowDefinitions>
        <RowDefinition Height="200"/>
        <RowDefinition Height="50" />
        <RowDefinition Height="*" />
        <RowDefinition Height="50" />
      </Grid.RowDefinitions>
      <Label
        Grid.Row="0" Grid.Column="0"
        Text="多奇創意行動應用"
        TextColor="White"
        FontSize="40"
        Opacity="0.3"
        HorizontalOptions="Center" VerticalOptions="Center"
        />
      <ProgressBar
        Grid.Row="1" Grid.Column="0"
        Progress="{Binding 處理進度百分比, Mode=TwoWay}"
      />
      <Label
        Grid.Row="2" Grid.Column="0"
        HorizontalOptions="Center" VerticalOptions="Start"
        Text="{Binding 處理訊息, Mode=TwoWay}"
        TextColor="White"
        FontSize="20"
        LineBreakMode="TailTruncation"
        />
      <Label
        Grid.Row="3" Grid.Column="0"
        HorizontalOptions="End" VerticalOptions="Start"
        Margin="0,0,0,0"
        Text="{Binding 版本資訊, Mode=TwoWay}"
        TextColor="Yellow"
      />
    </Grid>
  </Grid>
</ContentPage>

建立 SplashPageViewModel 檢視模型 (ViewModel)

  1. 滑鼠右擊核心PCL專案的 ViewModels 資料夾,選擇 加入 > 新增項目
  2. 在對話窗點選 Visual C# > Prism > Prism ViewModel
  3. 在名稱欄位輸入 SplashPageViewModel,接著點選 新增 按鈕
  4. 將底下 C# 程式碼複製到剛剛建立的檔案內

SplashPageViewModel.cs

using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace XFSplash.ViewModels
{
    public class SplashPageViewModel : BindableBase, INavigationAware
    {
        #region Field
        INavigationService _navigationService;
        #endregion

        #region ViewModel Property

        #region 處理訊息
        private string _處理訊息 = "系統執行中...";

        public string 處理訊息
        {
            get { return _處理訊息; }
            set { SetProperty(ref _處理訊息, value); }
        }
        #endregion

        #region 處理進度百分比
        private double _處理進度百分比 = 0;

        public double 處理進度百分比
        {
            get { return _處理進度百分比; }
            set { SetProperty(ref _處理進度百分比, value); }
        }
        #endregion

        #region 版本資訊
        private string _版本資訊 = "版本:1.2.4";

        public string 版本資訊
        {
            get { return _版本資訊; }
            set { SetProperty(ref _版本資訊, value); }
        }

        #endregion

        #endregion

        public SplashPageViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {
        }

        public async void OnNavigatedTo(NavigationParameters parameters)
        {
            await 系統初始化();
        }

        private async Task 系統初始化()
        {
            double fooPer = 0.0;
            await Task.Delay(800);
            for (int i = 0; i < 101; i++)
            {
                fooPer = i / 100.0;
                處理進度百分比 = fooPer;
                if (i < 40)
                {
                    處理訊息 = "讀取本機資源中,請稍後";
                    await Task.Delay(170);
                }
                else if (i < 90)
                {
                    處理訊息 = "更新網路上最新資源";
                    await Task.Delay(30);
                }
                else
                {
                    處理訊息 = "即將完成";
                    await Task.Delay(120);
                }
            }

            處理訊息 = "導航到首頁頁面";
            await _navigationService.NavigateAsync("MainPage?title=恭喜您,已經完成 Splash 練習");
        }
    }
}

修改 MainPage.xaml 檢視

  1. 開啟核心PCL專案內的 MainPage.xaml 檔案
  2. 將底下 XAML 標記宣告內容,覆蓋掉剛剛開啟的檔案

MainPage.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"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFSplash.Views.MainPage"
             Title="MainPage">
  <Grid>
    <Image
      Aspect="AspectFill"
      >
      <Image.Source>
        <OnPlatform
          x:TypeArguments="ImageSource"
          iOS="MainPageImg.jpg"
          Android="MainPageImg.jpg"
          WinPhone="Assets/MainPageImg.jpg"
          />
      </Image.Source>
    </Image>

    <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
      <Label Text="{Binding Title}" FontSize="30"
             HorizontalTextAlignment="Center"
             TextColor="#a64dff"
             />
    </StackLayout>
  </Grid>
</ContentPage>

修正進入點與註冊檢視

  1. 開啟核心PCL專案內的 App.xaml.cs
  2. 將底下 C# 程式碼覆蓋掉剛剛開啟的檔案

App.xaml.cs

using Prism.Unity;
using XFSplash.Views;

namespace XFSplash
{
    public partial class App : PrismApplication
    {
        public App(IPlatformInitializer initializer = null) : base(initializer) { }

        protected override void OnInitialized()
        {
            InitializeComponent();

            NavigationService.NavigateAsync("SplashPage");
        }

        protected override void RegisterTypes()
        {
            Container.RegisterTypeForNavigation<MainPage>();
            Container.RegisterTypeForNavigation<SplashPage>();
        }
    }
}

三個平台的執行結果螢幕截圖

Android

chapter01A1 chapter01A2

iOS

chapter01A1 chapter01A2

UWP

chapter01A1 chapter01A2

2016/09/01

Xamarin XAML 資源字典的繼承說明

XAML 資源字典的繼承說明

在這份筆記,將會記錄下 XAML 資源字典內的資源項目,在不同 視覺項目 (Visual Element) 內的繼承與覆蓋議題。

參考專案

執行畫面

資源字典的繼承說明

全域資源 App.xaml

在這個專案中,使用了 App.xaml 定義了一個全域的樣式 StyleForLabel;其定義了 Label 的 Text, TextColor, FontSize, VerticalOptions, HorizontalOptions 的屬性預設值。

App.xaml

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ElementTree.App">
  <Application.Resources>
    <ResourceDictionary>
      <Style x:Key="StyleForLabel" TargetType="Label">
        <Setter Property="Text" Value="App 資源字典" />
        <Setter Property="TextColor" Value="Blue" />
        <Setter Property="FontSize" Value="32" />
        <Setter Property="VerticalOptions" Value="Center" />
        <Setter Property="HorizontalOptions" Value="Center" />
      </Style>
    </ResourceDictionary>
  </Application.Resources>
</Application>

頁面中的相關資源字典定義

每個在 XAML 內的視覺項目 Visual Element 都可以定義資源字典,在同樣的資源字典內,其 x:Key 名稱是不能夠重複的;不過,在不同的視覺項目內的資源字典,卻可以定義同樣的資源名稱;另外,只要是在同一個視覺樹(Visual Tree)下,最上層定義的資源項目,是可以在底下階層的視覺項目直接來引用。
在這個頁面內,並沒有定義 ContentPage 的資源字典,並且所有的 Label 控制項,都使用同樣的 Style 靜態參考 StaticResource StyleForLabel; 而在第一個 Label 控制項中,將會採用全域資源中的資源項目。
第二個 Label 控制項目,將會使用上層 StackLayour 內資源字典定義的資源項目。
第三個 Label 控制項目,將會使用本身資源字典定義的資源項目。

MainPage.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"
             xmlns:local="clr-namespace:ElementTree"
             x:Class="ElementTree.MainPage">

  <StackLayout
    Orientation="Vertical"
    VerticalOptions="Center"
    >
    <Label Style="{StaticResource StyleForLabel}"/>
    <StackLayout
      Orientation="Vertical">
      <StackLayout.Resources>
        <ResourceDictionary>
          <Style x:Key="StyleForLabel" TargetType="Label">
            <Setter Property="Text" Value="StackLayour 資源字典" />
            <Setter Property="TextColor" Value="Red" />
            <Setter Property="FontSize" Value="18" />
            <Setter Property="VerticalOptions" Value="Center" />
            <Setter Property="HorizontalOptions" Value="Center" />
          </Style>
        </ResourceDictionary>
      </StackLayout.Resources>
      <Label Style="{StaticResource StyleForLabel}" />
      <Label Style="{StaticResource StyleForLabel}" >
        <Label.Resources>
          <ResourceDictionary>
            <Style x:Key="StyleForLabel" TargetType="Label">
              <Setter Property="Text" Value="Label 資源字典" />
              <Setter Property="TextColor" Value="Green" />
              <Setter Property="FontSize" Value="24" />
              <Setter Property="VerticalOptions" Value="Center" />
              <Setter Property="HorizontalOptions" Value="Center" />
            </Style>
          </ResourceDictionary>
        </Label.Resources>
      </Label>
    </StackLayout>
  </StackLayout>

</ContentPage>