在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);

}

}

}