Universal App - 實作 Data binding converter 動態更換 XAML 屬性
藉由 MVVM 的技術可藉由動態修改 ViewModel 的值配合 INotifyPropertyChanged 來更新 UI。
那麼如果希望在直接在 XAML 設定屬性時就給予需要動態更換的數值 (如:margin、width、height) 或 字型/背景色等,
又該怎麼處理呢?
Data Binding 技術提供了一個「IValueConverter」的技術,協助在 Binding 時可以動態藉由輸入的參數或 Binding 的 value 更換
我們希望呈現的畫面邏輯。相關的 binding 技術可參考<Binding 類別>的說明。
如果希望在 Data binding 時針對 binging view model 中的欄位或是 XAML 中輸入的屬性值轉換成對應的輸出或 UI 的調整,
需實作一個 IValueConverter 的介面,藉由介面中的 Convert 與 ConvertBack 來完成轉換的任務。至於建立好的 Converter 要
在 XAML 裡使用要記得宣告並利用「StaticResource」來取得。
為什麼需要這樣做?因為預設系統在 binding 時利用 隱含 式來嘗試轉換輸入的值至目標值之間的預設轉換子,但可能轉換
失敗或無法轉換,那預設轉換子會回傳 null。如果您使用的剛好的是列舉值那可能造成 Exception。
以下參考 MSDN 上的範例實作一個 IValueConverter 來加以說明:
public class DateTimeToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
DateTime date = (DateTime)value;
return date.ToString("yyy/MM/dd HH:mm:ss");
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
string strValue = value as string;
DateTime resultDateTime;
if (DateTime.TryParse(strValue, out resultDateTime))
{
return resultDateTime;
}
return DependencyProperty.UnsetValue;
}
}
上述是以 DateTime 轉換成 String 的範例,其中有幾個要注意的地方:
A. IValueConverter 的 Convert 與 ConvertBack 的用途:
a-1. Convert:負責轉換輸入值的型別值指定的繫結目標的值。
由於 data binding engine 不會攔截使用者提供的轉換程式會擲回的例外狀況,而是直接丟出 exception,
所以如果轉換失敗要記得加入「DependencyProperty.UnsetValue」來代表轉換常敗不會輸出任何值。可搭配 FallbackValue 使用。
a-2. ConvertBack:相反於 Convert 則是將繫結目標值轉換成繫值來源值。相同的如果無法轉換或有問題,要加上「DependencyProperty.UnsetValue」。
這二個方法裡除了會被輸入來源值之外,注意方法裡的第三個參數「parameter」可額外再加入需要的值。
B. ValueConversion 的屬性定義:
表示允許 IValueConverter 建立好後可以宣告於對應的 Data type 具有轉換的能力。
建立好的 IValueConverter 要怎麼用到 XAML 裡呢,如下:
<!-- 宣告 xmlns 來納入實作的 IValueConverter -->
<Page xmlns:converter="using:App1.View.Converter">
<Page.Resources>
<converter:DateTimeToStringConverter x:Key="datetimeStringConverter" />
</Page.Resources>
<Grid>
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,8,0"
Name="startDateTitle" Text="Start Date" />
<TextBlock Name="StartDateDTKey" Grid.Row="2" Grid.Column="1"
Text="{Binding Path=StartDate, Converter={StaticResource datetimeStringConverter}}" />
</Grid>
</Page>
這樣即完成 Data binding 至 XAML 後等 View Model 值匯入時搭配 IValueConverter 轉換成要輸出的內容。
藉由 IValueConverter 可以省掉以前為了判斷 View Model 中那一個值不為空或是需要的值來設定 Visibility 是否要顯示或隱藏所額外增加的屬性,
現在只要藉由在 bing 時加入 bing path 為 view model 的某一個值來加以轉換,例如:
// 定義一個 UserProfile 類別,具有一個 AvatarUrl 的屬性值
// 判斷如果為空或 null 則不要顯示畫面中的 Image Control.
public class UserProfile
{
public String AvatarUrl { get; set;}
}
public class NullDataVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (String.IsNullOrEmpty(value))
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
// 不提供轉換回來的功能
return DependencyProperty.UnsetValue;
}
}
在 XAML 上的使用方式就跟上述的介紹,直接在要 binding 的屬性加上「Converter」並且指定對應的 IValueConverter即可。
======
以上是分享一個最近學習到的技術。XAML 方便了開發人員在對於畫面的調整與動態給予。
希望對大家有幫忙學習自訂義 Converter 來讓畫面設計更多元。
References:
〉How to add IsVisible property to all WinRT UI elements
〉Binding.Converter 屬性 & Binding 類別
〉ValueConverters & Value conversion with IValueConverter
〉WPF Tutorial - Binding Converters