XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2016/06/30

Xamarin.Forms Hello World

這是這本書的第一個範例程式,也是大部分電腦程式語言或者開發工具第一個會介紹要做出的程式,那就是:您好 Hello。這個專案會讓您透過文字輸入盒,讓您輸入您的名字,接著會有一個按鈕,當您按下了這個按鈕,螢幕會顯示出這段文字 您的名字 您好,這段文字。
在這個實作範例展示過程,除了告訴您,當要使用 C# 配合 Xamarin.Forms Toolkit 來進行行動裝置跨平台應用程式開發,會經歷過哪些步驟,也會向您說明您應該、必須要知道的一些事情。

開始建立新的專案

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

建立的相關專案檢視

當新專案確定建立完成後,您可以從 方案總管 視窗中,看到專案精靈已經為您建立了總共6個專案,這別是:
  • HelloBlankXamlApp.Droid
    這個專案為 Android 應用程式使用的專案
  • HelloBlankXamlApp.iOS
    這個專案為 iOS 應用程式使用的專案
  • HelloBlankXamlApp.UWP
    這個專案為 Windows Universal Platform 應用程式使用的專案
  • HelloBlankXamlApp.Windows
    這個專案為 Windows 8.1 for WinRT 應用程式使用的專案
  • HelloBlankXamlApp.WinPhone
    這個專案為 Windows Phone 8.1 應用程式使用的專案
  • HelloBlankXamlApp
    這個專案是最為重要的核心,也是一個 PCL (Portable Class Library),所有的 Xamarin.Forms 的 UI 定義與商業邏輯程式碼,都會定義在這個專案內。
原則上,當在進行 Xamarin.Forms 跨平台裝置應用程式專案開發的時候,絕大部分的時間都會專注在 PCL 這個核心專案上,您需要在這個專案內定義各個手機頁面,透過 View Model 來進行商業邏輯程式碼的撰寫;當您需要建立個行動裝置平台要用的安裝檔案、需要使用個平台專屬的部分功能的時候,才會用到各個行動裝置的專案。

檢視 Android 專案

首先,先來檢視 Android 專案,看看在 Android 專案中,整個 Xamarin.Forms 的系統如何串接與運作的。
在方案總管中,展開 HelloBlankXamlApp.Droid 專案結構,如下圖所示,您可以看到這個專案就與 Xamarin.Android 類型的專案一樣,您可以在 Resource目錄下定義各種 Android 平台中會用到的各種資源。
Xamarin.Forms 的應用程式開發,其觀念非常的簡單,那就是,每個行動裝置平台,都會擁有一個專案,例如,在這個範例中,Android平台,會有一個 HelloBlankXamlApp.Droid,而 iOS平台,則會有一個HelloBlankXamlApp.iOS。每個行動裝置平台的專案都會參考到核心PCL專案,也就是HelloBlankXamlApp,您會在該專案內,透過 XAML 或者C#程式語言來定義各種不同的手機頁面。
通常,我們會將每個頁面要出現哪些內容,使用 XAML 宣告式語言來描述,我們稱作 View,接著,會定義另外一個類別,將這個頁面的商業邏輯行為與頁面互動的動作或者要讀取外部的資料,皆會在這個類別中定義出來。之後,就會透過 MVVM (Model, View, View Model)這個技術框架,將 View 與 View Model 整合在一起,若在頁面中需要顯示各項 View Model 內的資料,需要透過資料繫結的方式,將 View 的某個視覺元件的某個屬性與 View Model 內的某個屬性進行綁定,如此,當View Model 內的資料變動的時候,View 內的視覺元件屬性值,也會隨之變動;當然,您也可以做到當 View 內視覺元件的屬性值有變動的時候,可以讓 View Model 內已經綁定的屬性值也隨之變動。
這樣的開發方式,就是MVVM ,在使用 MVVM框架架構下開發的時候,View Model 不需要知道他是與哪個 View 會結合再一起,我們只需要在 View 中,描述需要進行資料綁定的路徑;這樣在執行時期,系統就會自動依據資料綁定的定義,進行資料更新;另外,當我們需要定某個 UI 元件互動事件的時候,以往是需要透過 Code Behind 的方式,這些事件定義在該 View,也就是該 Xaml 類型檔案的 Code Behind .cs 檔案內,由於採用了 MVVM 方式開發,現在就不需要這樣做了,我們可以將所有這樣的需求全部轉移到 View Model 內。更多關於 MVVM 的應用與觀念,會在其他範例中進行深入介紹。
讓我們回到 HelloBlankXamlApp.Droid 專案,在這個專案內,您會看到這個專案內只有一個 Activity類別檔案,其實,這就是 Xamarin.Forms 的 Android 應用程式地進入點,打開該檔案來檢視一下這個 Activity 做了哪些事情。
namespace HelloBlankXamlApp.Droid
{
    // 定義這個 Android 應用程式主要行為與應用程式圖示
    [Activity(Label = "HelloBlankXamlApp", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(bundle);

            // 從這裡開始,所有的手機畫面與互動,皆會透過 核心PCL (`HelloBlankXamlApp.Droid`) 來運行,
            // 也就是,都會使用 Xamarin.Forms 的框架來執行
            global::Xamarin.Forms.Forms.Init(this, bundle);
            // 載入定義在 核心PCL 內的主要進入點物件,將生命週期交給 Xamarin.Forms
            LoadApplication(new App());
        }
    }
}
在這個 MainActivity.cs 類別定義中,首先看到底下關於這個類別的宣告與相關屬性使用。
// 定義這個 Android 應用程式主要行為與應用程式圖示
    [Activity(Label = "HelloBlankXamlApp", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity

Android Activity 的屬性(Attribute)

在這個 Activity 中,使用了 ActivityAttribute 這個客製化屬性來描述予宣告 Activity 在應用程式中要如何建置其視覺介面,另外, ActivityAttribute 這個客製化屬性也會更新 AndroidMainfest.xml 這個檔案內容,例如,當我們想要讓這個 Android 應用程式可以存取 GPS,拍照鏡頭等使用能力,透過這樣的宣告,使得不再需要去修改 AndroidMainfest.xml 這個檔案,而直接在這裡定義即可。
在這個範例中,ActivityAttribute使用到了 LabelIconTheme, 'MainLauncher', 'ConfigurationChanges' 這些個屬性。
  • Label 屬性
    用於宣告這個 Activity 的名稱
  • Icon 屬性
    用於宣告這個 Activity 表示用的圖示稱(這個名稱用能夠存在於 Resources 內)
  • Theme 屬性
    用於宣告這個 Activity 所要參考的布景配置資源名稱
  • MainLauncher 屬性
    用於宣告這個 Activity 是否為當應用程式啟動之後,第一個要顯示的畫面,在這裡,一定要定義為 true
  • ConfigurationChanges 屬性
    用於宣告這個 Activity 當 Configuration 行為有變動的時候,這個 Activity 會自己處理這些相關事件;在這個範例中,定義了,當螢幕的尺寸有所異動、螢幕有轉向的時候,這個 Activity 會來處理這些事件,也就是說,可以在 Xamarin.Forms 內處理這些異動事件。

Android Activity 的建構式

這建構式非常的簡單,當執行這個建構式之後,就會把整個程式的執行與運作權利,轉交給 Xamarin.Forms 來處理,也就是說,接下來要顯示哪個畫面、每個畫面要顯示那些 UI、這些 UI 若接收到不同的手勢操作又該由哪些相對應的事件來處理等等需求,都可以直接在 核心PCL 並且使用 Xamarin.Forms 所提供的各樣功能來完成;您也可以視為,當您進行 Xamarin.Forms 程式開發的時候,原則上,您不再需要來用到這個專案 (HelloBlankXamlApp.Droid)。
雖然這個建構式裡面只有幾行程式碼,特別看到這個建構式的有下列程式碼:
            // 從這裡開始,所有的手機畫面與互動,皆會透過 核心PCL (`HelloBlankXamlApp.Droid`) 來運行,
            // 也就是,都會使用 Xamarin.Forms 的框架來執行
            global::Xamarin.Forms.Forms.Init(this, bundle);
            // 載入定義在 核心PCL 內的主要進入點物件,將生命週期交給 Xamarin.Forms
            LoadApplication(new App());
global::Xamarin.Forms.Forms.Init(this, bundle); 是進行 Xamarin.Forms 初始化工作。
LoadApplication(new App()); 則是使用 核心PCL 裡面定義的一個 Xamarin.Forms 進入點類別 (App),由這個專案載入這個物件,接著,就將執行控制權交給 Xamarin.Forms 來執行。
其中, golbal:: 這個是 C# 的 全域命名空間(global namespace)別名,讓您可以能夠存取全域命名空間(global namespace) 中的成員會十分有用,尤其是該成員可能會被其他同名的實體隱藏的時候。

Android Activity 的屬性(Attribute) 進一步了解

更多關於 Android Activity 的屬性定義,請參考官方網站https://developer.xamarin.com/api/type/Android.App.ActivityAttribute/

核心PCL

接下來就來研究 Xamarin.Forms 的核心PCL專案,並且了解上一段落提到的 Xamarin.Forms 進入點類別App 做了哪些事情,以及要如何透過 Xamarin.Forms 提供的 XAML 宣告語言來定義出這個專案需要的相關介面與功能。
打開 HelloBlankXamlApp 核心 PCL 專案,其相關成員如下圖所示:
從上圖,可以觀察到,這個專案擁有一個 App.Xaml 與 MainPage.Xaml 這兩個檔案,前者是各個行動裝置平台專案的 Xamarin.Forms 的進入點類別,後者是第一個要看到的畫面 XAML 定義檔案。
下列為 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="HelloBlankXamlApp.App">
  <Application.Resources>

    <!-- Application resource dictionary -->

  </Application.Resources>
</Application>
下列為 App.c# Code Behind 檔案內容。 這個 App 類別的 Code Behind .cs 檔案,定義了一個HelloBlankXamlApp.MainPage 物件,並且將它設定給 App 類別繼承的 Application 類別中的 MainPage 屬性,這表示當這個應用程式一啟動之後,第一個要顯示的畫面,就是使用 MainPage 這個類別中所定義的相關內容。
在這個遊專案樣板所產生的 App 類別中,有著 OnStartOnSleepOnResume 這三個方法,這三個方法將會用於處理 Xamarin.Forms 的應用程式整體生命週期相關事件。您可以依照您的應用程式需求,自行在這三個方法中加入更多的控制與處理功能,例如,當應用程式切換到背景模式的時候,需要把相關應用程式執行的狀態值,先儲存起來,而在回到前景模式的時候,可以把這些狀態值讀取出來,並且回覆到相關視覺控制項上。
  • OnStart
    當應用程式啟動的時候,會呼叫這個方法。
  • OnSleep
    每次當應用程式進入到背景情境的時候,都會呼叫這個方法。
  • OnResume
    當應用程式從背景情境,切換到前景情境下,要繼續執行的時候,會呼叫這個方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Xamarin.Forms;

namespace HelloBlankXamlApp
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();

            MainPage = new HelloBlankXamlApp.MainPage();
        }

        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
        }
    }
}
想要知道這三個方法,在不同的情況下的呼叫順序為和,可以加入底下程式碼,並且執行與操作不同情境,查看 Visual Studio 的輸出頁面的相關訊息輸出。
protected override void OnStart()
{
    Debug.WriteLine ("OnStart");
}
protected override void OnSleep()
{
    Debug.WriteLine ("OnSleep");
}
protected override void OnResume()
{
    Debug.WriteLine ("OnResume");
}
接著,進入到這個應用程式的第一個畫面的設計情境,打開核心PCL專案內的 MainPage.xaml & MainPage.cs 這兩檔案。
在 MainPage.xaml 檔案內,定義了根節點,是個 ContentPage 這個元素(Element),在這個根結點裡面,定義了一個 Label 控制項,用來顯示一段文字,並且該 Label 控制項是會水平與垂直採用置中對齊的方式來排列。
<?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:HelloBlankXamlApp"
             x:Class="HelloBlankXamlApp.MainPage">

  <Label Text="Welcome to Xamarin Forms!"
           VerticalOptions="Center"
           HorizontalOptions="Center" />

</ContentPage>
在 MainPage.cs 這個 Code Behind 檔案內,只有一個建構式方法,並且在這個建構式方法內,呼叫了InitializeComponent() 方法,這個方法會將 MainPage.xaml 檔案內的相關 XAML 宣告定義,使用 C# 程式語言產生相對應的物件,並且進行初始化。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace HelloBlankXamlApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
    }
}

開始在模擬器中執行 Android 專案

請使用滑鼠右擊方案總管的 HelloBlankXamlApp.Droid 專案,在彈出功能表選擇 設定為起始專案 這個選項,接著,按下 F5 按鍵,進行該專案的執行工作。
這個專案將會在 4.7" KiKat (4.4) XHDPI Phone (Android 4.4 - API 19) Visual Studio 模擬器上進行執行。想要知道 如何建立 Visual Stdio for Android的模擬器 ,請參考後面 如何建立 Visual Stdio for Android的模擬器 小節說明。
下圖是實際在 Visual Studio for Android 模擬器上執行結果的螢幕截圖。

檢視 iOS 專案

在檢視完 Android 專案並且順利執行該專案之後,接下來了解 iOS的專案組成方式。
在方案總管中,展開 HelloBlankXamlApp.iOS 專案結構,如下圖所示
在這個 iOS 專案內,有兩個檔案,需要來查看一下,那就是 Main.cs 與 ApDelegate.cs
打開 Main.cs 檔案,其內容會如下所示:
這個檔案為 iOS 應用程式的進入點,也就是 iOS 的程式會從這個地方開始執行;這個 Application 類別中,只有一個 Main 方法,該方法裡面只有一行,那就是呼叫 UIApplication.Main(args, null, "AppDelegate"); 方法,這個方法會產生一個 AppDelegate 物件類別,透過這個物件,開始進行進入到 Xamarin.Forms 的生命週期循環。
using System;
using System.Collections.Generic;
using System.Linq;

using Foundation;
using UIKit;

namespace HelloBlankXamlApp.iOS
{
    public class Application
    {
        // This is the main entry point of the application.
        static void Main(string[] args)
        {
            // if you want to use a different Application Delegate class from "AppDelegate"
            // you can specify it here.
            UIApplication.Main(args, null, "AppDelegate");
        }
    }
}
打開 AppDelegate.cs 檔案,其程式碼如下:
在 AppDelegate 繼承了 類別 Xamarin.Forms.Platform.iOS.FormsApplicationDelegate;在FinishedLaunching 方法內,執行了 `Xamarin.Forms.Forms.Init() 方法,進行 Xamarin.Forms的初始化(當然,在連結的時候,也會將 Xamarin.Forms 的組件(Assembly)連結到最終應用程式執行檔案內),而後,將 核心PCL 的 Xamarin.Forms 進入點類別產生一個物件,並且開始執行 Xamarin.Forms 的相關生命週期程序與功能。
using System;
using System.Collections.Generic;
using System.Linq;

using Foundation;
using UIKit;

namespace HelloBlankXamlApp.iOS
{
    // The UIApplicationDelegate for the application. This class is responsible for launching the 
    // User Interface of the application, as well as listening (and optionally responding) to 
    // application events from iOS.
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        //
        // This method is invoked when the application has loaded and is ready to run. In this 
        // method you should instantiate the window, load the UI into it and then make the window
        // visible.
        //
        // You have 17 seconds to return from this method, or iOS will terminate your application.
        //
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }
    }
}

建立與 Mac 電腦的連線

想要開發 iOS 的應用程式,您需要準備一台 Mac 電腦,裡面要安裝最新版本的 XCode & Xamarin Studio。
接著,在Visual Studio這裡,請在 Visual Studio 功能表中選擇 工具 > iOS > Xamarin Mac Agent 這個選項。
當出現了 Xamarin Mac Agent 對話窗之後,點選中間的 Add Mac... 按鈕,準備開始進行建立與 Mac 連線的資訊。
在出現的 Add Mac 對話窗中,輸入您的 Mac 電腦當時擁有的 IP 位置,輸入完成後,點選下方 Add按鈕。
接著出現了 Connect to Mac 對話窗,請輸入需要登入 Mac 電腦的帳號與密碼後,滑鼠右擊 Login 按鈕。這個時候 Xamarin Mac Agent會開始嘗試與遠端 Mac 電腦連線,一旦帳號與密碼正確且登入成功,就會出現如下圖的畫面。

開始在模擬器中執行 iOS 專案

請使用滑鼠右擊方案總管的 HelloBlankXamlApp.iOS 專案,在彈出功能表選擇 設定為起始專案 這個選項。
此時,Visual Studio 的工具列會變成如下圖,在這裡選擇了 iPhone 6s iOS 9.3 這個模擬器做為執行測試之用。
下圖是實際在 iOS 模擬器上執行的結果。

編輯 XAML 檔案與 IntelliSense

根據微軟官方對於 IntelliSense 的定義
IntelliSense 是一些功能的概括詞彙:列出成員、參數資訊,快速諮詢和自動完成文字。 這些功能有助於深入了解您使用的程式碼,追蹤所輸入的參數,以及幾個按鍵即可加入屬性和方法呼叫。
當我們在使用 Visual Studio 2015 進行 Xamarin.Forms 專案程式開發的時候,這是一個非常好用且實在的功能,相信很多人若突然沒有了這項功能,整體程式開發生產力與效率必定下降很多。
當然,在我們對於 Xamarin.Forms 專案內的 .xaml 檔案進行編輯的時候,一定要搭配 IntelliSense 這項功能,才能夠快速、正確地寫出相關 XAML 的宣告語法。
因此,請將 核心PCL 專案內的 MainPage.xaml 檔案在 Visual Studio IDE 編輯器中打開,在 Label 控制項的上一行,輸入一個 < 字元 ,此時,您會很興奮地看到 Visual Studio 顯示了 IntelliSense 視窗;不過,不要興奮的過早,這個時候,您看到的 IntelliSense 視窗,竟然只有幾個項目可以選擇,原來,Visual Studio 2015 把這個 MainPage.xaml 檔案,視為一般的 XML 檔案了。
沒有IntelliSense的功能
要解決這個問題相當的容易,此時,請先在方案總管切換預設專案為 Android 的專案,先找到 方案總管 >HelloBlankXamlApp.Droid 這個專案節點,使用滑鼠右擊該節點,再彈出功能表中選擇 設定為起始專案 這個選項,再使用滑鼠右擊該節點,選擇 重建 這個選項,將 HelloBlankXamlApp.Droid 這個專案進行編譯與建立出來。一旦完成的重建工作,一樣的在 MainPage.xaml 檔案內,在 Label 控制項的上一行,輸入一個 < 字元 ,此時,您會很興奮地看到 Visual Studio 顯示了 IntelliSense 視窗,並且在顯示了許多 XAML 項目供您選擇。
有IntelliSense的功能

修改 MainPage 成為一個有互動的 App

首先,請先將您整個方案有使用到 Xamarin.Forms 這個 NuGet 套件,都升級到最新版本;需要這樣做的原因是,現在這個 Xamarin.Forms 套件的版本是 2.0.0.6482,升級到最新的版本,可以任您的 Xamarin.Forms 應用程式避免掉之前就版本上存在的問題;所以,請先升級到最新版本,這樣,您就可以使用到更多、更豐富的 XAML 屬性。
請使用滑鼠右擊 方案總管 視窗中的 'HelloBlankXamlApp' 方案,接著點選 管理方案的 NuGet 套件,此時,會出現下圖視窗。請點選 更新 標籤頁次,並且在該頁次的最下方找到 Xamarin.Forms 這個項目。此時,在該視窗的右半部,請確認所有的專案都有選取,並且要更新到最新版本 (可以點選 版本 標題右邊的下拉選單),最後,點選 安裝 按鈕,進行該方案內所有的專案,所有有安裝 Xamarin.Forms 這個套件升級動作。
HelloBlankXamlApp方案_NuGet套件管理員1
當更新完成之後,請確認您的方案內的 起始專案 為 HelloBlankXamlApp.Droid
在接下來的過程,您需要修改這個應用程式,當這個應用程式執行之後,會有一個文字輸入盒和一個按鈕;您可以在文字輸入盒中輸入您的名字,接著點擊底下的按鈕,之後,就會出現 Hello, 您的名字,這樣具有互動性的應用程式。
接著,打開 MainPage.xaml 檔案,加入底下 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:HelloBlankXamlApp"
             x:Class="HelloBlankXamlApp.MainPage">

  <StackLayout
    Orientation="Vertical"
    Padding="20"
    >

    <Label Text="Welcome to Xamarin Forms!"
           VerticalOptions="Center"
           HorizontalOptions="Center" />
    <Label Text="Your Name" />
    <Entry x:Name="entYourName"
           Placeholder="Please input your name"
         />
    <Button x:Name="btnOK"
            Text="OK"
            Clicked="OnbtnOK_Clicked"
          />
    <Label x:Name="lblSayHello"
           Text="" 
          />
  </StackLayout>

</ContentPage>
打開 MainPage.cs 檔案,加入底下 C# 程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace HelloBlankXamlApp
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void OnbtnOK_Clicked(object sender, EventArgs e)
        {
            lblSayHello.Text = $"Hello, {entYourName.Text}";
        }
    }
}
此時,請按下 F5 ,就會在模擬器上執行該 Android 專案,底下分別是執行後與輸入姓名並且按下按鈕後的執行螢幕畫面截圖。
HelloBlankXamlApp.Droid執行前的畫面
HelloBlankXamlApp.Droid執行後的畫面
現在,可以來了解剛剛做了哪些變化,使得這個應用程式變得具有互動性。
在 MainPage.xaml 內,使用一個 StackLayout 這個版面配置控制項,讓 StackLayout 內的所有控制項,皆會呈現垂直方向的依序排列;會有這樣的效果,這是因為在 StackLayout 控制項內使用了Orientation="Vertical" 這個屬性定義。
StackLayout 版面配置控制項內,一共擁有五個控制項,Label 控制項主要的目的是會顯示文字之用;Entry 控制項用於顯示一個文字輸入盒,可以讓使用者在這個控制項內輸入文字;Button 這是一個按鈕控制項,當使用者按下這個按鈕,就會執行 Clicked 這個事件屬性所定義的 OnbtnOK_Clicked 事件,這個事件會定義在 Code Behind 檔案(也就是 MainPage.cs內) 。
這些控制項中,有些使用了 XAML 延伸功能 x:Name 用來定義這些控制項的名稱,而您可以在 Code Behind 的 .cs 檔案內,使用所定義的變數名字,存取該控制項,設定該控制項的各個屬性值,以變更其行為或者外觀。
這樣的應用,可參考 MainPage.cs 檔案內定義的事件方法 private void OnbtnOK_Clicked(object sender, EventArgs e) 這個 OnbtnOK_Clicked 事件方法會在使用者按下按鈕當時,就會呼叫這個方法;當這個方法執行的時候,會設定名稱為 lblSayHello 的 'Label' 控制項的 Text 屬性值。
最後,在 'MainPage.cs' 這個檔案內的類別 'MainPage',定義使用了這個屬性 '[XamlCompilation(XamlCompilationOptions.Compile)]' ;這樣的用法是相當的實用與重要,經過這樣定義之後,在 核心PCL 專案內的相關 .xaml 檔案之 XAML 定義,會在編譯時期進行檢查,讓您提早發現錯誤;也就是說,若沒有加入這樣的定義,您必須等候到執行時期,才能夠發現到是否 XAML 定義有任何錯誤,但往往在這個時候,您已經浪費了許多寶貴的開發時間,也會造成您的應用程式變得極度不穩定。

如何建立 Visual Stdio for Android的模擬器

想要使用 Visual Studio 提供的 Android 模擬器,請依照底下說明進行設定,完成設定之後,就可以在 Visual Studio 工具列上,看到您新產生的 Visual Studio for Android 模擬器。
請先在 Visual Studio 功能表中,點選 工具 > Visual Studio Emulatoro for Android 這個選項,如下圖所示:
等候一段時間,Visual Studio Emulator for Android 對話視窗將會顯示出來,在下圖,顯示出已經下載了三個 Visual Studio 的 Android 模擬器,您可以捲動這個對話窗內容,選擇您想要使用的 Visual Studio 的 Android 模擬器 ,接著點選該項目最右邊的 下載 小圖示;一旦下完成,這個模擬器就可以在 Visual Studio 的工具列上看到。
想要解除這個 Visual Studio 的 Android 模擬器,可以選擇已經安裝好的模擬器項目,在最右方的綠色箭頭的下方圖示 (Uninstall Profile),點選這個圖示,就可以解除這個 Visual Studio 的 Android 模擬器。

更新到最新的 Xamarin Toolkit

當您開啟 Xamarin.Forms 專案的時候,若在右下角看到下列畫面,這表示 Visual Studio 提醒您,Xamarin Toolkit 有新的更新推出了,此時,您可以點選右下角圖片區域,進行下載、更新。
當然,您也可以被動地進行檢查,是否 Xamarin Toolkit 是否有更新版本推出,這個時候,請透過功能表選擇工具 > 選項 ,當 選項 對話窗出現之後,在該對話窗的左半部選擇 Xamarin > Other > Check Now,進行線上檢查是否有最新的 Xamarin Toolkit 推出。
一旦有最新的 Xamarin for Visual Studio 更新發現到,就會跳出 Xamarin for Visual Studio Updated 對話窗,透過這個對話窗,您可以看到此次進行了那些更新內容,當您確認要進行更新到這個版本的 Xamarin for Visual Studio Updated ,此時,請點選右下角的 Download 按鈕,進行更新。

2015/10/04

Async Await , C# 編譯器做了些甚麼事情呢–2?

在上一篇文章中 Async Await , C# 編譯器做了些甚麼事情呢– 1,我們將 WPF 內的非同步程式碼,透過編譯器的處理,產生了相對應的狀態機程式碼,並且在產生後的程式碼中,加入了詳盡的註解說明,並且說明了編譯器的處理過程。

在這篇文章中,我們將要補足上篇文章的一些不足點,那就是,在我們呼叫非同步程式之前,也就是 await 關鍵字之前,若還有些 C# 程式碼的話,而且,在這 await 關鍵字之後,繼續有使用到這些變數,那麼,在編譯器中所產生的狀態機物件會如何呈現?

(至於,同一個非同步方法中,若有多個 await 關鍵字,則狀態機內會使用 goto 來切換到不同的部分還處理,有興趣的人,可以自行針對編譯器產生結果程式碼來觀察)

底下為我在 WPF 的按鈕事件內呼叫一個非同步方法,在呼叫非同步方法之前,我們會計算 x * y * z 的數學運算結果到本地變數 total 內;並且在呼叫完成非同步方法之後,再將 total 變數的值,輸出到 Console上。

        private async void btnDownload2_Click(object sender, RoutedEventArgs e)
{
int
x = 3, y = 1, z = 2, total = 0;
total = x * y * z;

string
fooStr = await GetString2Async();
Console.WriteLine(
string.Format("{0} {1}", total,fooStr));
}

接著我們來看看,經過了編譯器的轉換,狀態機的類別,會如何定義呢?


我們特別將呼叫 await 非同步方法前的程式碼使用黃底色標示出來,而呼叫完成非同步方法之後的程式碼使用橘底色標示出來,您可以參考上一篇文章 Async Await , C# 編譯器做了些甚麼事情呢– 1 ,試著找出其中異同點。

        [CompilerGenerated]
private sealed class
<btnDownload2_Click>d__3 : IAsyncStateMachine
{
public int
<>1__state;

public
AsyncVoidMethodBuilder <>t__builder;

public object
sender;

public
RoutedEventArgs e;

public
MainWindow <>4__this;

private int
<x>5__1;

private int
<y>5__2;

private int
<z>5__3;

private int
<total>5__4;

private string
<fooStr>5__5;

private string
<>s__6;

private TaskAwaiter<string
> <>u__1;

void
IAsyncStateMachine.MoveNext()
{
int num = this
.<>1__state;
try
{
TaskAwaiter<
string
> taskAwaiter;
if
(num != 0)
{
this
.<x>5__1 = 3;
this
.<y>5__2 = 1;
this
.<z>5__3 = 2;
this
.<total>5__4 = 0;
this.<total>5__4 = this.<x>5__1 * this.<y>5__2 * this
.<z>5__3;
taskAwaiter =
this
.<>4__this.GetString2Async().GetAwaiter();
if
(!taskAwaiter.IsCompleted)
{
this
.<>1__state = 0;
this
.<>u__1 = taskAwaiter;
MainWindow.<btnDownload2_Click>d__3 <btnDownload2_Click>d__ =
this
;
this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, MainWindow.<btnDownload2_Click>d__3>(ref taskAwaiter, ref
<btnDownload2_Click>d__);
return
;
}
}
else
{
taskAwaiter =
this
.<>u__1;
this.<>u__1 = default(TaskAwaiter<string
>);
this
.<>1__state = -1;
}
string
result = taskAwaiter.GetResult();
taskAwaiter =
default(TaskAwaiter<string
>);
this
.<>s__6 = result;
this.<fooStr>5__5 = this
.<>s__6;
this.<>s__6 = null
;
Console.WriteLine(
string.Format("{0} {1}", this.<total>5__4, this
.<fooStr>5__5));
}
catch
(Exception exception)
{
this
.<>1__state = -2;
this
.<>t__builder.SetException(exception);
return
;
}
this
.<>1__state = -2;
this
.<>t__builder.SetResult();
}

[DebuggerHidden]
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
}
}