博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[UWP]了解IValueConverter
阅读量:5955 次
发布时间:2019-06-19

本文共 6940 字,大约阅读时间需要 23 分钟。

原文:

1. 前言

IValueConverter是用于数据绑定的强大的武器,它用于Value在Binding Source和Binding Target之间的转换。本文将介绍IValueConverter的用法及一些常用的实现。

2. 为什么要使用IValueConverter

假设有如下的类TestResult:

public class TestResult{    public bool Passed { get; set; }}

UI需要通过Passed这个属性决定显示结果的文字颜色为红色或绿色,一般初学者最常见的做法是修改TestResult类,添加一个和Passed相关的属性:

public class TestResult{    public bool Passed { get; set; }    public Brush TestResultBrush    {        get        {            if (Passed)                return new SolidColorBrush(Colors.Red);            else                return new SolidColorBrush(Colors.Green);        }    }}

然后在XAML上绑定到这个属性:

另一种做法是直接才Code Behind为TextBlock更改Foreground:

var testResult = DataContext as TestResult;if (testResult != null){    if (testResult.Passed)        ResultElement.Foreground = new SolidColorBrush(Colors.Red);    else        ResultElement.Foreground = new SolidColorBrush(Colors.Green);}

两种做法都不够优雅,可以指出一大堆问题:破坏了TestResult的结构,违反了开放封闭原则,令UI和数据太过耦合,太多Hard Code等。

这种情况通常都可以使用IValueConverter处理。在Binding中,IValueConverter可以用于数据呈现前将它转换成新的目标值,实现IValueConverter需要执行以下步骤:

  1. 创建一个实现了IValueConverter接口的类类;
  2. 实现public object Convert(object value, Type targetType, object parameter, string language)方法,该方法将数据转换为新目标值;
  3. 实现public object ConvertBack(object value, Type targetType, object parameter, string language),该方法执行反向转换,只有使用双向绑定才需要实现这个方法。

在这个例子里,IValueConverter的目的是将bool类型的Passed转换成Brush,实现如下:

public class BoolToBrushConverter : IValueConverter{    public object Convert(object value, Type targetType, object parameter, string language)    {        if (value is bool passed)            return new SolidColorBrush(passed ? Colors.Green : Colors.Red);        return null;    }    public object ConvertBack(object value, Type targetType, object parameter, string language)    {        throw new NotImplementedException();    }}

在XAML中使用这个Convnerter需要先将它定义为Resource,然后Binding中指定Converter到这个已定义的Resource:

3. BoolToValueConverter

在XAML漫长的历史里,IValueConverter也诞生了各种奇怪的技巧,其中最常用的是BoolToValueConverter。

public class BoolToValueConverter : IValueConverter{    public object Convert(object value, Type targetType, object parameter, string language)    {        if (value == null || (bool) value == false)            return DependencyProperty.UnsetValue;        return parameter;    }    public object ConvertBack(object value, Type targetType, object parameter, string language)    {        return Equals(value, parameter);    }}

BoolToValueConverter灵活使用了Binding中和两个参数,常常用于解决IValueConverter中HardCode的问题。在Binding中,FallbackValue指明了如果Binding没法返回任何值时使用的值,在IValueConverter中返回即告诉Binding要使用FallbackValue的值。

使用BoolToValueConverter解决了上述例子的Hard Code的问题,在XAML中使用如下:

4. BoolToObjectConverter

需要注意的是上面XAML中Green和Red都只是字符串,它们最终能被解析成SolidColorBrush是由于的支持,也就是说上述XAML语法只能用于TypeConverter支持的数据类型,而且这种写法还是太过HardCode。如果要支持复杂类型或者对应本地化等问题,可以将ConverterParameter和FallbackValue绑定到StaticResource :

虽然看上去是很灵活,但如果有大量返回同样值的BoolToValueConverter将会使XAML产生大量冗余。提供了一些常用的IValueConverter实现,其中最常用的是。BoolToObjectConverter和BoolToValueConverter功能类似,但它提供了public object TrueValue { get; set; }public object FalseValue { get; set; }两个属性,而且这两个属性是依赖属性,可以使用绑定为其赋值。使用如下:

5. BoolToVisibilityConverter

UWP Community Toolkit中提供了另一个常用的Converter:。这个Converter只是简单地继承了BoolToObjectConverter,并且为TrueValue和FalseValue设置了默认值:

public BoolToVisibilityConverter(){    TrueValue = Visibility.Visible;    FalseValue = Visibility.Collapsed;}

BoolToVisibilityConverter虽然简单,但确实好用。不过从1607以后就不需要这个Converter了,微软是说的:

从 Windows 10 版本 1607 开始,XAML 框架向 Visibility 转换器提供内置布尔值。 转换器将 true 映射到 Visible 枚举值并将 false 映射到 Collapsed,以便你可以将 Visibility 属性绑定到布尔值,而无需创建转换器。 若要使用内置转换器,你的应用的最低目标 SDK 版本必须为 14393 或更高版本。

但有时候反而需要True对应Collapsed,于是现在是另一个常用Converter - 登上历史舞台的时候了:

6. StringFormatConverter

UWP的Binding缺少了StringFormat,这对Binding产生了很大影响,为弥补这个缺陷,可以使用UWP Community Toolkit中的。它的代码也十分简单(其实这才是ConverterParameter的正确用法):

public object Convert(object value, Type targetType, object parameter, string language){    if (value == null)    {        return null;    }    if (parameter == null)    {        return value;    }    return string.Format((string)parameter, value);}

在XAML中使用如下:

结果如下:

38937-20171212104536680-189683118.png

除了弥补StringFormat的功能,StringFormatConverter还有其它的应用场景。

** TestModel.CS **

public IEnumerable
ClickModes => new List
{ ClickMode.Hover, ClickMode.Press, ClickMode.Release };

在WPF中,以上XAML都可以正常呈现,而在UWP中,以上XAML显示如下:

38937-20171212104601837-1422648733.png

这种情况可以使用StringFormatConverter显示枚举的名称:

38937-20171212104635274-1057329556.png

可以说对UWP来说StringFormatConverter十分必要。

7. language参数

public object Convert(object value, Type targetType, object parameter, string language)方法中的参数language通常用于本地化,例如可以创建一个DateTimeValueConverter:

public class DateTimeValueConverter : IValueConverter{    public object Convert(object value, Type targetType, object parameter, string language)    {        if (value is DateTime dateTime)        {            var culture = new CultureInfo(language);            return dateTime.ToString(culture.DateTimeFormat);        }        return value;    }    public object ConvertBack(object value, Type targetType, object parameter, string language)    {        throw new NotImplementedException();    }}

结果如下:

38937-20171212104710743-1070243715.png

8. targetType参数

targetType参数指转换后的目标类型,使用这个参数可以实现一个简单的Value Converter:

public class ValueConverter : IValueConverter{    public object Convert(object value, Type targetType, object parameter, string language)    {        return System.Convert.ChangeType(value, targetType);    }    public object ConvertBack(object value, Type targetType, object parameter, string language)    {        throw new NotImplementedException();    }}

虽然代码简单,但它可以解决不少问题,例如 这篇文章里提到的不能在XAML中使用decimal的问题。IValueConverter要起作用依赖于BindingSource,而在XAML中虽然很多东西都可以用来做BindingSource,例如用元素自己的Tag:

或者Resources中的字符串:

10.01

或者更进一步写一个字符串的包装类:

public class StringWrapper{    public string this[string key]    {        get        {            return key;        }    }}

9. 使用IValueConverter的其它经验

9.1 统一管理IValueConverter

由于大部分IValueConverter行为是固定的,通常我都会把常用的IValueConverter放到一个Converters.xaml,然后在App.xaml中年合并资源字典,这样不用重复写创建Converter的xaml,也避免了重复创建Converter的资源消耗:

9.2 格式化

38937-20171212112112066-1024537239.png

Binding最让人诟病的缺点就是它的语法太长太长太长,例如以上两个TextBlock,在IDE中很难判断这它们有什么不同。很多时候我都会把XAML的格式化设置成“将每个属性分行放置”,如下图:

38937-20171212104748993-1857959252.png

这样上面两个TextBlock的XAML就清晰许多了:

38937-20171212112118363-353771609.png

不过这样设置也并不全是好处,怎么设置具体还是看个人喜好和屏幕尺寸。

10. 结语

虽然IValueConverter的文章已经不少了,但还是常常见到乱来的IValueConverter实现,而且UWP的IValueConverter有一些改变,所以还是写了这篇文章。

我很想写一些常用的,或者容易用错的基础知识,但连IValueConverter都不知不觉就写得这么长了,实在没勇气写Binding的概念,何况关于Binding 已经有很多很实用的文章。

我十分清楚文章写得太长就会被“保存到Pocket”,我也想每篇文章都能在三五分钟内看完,但偏偏越基础的概念就越能写得长,而且写得简短些又会被移出博客园首页,很难把握尺度。

下一篇文章会尽量写短一些。

11. 参考

转载地址:http://lmexx.baihongyu.com/

你可能感兴趣的文章
Ionic2 下处理 Android 设备下返回按钮的事件
查看>>
linux安全问答(1)
查看>>
zabbix监控进程的CPU和内存占用量
查看>>
【自用】手工编译lnmp环境
查看>>
普通用户通过Putty密钥方式登录
查看>>
网页显示3D模型
查看>>
第六章:thymeleaf页面模版-1. 信息输出
查看>>
Ubuntu 16.04 install Docker 1.12.0
查看>>
2012《Linux杂志》读者选择奖 (Readers' Choice Awards 2012- Linux Journal)
查看>>
21天让你成为Horizon View高手—Day11:手动池的创建
查看>>
Python迭代对象、迭代器、生成器
查看>>
请求转发与重定向的区别
查看>>
大数据分析 | 百年奥运往事知多少
查看>>
矩形覆盖-----批了外皮的亲蛙跳
查看>>
@RequestParam今天才知道是咋用的..
查看>>
全国第一家FPGA云主机(FAAS)正式启动售卖,被阿里云抢先了。
查看>>
Linux 局域网路由新手指南:第 2 部分
查看>>
TensorSpace:超酷炫3D神经网络可视化框架
查看>>
横向ListView (二)—— 添加快速滚动功能及item相关事件实现
查看>>
java 开发银行支付、对账时证书相关的操作总结
查看>>