具有不相符類型的資料繫結
有時候您使用的資料不符合顯示資料的控制項屬性資料類型。 例如,您可能有以您想顯示於 Label
控制項的 decimal
類型儲存的貨幣值 (格式化為貨幣)。 更複雜的範例是模組中呈現的天氣應用程式。 影像應該根據天氣預報的 Sunny
或 Cloudy
列舉值顯示,但您無法將來源的列舉值繫結至目標的影像屬性。 本單元探討您可以轉換資料的方式。
字串格式
有一個常見的類型不相符情況,就是您想要顯示為格式化字串的內建類型。 就像當您想要顯示 DateTime
值的部分,或您想要將 decimal
類型格式化為貨幣時一樣。
假設您想要在帳單上顯示到期金額,而且您的資料物件上有此屬性:
public decimal BillAmount { get; set; }
最終欠款金額為 22.0304。 您可使用兩個標籤控制項來顯示文字和貨幣金額,如以下程式碼片段所示:
<HorizontalStackLayout>
<Label Text="You owe" Margin="0,0,5,0" />
<Label Text="{Binding BillAmount}" />
<Label Text="to the bank" Margin="5,0,0,0" />
</HorizontalStackLayout>
這會將字串輸出至看起來像 You owe 22.0304 to the bank
的 UI,但遺漏貨幣符號,且根據當地貨幣,可能有太多或太少的小數位數。 一般而言,您會以程式碼中的 "C" (或貨幣) 格式指定名稱將值處理為字串,如下所示:
string formattedBillAmount = string.Format("{0:C}", BillAmount);
但是若要在資料繫結中使用格式設定,您必須讓資料物件提供格式化字串作為不同的屬性,或以某種方式攔截它並自行格式化。 幸運的是,.NET MAUI 繫結提供一種方式,以 StringFormat
繫結屬性來格式化字串。 格式字串會遵循與 String.Format
方法相同的規則。 您需以單引號括住格式字串,才不會因大括弧而造成 XAML 剖析器產生混淆。 字串格式參數 0
是由繫結所處理的屬性值。
<Label Text="{Binding BillAmount, StringFormat='You owe {0:C} to the bank'}" />
請考慮下列 XAML,其示範如何使用兩種方式來顯示 BillAmount
:
<VerticalStackLayout Padding="10">
<HorizontalStackLayout>
<Label Text="You owe" Margin="0,0,5,0" />
<Label Text="{Binding BillAmount}" />
<Label Text="to the bank" Margin="5,0,0,0" />
</HorizontalStackLayout>
<HorizontalStackLayout>
<Label Text="{Binding BillAmount, StringFormat='You owe {0:C} to the bank'}" />
</HorizontalStackLayout>
</VerticalStackLayout>
下圖說明 XAML 輸出在畫面上產生的內容:
使用 StringFormat
繫結屬性的 XAML 比其他 XAML 簡單,而且您可存取 .NET 的強大字串格式系統。
自訂類型轉換
當您將值顯示為字串時,StringFormat
繫結屬性很方便,但是當您想要從另一個類型轉換 Color
或 Image
之類的項目時,則不方便。 在這些情況下,您必須撰寫自訂轉換程式碼。
假設您提示使用者選擇密碼,而且您想要在 UI 中使用色彩來指出密碼的強度。 強度有三個等級:弱、好、強。 強度是以密碼中的字元數為基礎。 若要立即向使用者提供其密碼強度的意見反應,您希望包含密碼的 Entry
控制項背景根據強度變更。 下圖示範這三種等級的強度:弱、好、強。
在螢幕擷取畫面中的三個輸入控制項中,第一個控制項已輸入四個字元並具有紅色背景。 第二個控制項已輸入九個字元並具有黃色背景。 最後一個輸入控制項有 15 個字元並具有藍色背景。
這些等級會指派給 Strength
列舉:
private enum Strength
{
Weak,
Good,
Strong
}
資料物件會指派為頁面的 BindingContext
,其中包含具有 PasswordStrength
屬性的密碼強度。 當使用者鍵入密碼時,PasswordStrength
屬性會根據密碼的長度變更。 因為資料物件包含 PasswordStrength
屬性,因此您可將該屬性繫結至 Entry
控制項的 BackgroundColor
:
<Entry BackgroundColor="{Binding PasswordStrength} ... />
不過,這裡還是有問題。 當 BackgroundColor
為 Color
時,PasswordStrength
的類型為 Strength
。 這些類型彼此不相容。 .NET MAUI 提供修正這些類型不符問題的方法,也就是繫結的 Converter
屬性。
顧名思義,繫結轉換器只會在繫結來源和目標之間轉換。 轉換器會透過 IValueConverter
介面實作。
實作 IValueConverter
您可將轉換邏輯建立到實作 IValueConverter
介面的類別中。 一般而言,這些類別的名稱是以名稱 Converter
結尾,使其用途明確。
IValueConverter
介面會定義兩種方法:
Convert
—從繫結來源的屬性轉換成繫結目標的 UI 屬性。ConvertBack
—從繫結目標的 UI 屬性轉換回繫結來源的屬性。這個方法很少使用,而且不會在此案例中使用。 大部分轉換器都會擲回
NotSupportedException
,表示不支援此轉換。
以下是介面的合約:
public interface IValueConverter
{
object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture);
object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture);
}
回想一下,我們正在處理的情況是將 Entry.BackgroundColor
屬性繫結至資料物件的 PasswordStrength
屬性,這是 Strength
列舉。
<Entry BackgroundColor="{Binding PasswordStrength} ... />
Strength
列舉必須轉換成 Color
。 因此,轉換器必須評估已提供哪個 Strength
值,並傳回不同的 Color
。 下列程式碼可示範此轉換:
namespace MyProject.Converters;
class StrengthToColorConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return (Strength)value! switch
{
Strength.Weak => Colors.OrangeRed,
Strength.Good => Colors.Yellow,
Strength.Strong => Colors.LightBlue,
_ => Colors.LightBlue
};
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) =>
throw new NotImplementedException();
}
讓我們來詳細說明此程式碼:
Convert
方法有四個參數。 除非您有使用最後兩個參數的特定理由,否則通常可加以捨棄。value
參數包含傳入值。 在此範例中,這是Strength
列舉值。targetType
參數會被忽略。 但是,您可使用此參數來驗證搭配轉換器使用的屬性類型是否為Color
。 為了簡單起見,此範例省略這點。- 參數運算式用於根據
Strength
值傳回不同的色彩。
在 XAML 中使用轉換器
建立轉換器類別後,您必須建立其執行個體並在繫結中加以參考。 具現化轉換器的標準方法是在根元素的資源字典中。
首先,將 XML 命名空間對應至包含轉換器的 .NET 命名空間。 在下列程式碼範例中,cvt
XML 命名空間會對應至 MyProject.Converters
.NET 命名空間:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cvt="clr-namespace:MyProject.Converters"
...
接下來,在 ContentPage.Resources
中建立執行個體:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cvt="clr-namespace:MyProject.Converters"
x:Class="MyProject.PasswordExample">
<ContentPage.Resources>
<cvt:StrengthToColorConverter x:Key="StrengthToColorConverter" />
</ContentPage.Resources>
現在,轉換器的執行個體位於資源字典中且索引鍵為 StrengthToColorConverter
,其恰好與類型同名。 這是命名轉換器的典型方式,因為您通常只要在 XAML 中重複使用單一轉換器。 如果您基於某些原因而需要多個轉換器執行個體,則其間的索引鍵必須不同。
最後,參考繫結上的轉換器。 由於轉換器位於資源字典中,因此您可使用 {StaticResource}
標記延伸來參考它。 轉換器會指派給 Converter
繫結屬性:
<Entry BackgroundColor="{Binding PasswordStrength, Converter={StaticResource StrengthToColorConverter}}" ... />