原文:http://www.atmarkit.co.jp/fdotnet/introrx/introrx_02/introrx_02_03.html

作者:河合 宜文
合成用的方法
本章将介绍一些Rx代表性的方法。
○ SelectMany 方法
SelectMany 方法是 Rx 中最常用的方法之一。例如将鼠标移动事件插入鼠标按下事件中,甚至对于序列自身的修改替换。另外,从第一个异步结果中启动第2个异步处理,这对于使用Rx进行异步编程是非常重要的。

SelectMany的处理图
根据 A 序列的值,后续用 B 序列的值进行插入替换。

// 替换别的Observable的内容
// 结果:10, 10, 11, 10, 11, 12
Observable.Range(1, 3).SelectMany(x => Observable.Range(10, x)).Subscribe(Console.WriteLine);// 实际的替换过程
// { x = 1, y = 10 }
// { x = 2, y = 10 }
// { x = 2, y = 11 }
// { x = 3, y = 10 }
// { x = 3, y = 11 }
// { x = 3, y = 12 }
var query = from x in Observable.Range(1, 3)from y in Observable.Range(10, x)select new { x, y };
query.Subscribe(Console.WriteLine);

Range(1, 3)(A)序列的第一个值(x=1)代入后面的 Range(10, x) 中(B),因此被“10”替换,A 的第二个值(x=2)在 B 中"10", "11”代替,A的第三个值(x=3)则是被 "10","11","12"代替。
○ Concat方法
Concat 是将2个序列进行连接的方法。这个时候,直到第一个序列终止前,第二个序列的值就会被忽略掉。我们可以理解是在第一个序列的结尾追加上另一个序列。

代码如下例:

// 运行结果:1, 2, 3, -1, -1, -1
Observable.Range(1, 3).Concat(Observable.Repeat(-1, 3)).Subscribe(Console.WriteLine);

不仅仅是2个序列结合,复数(IEnumerable<IObservable<T>>)的连接也是可能的,在想明确规定执行顺序的场景里可以适用。
○ Merge 方法
Merge会将所有的值都会合并进来。不只是2个对象的连接,也可以进行多个对象的连接。如果要对应多个控件的共通处理的话,使用Merge是很方便的。

// WindowsForm中的4个TextBox控件全部设定为:
// “DragDropEffects.All”
new[] { textBox1, textBox2, textBox3, textBox4 }.Select(x => Observable.FromEventPattern<DragEventArgs>(x, "DragEnter")).Merge().Subscribe(x => x.EventArgs.Effect = DragDropEffects.All);// 上面的Merge方法是下面的代码的变形,
// 修改为:IEnumerable<IObservable<T>>进行Merge
// 代码变得更简洁
Observable.Merge(Observable.FromEventPattern<DragEventArgs>(textBox1, "DragEnter"),Observable.FromEventPattern<DragEventArgs>(textBox2, "DragEnter"),Observable.FromEventPattern<DragEventArgs>(textBox3, "DragEnter"),Observable.FromEventPattern<DragEventArgs>(textBox4, "DragEnter")
);

乍一看 IEnumerable<IObservable<T>> 对象的Merge好像有点奇怪,但结合 Linq2Object 使用的 IEnumerable<IObservable<T>> 的确能节省代码。

○ Zip 方法
Zip方法是A和B中各取1个值为一组(2个值)进行配对处理。一边的值如果发生偏移,那么Zip会直到取到2个值为止才输出。如下图所示:

如下代码所示,使用Zip方法将 Interval 方法(指定时间间隔发行值)和Timestamp(实际时刻)进行组合的结果。

// 結果:
// { x = 0@2011/12/20 7:37:15 +09:00, y = 0@2011/12/20 7:37:17 +09:00, now = 2011/12/20 7:37:17 +09:00 }
// { x = 1@2011/12/20 7:37:16 +09:00, y = 1@2011/12/20 7:37:20 +09:00, now = 2011/12/20 7:37:20 +09:00 }
// { x = 2@2011/12/20 7:37:17 +09:00, y = 2@2011/12/20 7:37:23 +09:00, now = 2011/12/20 7:37:23 +09:00 }
// { x = 3@2011/12/20 7:37:18 +09:00, y = 3@2011/12/20 7:37:26 +09:00, now = 2011/12/20 7:37:26 +09:00 }
// { x = 4@2011/12/20 7:37:19 +09:00, y = 4@2011/12/20 7:37:29 +09:00, now = 2011/12/20 7:37:29 +09:00 }
// { x = 5@2011/12/20 7:37:20 +09:00, y = 5@2011/12/20 7:37:32 +09:00, now = 2011/12/20 7:37:32 +09:00 }
// { x = 6@2011/12/20 7:37:21 +09:00, y = 6@2011/12/20 7:37:35 +09:00, now = 2011/12/20 7:37:35 +09:00 }
Observable.Interval(TimeSpan.FromSeconds(1)).Timestamp().Zip(Observable.Interval(TimeSpan.FromSeconds(3)).Timestamp(), (x, y) => new { x, y, now = DateTimeOffset.Now }).Subscribe(Console.WriteLine);

1秒间隔的timestamp序列和3秒间隔的timestamp序列,进行组合的结果。

○ CombineLatest 方法
类似 Zip 方法,两边引发“值”时,取得最新的值输出。如下图所示,两边都引发事件,且需要对两边的事件都需要处理的场景:

A和B的序列,任何一边在引发变化时都会取出两边最新的值输出。

如下,2个Checkbox,进行Check变换时,每次都会将两个Checkbox的Checked状态输出。

public static class ToggleButtonExtensions
{// WPF/Silverlight/WP7のToggleButton控件(Checkbox)// 如果Check状态变化 IsChecked属性值也跟着变化public static IObservable<bool> IsCheckedAsObservable(this ToggleButton button){var checkedAsObservable = Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(h => (sender, e) => h(e),h => button.Checked += h, h => button.Checked -= h);var uncheckedAsObservable = Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(h => (sender, e) => h(e),h => button.Unchecked += h, h => button.Unchecked -= h);return Observable.Merge(checkedAsObservable, uncheckedAsObservable).Select(_ => button.IsChecked.Value);}
}// checkBox1和checkBox2两个CheckBox
// 同时选中时,MessageBox才表示。
checkBox1.IsCheckedAsObservable().CombineLatest(checkBox2.IsCheckedAsObservable(),(isChecked1, isChecked2) => new { isChecked1, isChecked2 }).Where(x => x.isChecked1 && x.isChecked2).Subscribe(_ => MessageBox.Show("同时选择!"));

“checkBox1.IsCheckedAsObservable()"和"checkBox2.IsCheckedAsObservable()"的序列,双方任何一个状态发生改变时,都会取得两个最新的选择状态值输出。

但是,需要注意的是,在XAML中需要绑定CheckBox的IsChecked属性。XAML中,数据绑定是非常常用的。GUI编程中Rx的利用范围不能说是非常广。为了在XAML中更好的使用 Rx,有几个第三方的库可以利用。一个叫“ReactiveUI”,可以再MVVM模式开发中,对于ViewModel开发提供强有力的支持。另一个是笔者开发的“ReactiveProperty”,属性自身可以绑定而且是 IObservable<T> ,通过声明式的 CanExecute 利用 ReactiveCommand 可以与 View 分离。

○ Scan方法

最后,这个Scan方法不是连接方法而是一个集计的方法。Scan方法是1个前面的“结果”和现在的“值”进行合成输出的。因为可以获得1个前面的结果值,所以进行差分(累计)计算时使用比较方便。如下图所示:

A序列中,1个前面的“结果”(中间褐色的横线)和当前的“值”(上面蓝色的横线)进行合成。
Scan 方法就像 Linq2Object 中的 Aggregate 方法在计算时,列举的全部中间结果。

// 1, 3(=1+2), 6(=3+3), 10(=6+4), 15(=10+5)
Observable.Range(1, 5).Scan((x, y) => x + y).Subscribe(Console.WriteLine);

Range(1, 5) 的序列中,第一次,当前值为“1”,而累计(x+y的)结果还没有,因此第一次结果为“1”,第二次,当前值为“2”,累计结果为“1”所以结果为“3”,第三次,当前值为“3”累计结果为“3”,所以结果为“6”,这样的中间计算结果通过 Subscribe 发布给订阅者。

到此介绍了 Reactive Extensions(Rx) 的基本设计思想,事件的使用方法,以及一些合成方法。以后将介绍一下关于异步以及关系到时间处理的使用方法。

p, span, div, pre { font-family:'Microsoft YaHei';}

Reactive Extensions (Rx) 入门(5) —— Rx的事件编程③相关推荐

  1. Reactive Extensions (Rx) 入门(3) —— Rx的事件编程①

    原文:http://www.atmarkit.co.jp/fdotnet/introrx/introrx_01/introrx_01_02.html 作者:河合 宜文 前面两章介绍了Rx的概要和安装方 ...

  2. Reactive Extensions (Rx) 入门(4) —— Rx的事件编程②

    原文:http://www.atmarkit.co.jp/fdotnet/introrx/introrx_01/introrx_02_02.html 作者:河合 宜文 事件是什么?用Rx来处理事件的优 ...

  3. 牛刀小试:使用Reactive Extensions(Rx),对短时间内多次发生的事件限流

    我之前有一篇文章介绍到了Reactive Extension这个组件,请参考下面的文章,其中有一些基本的概念和相关的链接 牛刀小试:使用Reactive Extensions(Rx),一行代码实现多线 ...

  4. Reactive Extensions入门(4):Rx实战

    Reactive Extensions(Rx)的优点在于能够将传统的异步编程方式从支离破碎的代码调用中解放出来.传统的采用回调的异步编程方式会使得代码很零散,尤其是异步嵌套异步的时候,代码块很难管理. ...

  5. Reactive Extensions(Rx) 学习

    Bruce Eckel(著有多部编程书籍)和Jonas Boner(Akka的缔造者和Typesafe的CTO)发表了"反应性宣言",在其中尝试着定义什么是反应性应用. 这样的应用 ...

  6. Reactive Extensions for .NET (Rx)

    LINQ to Object使用IEnumerable和IEnumerator两个接口来迭代数据集.枚举器的MoveNext()方法用于从前一个元素枚举到下一个元素,而Current属性则用于检索个别 ...

  7. Reactive Extensions 相见恨晚的Rx.Net

    何为Reactive Extensions(Rx) Rx是一个遵循函数式编程的类库,它引用观察者以及迭代器设计模式对可观察对象产生的数据进行异步消费.使用Rx,开发人员将使用LINQ运算符操作异步数据 ...

  8. Resources about Rx(Reactive Extensions)

    为什么80%的码农都做不了架构师?>>>    http://msdn.microsoft.com/en-us/library/hh242985(v=VS.103).aspx htt ...

  9. 2、Reactive Extensions for .NET(译)

    本文转自:http://www.cnblogs.com/hebeiDGL/p/3405175.html 实验3-引入 .net 中的 events 到 Rx 目标:前面实验中的使用各种工厂构造方法创建 ...

最新文章

  1. 《火星救援VR》原班人马打造全新AR游戏,让可爱小飞龙伴随你左右
  2. php soap webservice 实例
  3. Windows7自带桌面截图不小心删了怎么办?
  4. 跟互联力量学Silverlight之十_如何完整安装Silverlight 4中文版
  5. js window.onlload 自遐想
  6. 关于Orchard CMS
  7. (04)FPGA学习基础
  8. MongoDB学习系列9:MongoDB里的若干规则
  9. atlas mysql怎么连接_Atlas安装配置教程 Atlas怎么安装配置
  10. Xstream 学习地址
  11. 虚拟机环境+Hadoop环境搭建
  12. 关于清除丢失贴图与IES文件
  13. 汇佳学校|应博丞:不及格“逆袭”全科满分,粉丝科普博主唤醒想象力
  14. 常用工具方法(7S,28,SWOT,PDCA,SMART,6W2H,时间管理四矩阵,WBS,碎石分析,ORID)
  15. 江西财大计算机研究生是统考,江西财经大学计算机技术在职研究生招生简章
  16. Pytorch踩坑记:赋值、浅拷贝、深拷贝三者的区别以及model.state_dict()和model.load_state_dict()的坑点
  17. 基于CEP的量化交易平台建设
  18. 【Flink实战系列】Lorg/apache/flink/kafka/shaded/org/apache/kafka/clients/consumer/ConsumerRecord;)Ljava/
  19. centos 6.7 GRUB配置
  20. 个人博客系统【项目篇】

热门文章

  1. php百度登录完整代码_百度熊掌号专业问答PHP方式推送完整代码(附说明)
  2. 微信hook3.1.0.72源码
  3. heritrix3 java_heritrix 3.2.0 详解 1 -- 环境搭建
  4. 大学计算机基础powerpoint实验,大学计算机基础实验指导及习题集.ppt
  5. python将窗口至于最前端的方式pygetwindow
  6. qt for android开发百度地图(一步步带图详解)
  7. 使用计算机粘贴板的步骤,如何打开剪贴板,详细教您电脑如何打开剪贴板
  8. 电子元件学习——晶闸管(可控硅)
  9. 强大的刻盘软件 Ashampoo Burning Studio 9.20 中文版 + 注册码下载
  10. 2023年JAVA面试宝典(全网最全未来十年可用)