具有不相符類型的資料繫結
- 10 分鐘
有時候,您所使用的資料不符合顯示資料的控制項屬性資料類型。 例如,您可能有以您想顯示於 decimal 控制項的 Label 類型儲存的貨幣值 (格式化為貨幣)。 更複雜的範例是模組中呈現的天氣應用程式。 影像應該根據天氣預報的 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」 (或 currency) 格式規範來處理值作為字串,如下所示:
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 屬性,因此您可將該屬性繫結至 BackgroundColor 控制項的 Entry:
<Entry BackgroundColor="{Binding PasswordStrength} ... />
不過,這裡有個問題。 當 PasswordStrength 為 Strength 時,BackgroundColor 的類型為 Color。 這些類型彼此不相容。 .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。 為了簡單起見,此範例省略這點。 - switch 運算式會根據
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}}" ... />