XAML 標記延伸

已完成

大部分的 XAML 定義將在編譯期間才會決定。 您通常應該會知道元素的位置、使用的色彩與字型,以及要指派給屬性的常值。

不過,在某些時候您會需要對無法在編譯期間決定的值,設定其屬性值。 這些值通常必須在程式執行時才能得知。 在這些情況下,您可以先建立一個會在執行階段提供值給 XAML 的物件。 XAML 支援此目的所需的標記延伸功能。

在此單元中,您會了解如何建立和使用標記延伸。

什麼是標記延伸?

標記延伸是一個類別,可在 XAML 中用來存取執行階段值。 假設在 XAML UI 中已定義了許多標籤,而您想要將 FontSize 屬性設定為在整個應用程式中具有相同的值,藉以確保所有標籤樣式都維持一致。 您可以使用 XAML 來設定 FontSize 屬性,如以下範例所示:

<Label Text="Hello, World!"
            Grid.Row="0"
            SemanticProperties.HeadingLevel="Level1"
            FontSize="28"
            HorizontalOptions="CenterAndExpand"/>

您可以針對每一個標籤重複這個設定步驟,但如果稍後想要變更此值的話,該怎麼辦? 您需要找到這個屬性的每一個執行個體,並進行變更。 此外,假設您不知道該使用什麼值;您可以依據像是裝置方向、螢幕解析度或其他考量,來計算執行階段值。 在這些情況下,您會需要比硬式編碼常值更為精細的資訊。 這正是標記延伸的實用之處。 標記延伸可讓您更靈活地取得會被用於 XAML 中的值。

建立標記延伸

標記延伸是一個實作 Microsoft.Maui.Controls.Xaml.IMarkupExtension 介面的類別。 這個介面定義了一種名為 ProvideValue 的方法,其中包含下列特徵標記:

public object ProvideValue(IServiceProvider serviceProvider)
{
    ...
}

此方法的目的是要提供一個值給 XAML 標記。 請注意,傳回型別為 object,所以此值可以為任何型別,只要適合使用該值的位置即可。 例如,在計算並傳回字型大小的標記延伸中,傳回類型應該是 double

serviceProvider 參數包含有關標記延伸在 XAML 程式碼中使用位置的資訊;與其他資訊不同的是,它可以識別要套用延伸的控制項。

您可以讓 FontSize 屬性的標記延伸保持簡單。 在下列範例中,MainPage 類別會公開名為 MyFontSizedouble 欄位。 GlobalFontSizeExtension 類別會實作 IMarkupExtension 介面,而 ProvideValue 方法會傳回 MyFontSize 變數的值:

namespace MyMauiApp;

public partial class MainPage : ContentPage
{
    public const double MyFontSize = 28;

    public MainPage()
    {
        InitializeComponent();
        ...
    }
    ...
}

public class GlobalFontSizeExtension : IMarkupExtension
{
    public object ProvideValue(IServiceProvider serviceProvider)
    {
        return MainPage.MyFontSize;
    }
}

注意

MyFontSize 欄位必須是 MainPage 類別的 static 成員,才能以這種方式在 ProvideValue 方法中加以參照。 良好做法表示在此情況下,變數應該也是常數。 const 值為 static

根據方向和裝置的外形規格等因素,ProvideValue 方法也可以對傳回的值加以調整。

將標記延伸套用至 XAML 中的控制項

若要在 XAML 程式碼中使用標記延伸,請將包含 GlobalFontSizeExtension 類別的命名空間新增至 ContentPage 標籤中的命名空間清單。 在以下範例中,會賦予此命名空間 mycode 的別名:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:mycode="clr-namespace:MyMauiApp"
             x:Class="MyMauiApp.MainPage">

您可以使用標記延伸來設定這一類的 FontSize 屬性。 請注意,慣例是標記延伸名稱的尾碼要有 Extension。 XAML 會辨識此尾碼,因此在 XAML 程式碼中呼叫該延伸時,已無需包含該尾碼。 在下列範例中,會直接將 GlobalFontSizeExtension 類別參照為 GlobalFontSize

<Label Text="Hello, World!"
            Grid.Row="0"
            SemanticProperties.HeadingLevel="Level1"
            FontSize="{mycode:GlobalFontSize}"
            HorizontalOptions="CenterAndExpand"/>

您可以在整個 XAML 程式碼中,對所有需要指定字型大小的控制項套用相同的標記延伸。 稍後,如果您決定變更字型大小,就只需修改 MainPage 類別中 MyFontSize 變數的定義即可。

StaticExtension 類別

儘管與 GlobalFontSize 標記延伸一樣實用,但不太可能建立這樣的延伸模組。 原因很簡單;.NET MAUI 已提供了更為通用的延伸模組,可讓您參照程式碼中的任何靜態值。 此延伸模組名為 StaticExtension,或簡稱 Static。 下列程式碼顯示此延伸模組類別的基本大綱:

[ContentProperty ("Member")]
public class StaticExtension : IMarkupExtension
{
    public string Member {get; set;}
    public object ProvideValue (IServiceProvider serviceProvider)
    {
        ...
    }
}

注意

自訂標記延伸的用途,是要讓您處理比簡單靜態大小寫更為複雜的情況。 例如,有可能會需要依據裝置的外形規格,以動態方式變更字型大小的情況。

若要在 XAML 程式碼中使用此類別,請提供要在 Member 屬性中參照的靜態變數名稱,ProvideValue 方法即會傳回此變數中的值。 下列範例會說明其使用方法:

<Label Text="Hello, World!"
            Grid.Row="0"
            SemanticProperties.HeadingLevel="Level1"
            FontSize="{x:Static Member=mycode:MainPage.MyFontSize}"
            HorizontalOptions="CenterAndExpand"/>

.NET MAUI 會提供一組其他標記延伸類別,您可以將這些類別用於像是資料繫結、參照動態資源和樣式,以及處理資料陣列等案例。

知識檢查

1.

該標記延伸可讓您將 XAML 屬性設定為程式碼後置類別中定義的靜態值?

2.

您使用何種介面來建立自訂標記延伸?