在WPF中應用數據綁定時經常需要做一些簡單的邏輯判斷。
比如ViewModel中有一個HasError(布爾值)的屬性表示是否有錯誤。我需要將它綁定於Button的IsEnable屬性上,即:當沒有錯誤時Button可用。這時就需要將HasError取反。WPF默認的綁定引擎是不支持的。
還有一種情況比如ViewModel中有一個Sex(int值)的屬性表示性別,我需要將它綁定到TextBlock上,當值為1時顯示男,值為2時顯示女。WPF默認綁定也是不支持這種判斷的。
於是一個通用的值轉換器就誕生了,用法如下:
<Button IsEnabled="{Binding HasError, Converter={StaticResource GenericTypeConverter}, ConverterParameter='IsReverse=True'}">OK</Button>
IsReverse參數表示是否取返,如果轉換的值為true則變為false,反之亦然。
<TextBlock Text="{Binding Sex, Converter={StaticResource GenericTypeConverter}, ConverterParameter='Alias=1:男|2:女|other:未知'}" />
Alias參數表示將值映射為字符串,other表示當遇到沒有指定的值時顯示的文本
另外bool to Visibility的轉換可以自動進行,不需要指定參數。
有意見歡迎指正
完整代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows;
namespace MoodSunshiny.WPF.Converter
{
/// <summary>
/// 一個通用的類型轉換器,可以提供更多轉換控制參數
/// </summary>
public class GenericTypeConverter : IValueConverter
{
/// <summary>
/// 是否反轉轉換源參數值
/// 僅對bool類型的值有效
/// </summary>
private bool IsReverse { get; set; }
/// <summary>
/// 用於將轉換結果映射為其它字符串
/// 例如:Alias=True:是|False:否
/// </summary>
private Dictionary< object, string> Alias { get; set; }
/// <summary>
/// 解析轉換參數
/// </summary>
private void AnalyseConvertParameter( string convertParameter)
{
/* 設置參數默認值 */
IsReverse = false;
Alias = null;
if (! string.IsNullOrEmpty(convertParameter))
{
var pkvs = convertParameter.Split( new char[] { ' , ' }, StringSplitOptions.RemoveEmptyEntries);
foreach ( var pkv in pkvs)
{
var pkvo = pkv.Split( new char[] { ' = ' }, StringSplitOptions.RemoveEmptyEntries);
if (pkvo.Length != 2)
throw new NotSupportedException( " 不支持設置: " + pkv);
var pk = pkvo[ 0].Trim();
var pv = pkvo[ 1].Trim();
switch (pk)
{
case " IsReverse ":
bool b;
if (! bool.TryParse(pv, out b))
throw new NotSupportedException( " 參數取值錯誤: " + pkv);
else
IsReverse = b;
break;
case " Alias ":
{
Alias = new Dictionary< object, string>();
var dfkvs = pv.Split( new char[] { ' | ' }, StringSplitOptions.RemoveEmptyEntries);
foreach ( var dfkv in dfkvs)
{
var dfkvo = dfkv.Split( new char[] { ' : ' }, StringSplitOptions.RemoveEmptyEntries);
if (dfkvo.Length != 2)
throw new NotSupportedException( " 不支持設置: " + dfkvo);
var dfk = dfkvo[ 0].Trim();
var dfv = dfkvo[ 1].Trim();
object oKey = null;
int i;
if (dfk.Equals( " true ", StringComparison.OrdinalIgnoreCase))
oKey = true;
else if (dfk.Equals( " false ", StringComparison.OrdinalIgnoreCase))
oKey = false;
else if (dfk.Equals( " other ", StringComparison.OrdinalIgnoreCase))
oKey = " other ";
else if ( int.TryParse(dfk, out i))
oKey = i;
else
throw new NotSupportedException( " 參數取值錯誤: " + dfkv);
Alias[oKey] = dfv;
}
}
break;
default:
throw new NotSupportedException( " 不支持的參數名: " + pk);
}
}
}
}
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
AnalyseConvertParameter(parameter as string);
try
{
var sourceType = value.GetType();
if (IsReverse && sourceType == typeof( bool))
value = !(( bool)value);
if (targetType == typeof( string))
{
if (Alias != null && Alias.ContainsKey(value))
return Alias[value];
else if (Alias != null && Alias.ContainsKey( " other "))
return Alias[ " other "];
else
return value == null ? "" : value.ToString();
}
if (targetType == typeof( bool))
{
if (sourceType == typeof(Visibility))
return (Visibility)value == Visibility.Visible;
}
else if (targetType.IsEnum)
{
if (sourceType == typeof( bool) && targetType == typeof(Visibility))
{
return ( bool)value ? Visibility.Visible : Visibility.Collapsed;
}
else
{
return Enum.Parse(targetType, value.ToString(), true);
}
}
else
{
return System.Convert.ChangeType(value, targetType);
}
return System.Convert.ChangeType(value, targetType);
}
catch
{
return null;
}
}
public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Convert(value, targetType, parameter, culture);
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows;
namespace MoodSunshiny.WPF.Converter
{
/// <summary>
/// 一個通用的類型轉換器,可以提供更多轉換控制參數
/// </summary>
public class GenericTypeConverter : IValueConverter
{
/// <summary>
/// 是否反轉轉換源參數值
/// 僅對bool類型的值有效
/// </summary>
private bool IsReverse { get; set; }
/// <summary>
/// 用於將轉換結果映射為其它字符串
/// 例如:Alias=True:是|False:否
/// </summary>
private Dictionary< object, string> Alias { get; set; }
/// <summary>
/// 解析轉換參數
/// </summary>
private void AnalyseConvertParameter( string convertParameter)
{
/* 設置參數默認值 */
IsReverse = false;
Alias = null;
if (! string.IsNullOrEmpty(convertParameter))
{
var pkvs = convertParameter.Split( new char[] { ' , ' }, StringSplitOptions.RemoveEmptyEntries);
foreach ( var pkv in pkvs)
{
var pkvo = pkv.Split( new char[] { ' = ' }, StringSplitOptions.RemoveEmptyEntries);
if (pkvo.Length != 2)
throw new NotSupportedException( " 不支持設置: " + pkv);
var pk = pkvo[ 0].Trim();
var pv = pkvo[ 1].Trim();
switch (pk)
{
case " IsReverse ":
bool b;
if (! bool.TryParse(pv, out b))
throw new NotSupportedException( " 參數取值錯誤: " + pkv);
else
IsReverse = b;
break;
case " Alias ":
{
Alias = new Dictionary< object, string>();
var dfkvs = pv.Split( new char[] { ' | ' }, StringSplitOptions.RemoveEmptyEntries);
foreach ( var dfkv in dfkvs)
{
var dfkvo = dfkv.Split( new char[] { ' : ' }, StringSplitOptions.RemoveEmptyEntries);
if (dfkvo.Length != 2)
throw new NotSupportedException( " 不支持設置: " + dfkvo);
var dfk = dfkvo[ 0].Trim();
var dfv = dfkvo[ 1].Trim();
object oKey = null;
int i;
if (dfk.Equals( " true ", StringComparison.OrdinalIgnoreCase))
oKey = true;
else if (dfk.Equals( " false ", StringComparison.OrdinalIgnoreCase))
oKey = false;
else if (dfk.Equals( " other ", StringComparison.OrdinalIgnoreCase))
oKey = " other ";
else if ( int.TryParse(dfk, out i))
oKey = i;
else
throw new NotSupportedException( " 參數取值錯誤: " + dfkv);
Alias[oKey] = dfv;
}
}
break;
default:
throw new NotSupportedException( " 不支持的參數名: " + pk);
}
}
}
}
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
AnalyseConvertParameter(parameter as string);
try
{
var sourceType = value.GetType();
if (IsReverse && sourceType == typeof( bool))
value = !(( bool)value);
if (targetType == typeof( string))
{
if (Alias != null && Alias.ContainsKey(value))
return Alias[value];
else if (Alias != null && Alias.ContainsKey( " other "))
return Alias[ " other "];
else
return value == null ? "" : value.ToString();
}
if (targetType == typeof( bool))
{
if (sourceType == typeof(Visibility))
return (Visibility)value == Visibility.Visible;
}
else if (targetType.IsEnum)
{
if (sourceType == typeof( bool) && targetType == typeof(Visibility))
{
return ( bool)value ? Visibility.Visible : Visibility.Collapsed;
}
else
{
return Enum.Parse(targetType, value.ToString(), true);
}
}
else
{
return System.Convert.ChangeType(value, targetType);
}
return System.Convert.ChangeType(value, targetType);
}
catch
{
return null;
}
}
public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Convert(value, targetType, parameter, culture);
}
}
}