學習目標
- 從 XAML 使用參數與呼叫方法 來建構物件
- x:Name - Visual Elements 相對於 C# 的 ID
- 客製化 XAML View,可重複利用的 View
在建立 XAML 時都會附帶一支 .cs 檔案,除了將關注點分離外,也讓我們在寫 XAML 時擁有更多的彈性,能夠利用 .cs 去控制 XAML 的物件。
這也是我們稱呼為 code-behind 的作法。
此章節會比較分散,每一段落講解的東西都較獨立,基本上就是了解一下 XAML 和 cs 之間如何互相運作。
先來看一下如何在 XAML 類 C#,達到 建構物件 的目的。
XAML 內建構 C# 物件
當你要建構 Color 物件時,會需要帶入 RGB 三個參數值,或是使用 FromHsla() 等方法來回傳 Color 物件。
這件事情通常是在 .cs 內做,但我們能不能在 XAML 內建構 Color 物件?
2009 XAML 規範提供了兩個屬性:
- x:Arguments
- x:FactoryMethod
x:Arguments 使 XAML 擁有傳遞參數的功能,而 x:FactoryMethod 則使 XAML 擁有呼叫 C# 方法的功能,要注意的是 x:FactoryMethod 呼叫的方法必須回傳物件。
<BoxView WidthRequest="100" HeightRequest="100" HorizontalOptions="Center" VerticalOptions="CenterAndExpand"> <BoxView.Color> <Color> <x:Arguments> <x:Double>0</x:Double> <x:Double>0</x:Double> <x:Double>1</x:Double> <x:Double>0.5</x:Double> </x:Arguments> </Color> </BoxView.Color> </BoxView>如上,就能在 BoxView.Color 底下利用 x:Arguments 傳遞 RGBA 四個值,並建構 Color 物件。
而 XAML 提供以下的 Arguments 類別可以使用:
- x : Object
- x : Boolean
- x : Byte
- x : Int16
- x : Int32
- x : Int64
- x : Single
- x : Double
- x : Decimal
- x : Char
- x : String
- x : TimeSpan
- x : Array
- x : DateTime(supported by Xamarin.Forms but not the XAML 2009 specification)
接著來看要如何用 x:FactoryMethod 和 FromHsla() 來建構 Color:
<BoxView.Color> <Color x:FactoryMethod="FromHsla"> <x:Arguments> <x:Double>0.67</x:Double> <x:Double>1.0</x:Double> <x:Double>0.5</x:Double> <x:Double>1.0</x:Double> </x:Arguments> </Color> </BoxView.Color>
x:Name - XAML 物件的ID
前面的章節有提到 Walking the tree 方法,當我們知道且確定 XAML 架構時,能夠從 Root 往下層追蹤到我們要修改的 Visual Elements。
但更好的方法是,我們直接幫 Visual Elements 取個唯一的名字,而這個屬性就是 x:Name。
來看範例,
底下的 XAML 有兩個 Label,分別給予 x:Name 的值為 timeLabel 和 dateLabel:
<Label x:Name="timeLabel" FontSize="Large" HorizontalOptions="Center" VerticalOptions="EndAndExpand" /> <Label x:Name="dateLabel" HorizontalOptions="Center" VerticalOptions="StartAndExpand" />
再來看一下 .cs:
namespace XamlClock { public partial class XamlClockPage { public XamlClockPage() { InitializeComponent(); Device.StartTimer(TimeSpan.FromSeconds(1), OnTimerTick); } bool OnTimerTick() { DateTime dt = DateTime.Now; timeLabel.Text = dt.ToString("T"); dateLabel.Text = dt.ToString("D"); return true; } } }可以看到 .cs 內能直接將有設定 x:Name 的 Visual Element,視為可用的物件。
原文書 p163 頁有講解 Xamarin.Forms 是如何辦到的,有興趣可以看一下。
注意:同一個 XAML 內不能有重複的 x:Name
客製化 XAML Views - 重複使用
若今天要如下圖顯示多筆顏色時,標籤程式全部寫在同一支 XAML 內程式會變得很醜且不好維護。
而 XAML 又沒有 for 或是 while 等商業邏輯面的程式可以使用...
這邊提供一個客製化 View 的做法,讓程式碼看起來更加精簡。
首先,我們先建立一個 ContentView 的 XAML 如ㄒ:
namespace 為 ColorViewList,class 為 ColorView
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="ColorViewList.ColorView"> <Frame OutlineColor="Accent"> <StackLayout Orientation="Horizontal"> <BoxView x:Name="boxView" WidthRequest="70" HeightRequest="70" /> <StackLayout> <Label x:Name="colorNameLabel" FontSize="Large" VerticalOptions="CenterAndExpand" /> <Label x:Name="colorValueLabel" VerticalOptions="CenterAndExpand" /> </StackLayout> </StackLayout> </Frame> </ContentView>
接著 .cs 為:
public partial class ColorView : ContentView { string colorName; ColorTypeConverter colorTypeConv = new ColorTypeConverter(); public ColorView() { InitializeComponent(); } public string ColorName { set { // Set the name. colorName = value; colorNameLabel.Text = value; // Get the actual Color and set the other views. Color color = (Color)colorTypeConv.ConvertFrom(colorName); boxView.Color = color; colorValueLabel.Text = String.Format("{0:X2}-{1:X2}-{2:X2}",( (int)(255 * color.R), (int)(255 * color.G), (int)(255 * color.B))); } get { return colorName; } } }可以看程式內有個 string ColorName 的屬性,當這個屬性被指派值時,會去設定 XAML 上boxView 的 Color 和 colorValueLabel 的 Text。
這樣我們客製化的 View 就建立好了。
使用方式如下:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:ColorViewList" x:Class="ColorViewList.ColorViewListPage"> <ContentPage.Padding> <OnPlatform x:TypeArguments="Thickness" iOS="0, 20, 0, 0" /> </ContentPage.Padding> <ScrollView> <StackLayout Padding="6, 0"> <local:ColorView ColorName="Aqua" /> <local:ColorView ColorName="Black" /> <local:ColorView ColorName="Blue" /> <local:ColorView ColorName="Fuchsia" /> <local:ColorView ColorName="Gray" /> <local:ColorView ColorName="Green" /> <local:ColorView ColorName="Lime" /> <local:ColorView ColorName="Maroon" /> <local:ColorView ColorName="Navy" /> <local:ColorView ColorName="Olive" /> <local:ColorView ColorName="Purple" /> <local:ColorView ColorName="Pink" /> <local:ColorView ColorName="Red" /> <local:ColorView ColorName="Silver" /> <local:ColorView ColorName="Teal" /> <local:ColorView ColorName="White" /> <local:ColorView ColorName="Yellow" /> </StackLayout> </ScrollView> </ContentPage>這裡最需要注意的是 ContentPage 內多出的那一行,
xmlns:local="clr-namespace:ColorViewList"
一定要先將 local 指派為 ColorViewList namespace,才能在 XAML 內使用同一層 namespace 底下的 class - ColorView。
為什麼是 local?
這邊的 local 是一個 變數名稱 的概念,你要取其他名字也可以,舉例來說,ContentPage 內我先設定 xmlns:logan="clr-namespace:ColorViewList"
使用時就要寫 <logan:ColorView ColorName="White" />
一般來說使用 local ,不過命名爽就好了。
Color color = (Color)colorTypeConv.ConvertFrom(colorName);
回覆刪除又是過時的XD....
而且我作完會跳出例外錯誤
Unhandled Exception:
Xamarin.Forms.Xaml.XamlParseException:
晚點我再試試喔~ 畢竟這邊的code都是從第一版原文書上節錄下來的
刪除Xamarin都不知道更新到幾版了Orz
好的,謝謝
刪除這真的更新太快 連書都跟不上
網路上其他教學也是...
我找到了 改用ConvertFromInvariantString("T")
刪除_(:3」∠)_
colorValueLabel.Text = String.Format("{0:X2}-{1:X2}-{2:X2}",(
回覆刪除(int)(255 * color.R),
(int)(255 * color.G),
(int)(255 * color.B));
似乎少了一個右括弧~雖然不太重要XD
謝謝你喔,已更新
刪除