小序:

通过前面几个章节的学习,我们已经了解了Data Binding的基本常识和简单的使用方法。今天让我们更进一步,学习一下多路Data Binding。

说实话,起“脚踩N条船”这个标题,实在有点不雅,可为了让大家记忆方便,我也管不了那么多鸟~~~那么什么是多路Binding、它有什么用、怎么用呢?

正文:

让我们分析这样一个需求——UI上有若干个文本框和一个“提交”按钮,这些文本框都是用户必须填写的,如果不都填写,提交按钮是不可用的。

习惯了使用WinForm的同学可能脑子里已经开始飞速地搜寻使用Event来解决的方案了。实际上,在WPF里使用多路Data Binding将非常简单。所谓“多路Binding(也可以叫复合Binding)”就是指某个元素的Dependency Property的值不是由单一的数据源来决定,而是由多个数据源(通过一定逻辑)共同决定的,我们一般会把逻辑写在Converter里。是不是颇有些“脚踩N条船”的意思?

多路Binding使用的类是MultiBinding类,这个类实际上就是对一组Binding对象的包装——本质上并没有影响Binding是“一对一”的基本理论。

下面让我们动手实现这个例子,因为大家已经对WPF的基本编程很熟悉了,所以我只把核心代码写在下面(又一次,我违反代码维护性原则,把它们写在了窗体的构造程序中)。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Data;
  8. using System.Windows.Documents;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using System.Windows.Navigation;
  13. using System.Windows.Shapes;
  14. namespace MultiBindingSample
  15. {
  16. public partial class Window1 : Window
  17. {
  18. public Window1()
  19. {
  20. InitializeComponent();
  21. // 准备作为基础的“一对一”子Binding
  22. Binding b1 = new Binding("Text") { Source = this.textBox1 };
  23. Binding b2 = new Binding("Text") { Source = this.textBox2 };
  24. Binding b3 = new Binding("Text") { Source = this.textBox3 };
  25. Binding b4 = new Binding("Text") { Source = this.textBox4 };
  26. // 准备一对一Binding的包装箱,并把子Binding装进去
  27. MultiBinding mb = new MultiBinding();
  28. mb.Bindings.Add(b1);
  29. mb.Bindings.Add(b2);
  30. mb.Bindings.Add(b3);
  31. mb.Bindings.Add(b4);
  32. // 为多路Binding配备决策逻辑(它是一个多路Converter),并设置为OneWay
  33. mb.Converter = new SubmitEnableConverter();
  34. mb.Mode = BindingMode.OneWay;
  35. // 为Button设置多路Binding
  36. this.button1.SetBinding(Button.IsEnabledProperty, mb);
  37. }
  38. }
  39. public class SubmitEnableConverter : IMultiValueConverter // 注意Converter基类的变化
  40. {
  41. public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  42. {
  43. // 使用Lambda表达式判断,只要有空的,就返回false
  44. return !values.Cast<string>().Any(text => string.IsNullOrEmpty(text));
  45. }
  46. // 因为是只从数据源到目标的方向Binding,所以,这个函数永远也不会被调到
  47. public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
  48. {
  49. throw new NotImplementedException();
  50. }
  51. }
  52. }

整个程序并没有什么难理解的,与我们以前学习的Binding最大的区别就在它的Converter上,这回使用的Converter,其基接口是IMultiValueConverter,而不是先前我们使用的IValueConverter。这个接口仍然只有两个函数需要实现一下。又因为我们这次使用的是OneWay模式,所以,代码中只有Convert函数中包含逻辑。

请大家注意,Convert函数中最重要的就是它的values参数。这个参数是一个数组,这个数组里包含的就是从一对一子Binding里送来的值(在我们的程序里,就是4个TextBox的Text属性值)。数组是可被索引的,这就意味着values里面的值是有顺序的!那么这个顺序是什么呢?这个顺序就是你调用MultiBinding.Bindings.Add(...)添加子Binding顺序——我认为这里是多路Binding一个小小的败笔——这样,写出来的代码会比较脆弱、顺序不能变,而且比较隐晦。换句话说,后来的程序员如果改变一下Add的顺序,就有可能导致程序出现很难测出的bug。

本例中,values[0]对应的是textBox1.Text属性值、values[1]对应的是textBox2.Text属性值、values[2]对应的是textBox3.Text属性值、values[3]对应的是textBox4.Text属性值。

然后,我使用Lambda表达式,判断了一下是否有某个TextBox值是空的,对这个值取反,就是Submit Button.IsEnable的值。

运行效果如下:

逻辑进阶

现在客户的需求变了。要求是,前两个文本框的内容一致、后两个文本框内容一致,这时候Submit才亮(这在注册新用户的时候经常遇到)。

要是在WinForm中使用Event实现,就会有多处事件处理函数有变更,而在这个例子中,我们只需改一两句代码就OK了。下面的代码中,我优化了格式——项目中推荐这样的格式。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Data;
  8. using System.Windows.Documents;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using System.Windows.Navigation;
  13. using System.Windows.Shapes;
  14. namespace MultiBindingSample
  15. {
  16. /// <summary>
  17. /// Interaction logic for Window1.xaml
  18. /// </summary>
  19. public partial class Window1 : Window
  20. {
  21. public Window1()
  22. {
  23. InitializeComponent();
  24. InitializeBindings(); // 拎出来封装
  25. }
  26. private void InitializeBindings()
  27. {
  28. // 声名、定义并初始化MultiBinding
  29. MultiBinding mb = new MultiBinding() { Mode = BindingMode.OneWay, Converter = new SubmitEnableConverter() };
  30. mb.Bindings.Add(new Binding("Text") { Source = this.textBox1 });
  31. mb.Bindings.Add(new Binding("Text") { Source = this.textBox2 });
  32. mb.Bindings.Add(new Binding("Text") { Source = this.textBox3 });
  33. mb.Bindings.Add(new Binding("Text") { Source = this.textBox4 });
  34. // 为Button设置多路Binding
  35. this.button1.SetBinding(Button.IsEnabledProperty, mb);
  36. }
  37. }
  38. // Converter
  39. public class SubmitEnableConverter : IMultiValueConverter // 注意Converter基类的变化
  40. {
  41. public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  42. {
  43. // 按对应值做决策
  44. if (!values.Cast<string>().Any(text => string.IsNullOrEmpty(text))
  45. && values[0].ToString() == values[1].ToString()
  46. && values[2].ToString() == values[3].ToString())
  47. {
  48. return true;
  49. }
  50. return false;
  51. }
  52. // 因为是只从数据源到目标的意向Binding,所以,这个函数永远也不会被调到
  53. public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
  54. {
  55. throw new NotImplementedException();
  56. }
  57. }
  58. }

运行效果如下:

深入浅出WPF(10)——“脚踩N条船”的多路Binding相关推荐

  1. 诺基亚无意“脚踩三只船”

    诺基亚无意"脚踩三只船" 2011年07月06日05:18北京商报我要评论(0) 字号:T|T 诺基亚总裁史蒂芬·埃洛普近日宣布,公司将放弃与英特尔共同开发的手机操作系统MeeGo ...

  2. 《深入浅出WPF》笔记——事件篇

    如果对事件一点都不了解或者是模棱两可的话,建议先去看张子阳的委托与事件的文章(比较长,或许看完了,也忘记看这一篇了,没事,我会原谅你的)http://www.cnblogs.com/JimmyZhan ...

  3. 《深入浅出WPF》笔记——绑定篇(一)

    上一节,有记录写到:在WPF里,数据驱动UI,数据占核心地位,UI次之.怎么恢复数据的核心地位,那就要先了解一下Binding. 一.Binding 基础 1.1WPF中Data Binding的带来 ...

  4. [转]深入浅出WPF(7)——数据的绿色通道,Binding

    本文转自:http://liutiemeng.blog.51cto.com/120361/95273 小序: 怎么直接从2蹦到7啦?!啊哦,实在是不好意思,最近实在是太忙了,忙的原因也非常简单--自己 ...

  5. [书目20130216]深入浅出WPF

    目录 写作缘起 WPF之What & Why 致谢 第一部分  深入浅出话XAML 第1章  XAML概览 2 1.1  XAML是什么 2 1.2  XAML的优点 3 第2章  从零起步认 ...

  6. 全凭“脚感”,这个不看路的机器人就能稳稳爬楼梯,一脚踩空也不怕 | RSS 2021...

    鱼羊 发自 凹非寺 量子位 报道 | 公众号 QbitAI 能自己走台阶: △安全绳仅用于防止意外 一不小心踩空了也能及时调整步伐. 上下斜坡更是闲庭信步. 你敢信,这只名叫Cassie的双足机器人, ...

  7. 交大博士血泪自述:不是读博的料,别上博士这条船

    一.前言原先我是准备等到毕业的那一天,痛痛快快地哭过了之后,一口气写掉这篇文章的.其实一直在零散时间打腹稿,差不多已经煲熟了.刚才有同样读博士读得凄凄惨惨切切的师兄表示期待,于是一横心决定现在就写了. ...

  8. 能挽救这条船的,唯有你图片_这是科技如何帮助普通民众挽救生命

    能挽救这条船的,唯有你图片 It's no secret that the coronavirus pandemic has millions feeling helpless and lost, a ...

  9. 《深入浅出WPF》笔记——模板篇

    原文:<深入浅出WPF>笔记--模板篇 我们通常说的模板是用来参照的,同样在WPF中,模板是用来作为制作控件的参照. 一.认识模板 1.1WPF菜鸟看模板 前面的记录有提过,控件主要是算法 ...

最新文章

  1. SAP EWM 性能优化(一)
  2. 关于64位 MS SQL 导入导出 Oracle 引发 ORA-06413 的解决方法
  3. modelsim仿真正确FPGA运行不正确的可能原因 - cm4写寄存器错
  4. Oracle cursor_sharing 参数 详解
  5. 数据中心成为生态系统向绿色氢经济转变的催化剂
  6. python中三个双引号 的作用是什么?1、多行注释 2、定义多行字符串(代替转义字符换行符 \n)
  7. JSON——IT技术人员都必须要了解的一种数据交换格式
  8. iOS UI基础-7.0 UIScrollView
  9. 根据谁创建资源授权资源
  10. C#中一些日期的相关操作
  11. Linux 建立文件夹的链接
  12. 最小生成树prim、
  13. SQLAlchemy 基本使用
  14. Java基础学习总结(115)——Java 类加载机制详解
  15. 厉害!不到30行代码,自制成语接龙小游戏
  16. oracle中的dbf是什么文件,ORACLE数据库 DBF数据恢复-dbf是什么文件
  17. css中margin和padding设置成百分比时参照物是谁
  18. 一根均线选股法_一根均线选股法视频教程
  19. 小知识 | Java中的“魔数”
  20. 鸿蒙应用分身,应用分身怎么设置?按照这个步骤操作,分分钟即可搞定它

热门文章

  1. vue中延迟加载函数
  2. 各种网页播放器代码大全
  3. linux挂在谷歌硬盘,【Colab系列】挂载谷歌硬盘详解
  4. JS获取对象属性的各种方式和区别(自身/原型属性、可枚举/不可枚举)
  5. 类似QQ登陆界面保存密码和账号下拉选择框
  6. js实现 php 的 ksort排序
  7. 小米10pro和荣耀30pro+哪个好
  8. java环境配置——JDK安装
  9. 5.6 拉普拉斯变换讲解-意境级
  10. 百战商城(十二)-项目部署