Universal App - 實作 Data binding converter 動態更換 XAML 屬性

Universal App - 實作 Data binding converter 動態更換 XAML 屬性

藉由 MVVM 的技術可藉由動態修改 ViewModel 的值配合 INotifyPropertyChanged 來更新 UI。

那麼如果希望在直接在 XAML 設定屬性時就給予需要動態更換的數值 (如:margin、width、height) 或 字型/背景色等,

又該怎麼處理呢?

 

Data Binding 技術提供了一個「IValueConverter」的技術,協助在 Binding 時可以動態藉由輸入的參數或 Binding 的 value 更換

我們希望呈現的畫面邏輯。相關的 binding 技術可參考<Binding 類別>的說明。

 

Binding.Converter 屬性

     如果希望在 Data binding 時針對 binging view model 中的欄位或是 XAML 中輸入的屬性值轉換成對應的輸出或 UI 的調整,

需實作一個 IValueConverter 的介面,藉由介面中的 ConvertConvertBack 來完成轉換的任務。至於建立好的 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

 

Dotblogs Tags: