第 1 部份: 開始使用 XAML
Xamarin.Forms在應用程式中,XAML 主要用於定義頁面的視覺內容,並與 C# 程式代碼後置檔案搭配運作。
程序代碼後置檔案提供標記的程式代碼支援。 這兩個檔案會共同參與新的類別定義,其中包含子檢視和屬性初始化。 在 XAML 檔案中,會使用 XML 元素和屬性來參考類別和屬性,並建立標記和程式代碼之間的連結。
建立方案
若要開始編輯您的第一個 XAML 檔案,請使用 Visual Studio 或 Visual Studio for Mac 來建立新的 Xamarin.Forms 解決方案。 (選取下方對應至您環境的索引標籤。
在 Windows 中,啟動 Visual Studio 2019,然後在 [開始] 視窗中,按兩下 [建立新專案] 以建立新的專案 :
在 [建立新專案] 視窗中,選取 [專案類型] 下拉式清單中的 [行動裝置],選取 [行動應用程式]Xamarin.Forms 範本,然後按兩下 [下一步] 按鈕:
在 [設定新專案] 視窗中,將 [專案名稱] 設定為 [XamlSamples] (或您偏好的任何專案),然後按兩下 [建立] 按鈕。
在 [ 新增跨平臺應用程式 ] 對話框中,按兩下 [ 空白],然後按下 [ 確定] 按鈕:
解決方案中會建立四個專案:XamlSamples .NET Standard 連結庫、XamlSamples.Android、XamlSamples.iOS 和 通用 Windows 平台 方案 XamlSamples.UWP。
建立 XamlSamples 解決方案之後,您可以選取各種平臺專案作為方案啟動專案,並在手機模擬器或實際裝置上建置和部署專案範本所建立的簡單應用程式,以測試開發環境。
除非您需要撰寫平臺特定的程式代碼,否則共用 的 XamlSamples .NET Standard 連結庫專案就是您將花費幾乎所有程式設計時間的地方。 這些文章不會冒險到該專案之外。
XAML 檔案的結構
在 XamlSamples .NET Standard 連結庫中,有一組具有下列名稱的檔案:
- App.xaml,XAML 檔案;和
- App.xaml.cs,與 XAML 檔案相關聯的 C# 程式代碼後置檔案。
您必須按兩下 App.xaml 旁的箭號,才能查看程式代碼後置檔案。
App.xaml 和 App.xaml.cs都會參與衍生自 Application
的類別App
。 大部分具有 XAML 檔案的其他類別都會參與衍生自 ContentPage
的類別;這些檔案會使用 XAML 來定義整個頁面的視覺內容。 這是 XamlSamples 專案中其他兩個檔案的 true:
- MainPage.xaml,XAML 檔案;和
- MainPage.xaml.cs,C# 程式代碼後置檔案。
MainPage.xaml 檔案看起來像這樣(雖然格式可能稍有不同):
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
x:Class="XamlSamples.MainPage">
<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin Forms!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
這兩個 XML 命名空間 (xmlns
) 宣告是指 URI,第一個似乎在 Xamarin 的網站上,第二個似乎是Microsoft。 不要費心檢查這些 URI 指向什麼。 那裡沒有什麼。 它們只是 Xamarin 和 Microsoft所擁有的 URI,而且基本上會作為版本識別碼運作。
第一個 XML 命名空間宣告表示在 XAML 檔案中定義的標籤沒有前置詞, Xamarin.Forms例如 ContentPage
。 第二個命名空間宣告會定義的 x
前置詞。 這用於 XAML 本身內建的數個元素和屬性,以及 XAML 的其他實作所支援的屬性。 不過,這些元素和屬性會根據 URI 中內嵌的年份而略有不同。 Xamarin.Forms 支援 2009 XAML 規格,但並非全部。
local
命名空間宣告可讓您從 .NET Standard 連結庫專案存取其他類別。
在第一個標記的結尾,前置 x
詞會用於名為 Class
的屬性。 由於此 x
前置詞的使用幾乎適用於 XAML 命名空間,因此 Class
XAML 屬性幾乎一律稱為 x:Class
。
屬性 x:Class
會指定完整 .NET 類別名稱: MainPage
命名空間中的 XamlSamples
類別。 這表示這個 XAML 檔案會在衍生自 ContentPage
的命名空間中XamlSamples
定義名為 MainPage
的新類別,也就是屬性出現所在的x:Class
標記。
屬性 x:Class
只能出現在 XAML 檔案的根元素中,以定義衍生的 C# 類別。 這是 XAML 檔案中唯一定義的新類別。 XAML 檔案中出現的所有其他專案,只是從現有的類別具現化並初始化。
MainPage.xaml.cs檔案看起來像這樣(除了未使用的using
指示詞外):
using Xamarin.Forms;
namespace XamlSamples
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
}
類別 MainPage
衍生自 ContentPage
,但請注意 partial
類別定義。 這表示應該有另一個 的部分類別定義, MainPage
但該定義在哪裡? 這個方法是什麼 InitializeComponent
?
當 Visual Studio 建置專案時,它會剖析 XAML 檔案以產生 C# 程式代碼檔案。 如果您在 XamlSamples\XamlSamples\obj\Debug 目錄中尋找名為 XamlSamples.MainPage.xaml.g.cs 的檔案。 'g' 代表產生的 。 這是的另一個部分類別定義MainPage
,其中包含從MainPage
建構函式呼叫的方法定義InitializeComponent
。 然後,這兩個部分 MainPage
類別定義可以一起編譯。 根據 XAML 是否已編譯,XAML 檔案或 XAML 檔案的二進位格式會內嵌在可執行檔中。
在運行時間,特定平台專案中的程式代碼會呼叫 LoadApplication
方法,並傳遞至 .NET Standard 連結庫中 類別的新實例 App
。 類別建構函式會 App
具現化 MainPage
。 該類別的建構函式會呼叫 InitializeComponent
,然後呼叫 LoadFromXaml
方法,從 .NET Standard 連結庫擷取 XAML 檔案(或其編譯的二進位檔)。 LoadFromXaml
初始化 XAML 檔案中定義的所有物件、將它們全部連接在父子關聯性中、將程式代碼中定義的事件處理程式附加至 XAML 檔案中設定的事件,並將對象的結果樹狀結構設定為頁面的內容。
雖然您通常不需要花太多時間處理產生的程式代碼檔案,但有時候產生的檔案中的程式代碼上會引發運行時間例外狀況,因此您應該熟悉它們。
當您編譯並執行此程式時, Label
元素會出現在頁面中央,如 XAML 建議:
如需更有趣的視覺效果,您只需要更有趣的 XAML。
新增 XAML 頁面
若要將其他 XAML 型ContentPage
類別新增至您的專案,請選取 XamlSamples .NET Standard 連結庫專案,以滑鼠右鍵按兩下,然後選取 [新增>專案...]。在 [新增專案] 對話框中,選取 [Visual C# 專案>>Xamarin.Forms內容頁面] (而非 [內容頁面 ][C#],這會建立僅限程序代碼的頁面,或不是頁面的內容檢視)。 提供頁面名稱,例如 HelloXamlPage:
兩個檔案會新增至專案 HelloXamlPage.xaml 和程式代碼後置檔案 HelloXamlPage.xaml.cs。
設定頁面內容
編輯 HelloXamlPage.xaml 檔案,讓唯一的標籤是 和 ContentPage.Content
的ContentPage
標籤:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.HelloXamlPage">
<ContentPage.Content>
</ContentPage.Content>
</ContentPage>
標籤 ContentPage.Content
是 XAML 唯一語法的一部分。 起初,它們看起來可能無效,但它們是合法的。 句點不是 XML 中的特殊字元。
標籤 ContentPage.Content
為 屬性項目 標記。 Content
是 的 ContentPage
屬性,通常設定為單一檢視或具有子檢視的配置。 一般而言,屬性會變成 XAML 中的屬性,但很難將屬性設定 Content
為複雜物件。 因此,屬性會以 XML 專案表示,其中包含類別名稱和以句號分隔的屬性名稱。 Content
現在可以在標記之間ContentPage.Content
設定 屬性,如下所示:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.HelloXamlPage"
Title="Hello XAML Page">
<ContentPage.Content>
<Label Text="Hello, XAML!"
VerticalOptions="Center"
HorizontalTextAlignment="Center"
Rotation="-15"
IsVisible="true"
FontSize="Large"
FontAttributes="Bold"
TextColor="Blue" />
</ContentPage.Content>
</ContentPage>
另請注意, Title
已在根標記上設定屬性。
此時,類別、屬性和 XML 之間的關聯性應該很明顯: Xamarin.Forms 類別 (例如 ContentPage
或 Label
) 會以 XML 元素的形式出現在 XAML 檔案中。 該類別的屬性,包括 Title
on ContentPage
和 7 屬性 Label
,通常會顯示為 XML 屬性。
有許多快捷方式可用來設定這些屬性的值。 某些屬性是基本資料類型:例如,Title
和 屬性的類型為 String
Rotation
,屬於 類型 Double
,且 IsVisible
(true
預設為 ,且僅針對圖例設定在這裡) 的類型為 Boolean
Text
。
屬性 HorizontalTextAlignment
的類型為 TextAlignment
,這是列舉。 對於任何列舉型別的屬性,您只需要提供的成員名稱。
不過,對於更複雜的型別屬性,轉換器會用於剖析 XAML。 這些是衍生自TypeConverter
的Xamarin.Forms類別。 許多是公用類別,但有些不是。 針對這個特定的 XAML 檔案,這些類別中有數個會在幕後扮演角色:
LayoutOptionsConverter
屬性的VerticalOptions
FontSizeConverter
屬性的FontSize
ColorTypeConverter
屬性的TextColor
這些轉換器會控管屬性設定的允許語法。
ThicknessTypeConverter
可以處理以逗號分隔的一、二或四個數位。 如果提供一個數位,則會套用至所有四面。 使用兩個數位時,第一個是左右邊框間距,第二個是頂端和底部。 四個數位依左、上、右和下的順序排列。
LayoutOptionsConverter
可以將 結構之公用靜態字段LayoutOptions
的名稱轉換為 類型的LayoutOptions
值。
FontSizeConverter
可以處理NamedSize
成員或數值字型大小。
接受 ColorTypeConverter
結構或十六進位 RGB 值之公用靜態欄位 Color
的名稱,且前面加上數字符號 (#) 或不含 Alpha 色板。 以下是沒有Alpha通道的語法:
TextColor="#rrggbb"
每個小字母都是十六進位數位。 以下是包含 Alpha 色板的方式:
TextColor="#aarrggbb">
對於Alpha色板,請記住FF完全不透明,00完全透明。
另外兩種格式可讓您為每個通道指定一個十六進位數位:
TextColor="#rgb"
TextColor="#argb"
在這些情況下,會重複數位以形成值。 例如,#CF3 是 RGB 色彩 CC-FF-33。
頁面瀏覽
當您執行 XamlSamples 程式時, MainPage
會顯示 。 若要查看新的 HelloXamlPage
,您可以將該設定為 App.xaml.cs 檔案中的新啟動頁面,或從 MainPage
流覽至新頁面。
若要實作導覽,請先變更App.xaml.cs建構函式中的程序代碼,NavigationPage
以便建立物件:
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
在MainPage.xaml.cs建構函式中,您可以建立簡單的 Button
,並使用事件處理程式巡覽至 HelloXamlPage
:
public MainPage()
{
InitializeComponent();
Button button = new Button
{
Text = "Navigate!",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};
button.Clicked += async (sender, args) =>
{
await Navigation.PushAsync(new HelloXamlPage());
};
Content = button;
}
設定 Content
頁面的 屬性會取代 XAML 檔案中的 屬性設定 Content
。 當您編譯及部署這個程式的新版本時,畫面上會出現一個按鈕。 按會巡覽至 HelloXamlPage
。 以下是iPhone、Android和UWP上的結果頁面:
您可以使用 iOS 上的 [上一頁] 按鈕,使用頁面頂端或 Android 手機底部的向左箭號,或使用 Windows 10 頁面上頂端的向左箭號來流覽MainPage
<。
您可以隨意試驗 XAML,以取得轉譯 Label
的不同方式。 如果您需要將任何 Unicode 字元內嵌到文字中,您可以使用標準 XML 語法。 例如,若要將問候語放在智慧引號中,請使用:
<Label Text="“Hello, XAML!”" … />
外觀大致如下:
XAML 和程式代碼互動
HelloXamlPage 範例只包含頁面上的單Label
一,但這是非常不尋常的。 大部分 ContentPage
的衍生專案會將 Content
屬性設定為某種類型的版面配置,例如 StackLayout
。 的 Children
StackLayout
屬性定義為 型 IList<View>
別,但它實際上是 類型的 ElementCollection<View>
物件,而且該集合可以填入多個檢視或其他版面配置。 在 XAML 中,這些父子式關聯性是使用一般 XML 階層建立的。 以下是名為 XamlPlusCodePage 之新頁面的 XAML 檔案:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.XamlPlusCodePage"
Title="XAML + Code Page">
<StackLayout>
<Slider VerticalOptions="CenterAndExpand" />
<Label Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Click Me!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
此 XAML 檔案是語法完整的,以下是其外觀:
不過,您可能會將此程式視為功能不足。 也許 Slider
應該會導致 Label
顯示目前值,而 Button
可能打算在程式內執行某些動作。
如您在第 4 部分中所見。數據系結基本概念,使用 Label
來顯示Slider
值的作業可以透過數據系結在 XAML 中完全處理。 但先查看程式程式碼解決方案會很有用。 即便如此,處理 Button
點擊肯定需要程序代碼。 這表示的程式代碼後置檔案XamlPlusCodePage
必須包含 之 事件的Slider
處理程式ValueChanged
,以及 Clicked
的Button
事件。 讓我們新增它們:
namespace XamlSamples
{
public partial class XamlPlusCodePage
{
public XamlPlusCodePage()
{
InitializeComponent();
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
}
void OnButtonClicked(object sender, EventArgs args)
{
}
}
}
這些事件處理程式不需要是公用的。
回到 XAML 檔案, Slider
和 Button
標記必須包含參考這些處理程式之 ValueChanged
和 Clicked
事件的屬性:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.XamlPlusCodePage"
Title="XAML + Code Page">
<StackLayout>
<Slider VerticalOptions="CenterAndExpand"
ValueChanged="OnSliderValueChanged" />
<Label Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Click Me!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
</StackLayout>
</ContentPage>
請注意,將處理程式指派給事件具有與將值指派給屬性相同的語法。
如果 事件的Slider
處理程式ValueChanged
將使用 Label
來顯示目前值,處理程式就必須從程式代碼參考該物件。 需要 Label
以 屬性指定 x:Name
的名稱。
<Label x:Name="valueLabel"
Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
屬性 x
的 x:Name
前置詞表示這個屬性是 XAML 內建的。
您指派給 x:Name
屬性的名稱與 C# 變數名稱具有相同的規則。 例如,它必須以字母或底線開頭,且不包含內嵌空格。
ValueChanged
現在事件處理程式可以設定 Label
來顯示新Slider
值。 新的值可從事件自變數取得:
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
valueLabel.Text = args.NewValue.ToString("F3");
}
或者,處理程式可以從 自變數取得 Slider
產生此事件 sender
的物件,並從中取得 Value
屬性:
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
valueLabel.Text = ((Slider)sender).Value.ToString("F3");
}
當您第一次執行程式時, Label
不會顯示 Slider
值,因為 ValueChanged
事件尚未引發。 但是,任何操作 Slider
都會顯示值:
現在針對 Button
。 讓我們藉由顯示具有 按鈕的警示Text
來模擬事件的回應Clicked
。 事件處理程式可以安全地將 自變數Button
轉換成 sender
,然後存取其屬性:
async void OnButtonClicked(object sender, EventArgs args)
{
Button button = (Button)sender;
await DisplayAlert("Clicked!",
"The button labeled '" + button.Text + "' has been clicked",
"OK");
}
方法的定義是 async
,因為 DisplayAlert
方法是異步的 await
,而且應該以 運算符開頭,這個運算符會在方法完成時傳回。 因為這個方法會 Button
從 sender
自變數取得引發事件,所以同一個處理程式可用於多個按鈕。
您已看到在 XAML 中定義的物件可以引發程式代碼後置檔案中處理的事件,而且程式代碼後置檔案可以使用指派給 x:Name
它與 屬性的名稱來存取 XAML 中定義的物件。 這些是程式代碼和 XAML 互動的兩種基本方式。
藉由檢查新產生的 XamlPlusCode.xaml.g.cs檔案來收集 XAML 運作方式的一些額外見解,該檔案現在包含指派給任何屬性做為私人字段的任何 x:Name
名稱。 以下是該檔案的簡化版本:
public partial class XamlPlusCodePage : ContentPage {
private Label valueLabel;
private void InitializeComponent() {
this.LoadFromXaml(typeof(XamlPlusCodePage));
valueLabel = this.FindByName<Label>("valueLabel");
}
}
此欄位的宣告可讓變數自由使用您管轄範圍內部分類別檔案內 XamlPlusCodePage
的任何位置。 在運行時間,欄位會在剖析 XAML 之後指派。 這表示valueLabel
欄位是在null
建構函式開始時,但在呼叫 之後InitializeComponent
有效時XamlPlusCodePage
。
將控件傳回建構函式之後 InitializeComponent
,頁面的視覺效果就如同已在程式代碼中具現化和初始化一樣建構。 XAML 檔案不再在 類別中扮演任何角色。 例如,您可以將檢視新增至 ,或將頁面的 屬性完全設定Content
為StackLayout
其他物件,以任何您想要的方式操作頁面上的物件。 您可以檢查頁面的 屬性和版面配置集合中的Children
專案,以「逐步執行Content
樹狀結構」。 您可以在以這種方式存取的檢視上設定屬性,或動態指派事件處理程式給它們。
自由自在。 它是您的頁面,而 XAML 只是建置其內容的工具。
摘要
在此簡介中,您已瞭解 XAML 檔案和程式代碼檔案如何參與類別定義,以及 XAML 和程式代碼檔案的互動方式。 但 XAML 也有它自己的獨特語法功能,允許它以非常靈活的方式使用。 您可以在第 2 部分開始探索這些專案 。基本 XAML 語法。