[UWP]了解IValueConverter
原文:[UWP]了解IValueConverter

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);elsereturn new SolidColorBrush(Colors.Green);}}
}

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

<TextBlock  Text="Score : 60" Foreground="{Binding TestResultBrush}"/>

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

var testResult = DataContext as TestResult;
if (testResult != null)
{if (testResult.Passed)ResultElement.Foreground = new SolidColorBrush(Colors.Red);elseResultElement.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:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><Grid.Resources><local:BoolToBrushConverter x:Key="BoolToBrushConverter"/></Grid.Resources><TextBlock  Text="Score : 60" Foreground="{Binding Passed,Converter={StaticResource BoolToBrushConverter}}"/>
</Grid>

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中ConverterParameter和FallbackValue两个参数,常常用于解决IValueConverter中HardCode的问题。在Binding中,FallbackValue指明了如果Binding没法返回任何值时使用的值,在IValueConverter中返回DependencyProperty.UnsetValue即告诉Binding要使用FallbackValue的值。

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

<Grid><Grid.Resources><local:BoolToValueConverter x:Key="BoolToValueConverter"/></Grid.Resources><TextBlock Text="Score : 60" Foreground="{Binding Passed,Converter={StaticResource BoolToValueConverter},ConverterParameter=Green,FallbackValue=Red}"/>
</Grid>

4. BoolToObjectConverter

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

<Grid.Resources><SolidColorBrush Color="Green" x:Key="PassedBrush"/><SolidColorBrush Color="Red" x:Key="FailedBrush"/><local:BoolToValueConverter x:Key="BoolToValueConverter"/>
</Grid.Resources>
<TextBlock Text="Score : 60" Foreground="{Binding Passed,Converter={StaticResource BoolToValueConverter},ConverterParameter={StaticResource PassedBrush},FallbackValue={StaticResource FailedBrush}}"/>

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

<Grid.Resources><SolidColorBrush Color="Green" x:Key="PassedBrush"/><SolidColorBrush Color="Red" x:Key="FailedBrush"/><converters:BoolToObjectConverter x:Key="BoolToObjectConverter" TrueValue="{StaticResource PassedBrush}" FalseValue="{StaticResource FailedBrush}"/>
</Grid.Resources>
<TextBlock Text="Score : 60" Foreground="{Binding Passed,Converter={StaticResource BoolToObjectConverter}}"/>

5. BoolToVisibilityConverter

UWP Community Toolkit中提供了另一个常用的Converter:BoolToVisibilityConverter。这个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 - BoolNegationConverter登上历史舞台的时候了:

<StackPanel ><StackPanel.Resources><converters:BoolNegationConverter x:Key="BoolNegationConverter" /></StackPanel.Resources><TextBlock Text="Passed" Foreground="Green" Visibility="{Binding Passed}"/><TextBlock Text="Failed" Foreground="Red" Visibility="{Binding Passed,Converter={StaticResource BoolNegationConverter}}"/>
</StackPanel>

6. StringFormatConverter

UWP的Binding缺少了StringFormat,这对Binding产生了很大影响,为弥补这个缺陷,可以使用UWP Community Toolkit中的StringFormatConverter。它的代码也十分简单(其实这才是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中使用如下:

<TextBlock Text="{Binding DoubleValue,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0:N2}'}"/>
<TextBlock Text="{Binding DoubleValue,Converter={StaticResource StringFormatConverter},ConverterParameter='There are {0:N0} Items'}"/>

结果如下:

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

** TestModel.CS **

public IEnumerable<ClickMode> ClickModes => new List<ClickMode> { ClickMode.Hover, ClickMode.Press, ClickMode.Release };
<ListBox ItemsSource="{Binding ClickModes}"><ListBox.ItemTemplate><DataTemplate><TextBlock Text="{Binding }" /></DataTemplate></ListBox.ItemTemplate>
</ListBox>
<ListBox ItemsSource="{Binding ClickModes}"/>

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

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

<ListBox ItemsSource="{Binding ClickModes}"><ListBox.ItemTemplate><DataTemplate><TextBlock Text="{Binding Converter={StaticResource StringFormatConverter}}" /></DataTemplate></ListBox.ItemTemplate>
</ListBox>

可以说对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();}
}
<TextBlock Text="{Binding Date,Converter={StaticResource DateTimeValueConverter},ConverterLanguage=en-US}"/>
<TextBlock Text="{Binding Date,Converter={StaticResource DateTimeValueConverter},ConverterLanguage=zh-CN}"/>

结果如下:

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();}
}

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

<local:MyContentControl Tag="10.01" Amount="{Binding Converter={StaticResource ValueConverter},Path=Tag,RelativeSource={RelativeSource Mode=Self}}"/>

或者Resources中的字符串:

<Grid.Resources><x:String x:Key="DecimalString">10.01</x:String>
</Grid.Resources>
<local:MyContentControl Amount="{Binding Source={StaticResource DecimalString},Converter={StaticResource ValueConverter}}"/>

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

public class StringWrapper
{public string this[string key]{get{return key;}}
}
<local:MyContentControl Amount="{Binding [10.01],Source={StaticResource StringWrapper},Converter={StaticResource ValueConverter}}"/>

9. 使用IValueConverter的其它经验

9.1 统一管理IValueConverter

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

<Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Converters.xaml" /></ResourceDictionary.MergedDictionaries></ResourceDictionary>
</Application.Resources>

9.2 格式化

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

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

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

10. 结语

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

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

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

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

11. 参考

IValueConverter Interface
Binding Class
深入了解数据绑定
Converters - UWP Community Toolkit _ Microsoft Docs

posted on 2018-11-06 14:17 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/9915017.html

[UWP]了解IValueConverter相关推荐

  1. win10 uwp 如何使用DataTemplate

    这是数据模板,一般用在数组的绑定,显示数组中的元素. 假如我们有一个列表,列表里是书,包括书名.作者.还有出版,那么我们只有源信息,如何把它显示到我们的ListView,就需要DataTemplate ...

  2. Win10 UWP开发中的重复性静态UI绘制小技巧 1

    Win10 UWP开发中的重复性静态UI绘制小技巧 1 原文:Win10 UWP开发中的重复性静态UI绘制小技巧 1 介绍 在Windows 10 UWP界面实现的过程中,有时会遇到一些重复性的.静态 ...

  3. 使用UWP人脸检测API在WPF中进行人脸检测

    目录 介绍 先决条件 背景 人脸检测 标记人脸 查看模型 视图 结论 Download repository 介绍 通用Windows平台的Windows.Media.FaceAnalysis名称空间 ...

  4. UWP控件与DataBind

    原文:UWP控件与DataBind 在uwp开发中必不可少的一个环节就是各种通用的控件的开发,所以在闲暇时间汇总了一下在uwp开发中控件的几种常用写法,以及属性的几种绑定方式,有可能不全面,请大家多多 ...

  5. [UWP开发]UI模板(一)

    [UWP开发]UI模板(一) 总结一些以前用过的界面框架,贴出来给新手参考. 先介绍一个用于文章的图文混排,具有列表的格式. 左边为标题,文字内容.下面为一个List结构,包含标题和内容.右边为图片. ...

  6. [UWP]实现一个轻量级的应用内消息通知控件

    [UWP]实现一个轻量级的应用内消息通知控件 原文:[UWP]实现一个轻量级的应用内消息通知控件 在UWP应用开发中,我们常常有向用户发送一些提示性消息的需求.这种时候我们一般会选择MessageDi ...

  7. [UWP小白日记-10]程序启动屏(ios解锁既视感)

    [UWP小白日记-10]程序启动屏(ios解锁既视感) 原文:[UWP小白日记-10]程序启动屏(ios解锁既视感) 讲一下 微软爸爸的开发者大会2016又暴了个表达式动画和Windows.UI.Co ...

  8. win10 UWP 应用设置

    win10 UWP 应用设置 简单的把设置需要的,放到微软自带的LocalSettings LocalSettings.Values可以存放几乎所有数据 如果需要存放复合数据,一个设置项是由多个值组成 ...

  9. [UWP] 用 AudioGraph 来增强 UWP 的音频处理能力——AudioFrameInputNode

    原文:[UWP] 用 AudioGraph 来增强 UWP 的音频处理能力--AudioFrameInputNode 上一篇心得记录中提到了 AudioGraph, 描述了一下 什么是 AudioGr ...

最新文章

  1. Local Response Normalization作用——对局部神经元的活动创建竞争机制,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力...
  2. php 接收 oc 图片上传,php yii2接口中图片上传
  3. java利用poi读取excel_java利用POI 读取EXCEL
  4. 白领丽人:这六行盛产“钻石王老五”
  5. python-字符串方法
  6. 产品部门四大角色——PM/PD/UE/UI
  7. 轨迹分析_肌力测试 心理测评 轨迹分析 科技助力体能训练 让备战更高效
  8. ASP.NET Web Game 构架设计3--业务逻辑服务器之计时器
  9. Spring容器创建流程(1)容器创建准备
  10. linux去掉空行的几种方法
  11. opengl画的弧线 为什么有一个半径_6个1画生日蛋糕,也太简单啦【图文+视频教程】...
  12. xshell linux查看cpu,Linux系统CPU子系统,命令和监控
  13. python 数据结构包括三方面_Python数据结构:数据框
  14. zend studio php插件,Zend Studio使用技巧两则 zend studio安装 zend studio 插件 zend studio 中文...
  15. Session使用方法
  16. 数据库管理系统的未来是什么?
  17. iMX8MP方案推荐|一款适用于心电监护仪的嵌入式核心板
  18. 《生命科学50讲》课程笔记9--自我
  19. u深度做linux启动盘,u深度u盘启动盘制作教程
  20. Android Banner

热门文章

  1. vs转eclipse之工具快速上手篇
  2. 单链表的操作_二分查找
  3. 23种设计模式整体详解
  4. swift 简单语句 控制流语句
  5. linux nginx svn 安装
  6. Hadoop之zookeeper快速安装
  7. Linux守护进程简介
  8. 样式处理——提取样式文件
  9. DELL服务器利用OMSA修改BIOS设置
  10. 2017.07.05 第五组 NABCD+用户原型+用户调研