使用现有 .NET 事件进行桥接

Rx 提供工厂方法,使你能够与 .NET 中的现有异步源进行桥接,以便你可以在任何类型的数据流上使用 Rx 提供的丰富组合、筛选和资源管理功能。 本主题介绍 FromEventPattern 运算符,该运算符允许将 .NET 事件作为可观察序列“导入”到 Rx 中。 每次引发事件时,OnNext 消息都将传递到可观测序列。 然后,可以像处理任何其他可观察序列一样操作事件数据。

Rx 不旨在替换现有的异步编程模型,例如 .NET 事件、异步模式或任务并行库。 但是,当你尝试撰写事件时,Rx 的工厂方法将为你提供在当前编程模型中找不到的便利。 这尤其适用于资源维护 (例如何时取消订阅) 和筛选 (例如选择要接收) 的数据类型。 在本主题和后续内容中,你可以了解这些 Rx 功能如何帮助你进行异步编程。

将 .NET 事件转换为 Rx 可观测序列

下面的示例为鼠标移动事件创建一个简单的 .NET 事件处理程序,并在 Windows 窗体上的标签中输出鼠标的位置。

using System.Linq;
using System.Windows.Forms;
using System.Reactive;
using System.Reactive.Linq;
using System;
using WinForm;
using System.Reactive.Disposables;

class Program {
 
    static void Main() 
    {
         var lbl = new Label(); 
         var frm = new Form { Controls = { lbl } }; 
         frm.MouseMove += (sender, args) =>
         {
              lbl.Text = args.Location.ToString();
         };
         Application.Run(frm);
    }; 
}

若要将事件导入 Rx,可以使用 FromEventPattern 运算符,并提供将由桥接的事件引发的 EventArgs 对象。 FromEventPattern 运算符处理采用对象发送方和一些 EventArgs 的事件,并使用反射查找这些添加/删除方法。 然后,它将给定事件转换为具有 EventPattern 类型的可观测序列,该类型捕获发送方和事件参数。

对于具有一个参数 (非标准事件) 的委托,可以使用 FromEvent 运算符,该运算符采用一对用于附加和分离处理程序的函数。

在以下示例中,我们将 Windows 窗体的鼠标移动事件流转换为可观察序列。 每次触发鼠标移动事件时,订阅者都将收到 OnNext 通知。 然后,我们可以检查此类通知的 EventArgs 值,并获取鼠标移动的位置。

using System.Linq;
using System.Windows.Forms;
using System.Reactive;
using System.Reactive.Linq;
using System;
using WinForm;
using System.Reactive.Disposables;

class Program {
 
    static void Main() 
    {
         var lbl = new Label(); 
         var frm = new Form { Controls = { lbl } }; 
         IObservable<EventPattern<MouseEventArgs>> move = Observable.FromEventPattern<MouseEventArgs>(frm, "MouseMove");
         move.Subscribe(evt => { 
                             lbl.Text = evt.EventArgs.Location.ToString(); 
                       }) ;
         Application.Run(frm);
   }; 
}

请注意,在此示例中, move 成为一个可观察的序列,我们可以在此序列中进一步操作。 使用 LINQ 运算符查询可观测序列主题将介绍如何将此序列投影到 Points 类型的集合中并筛选其内容,以便应用程序仅接收满足特定条件的值。

事件处理程序的清理由 Subscribe 方法返回的 IDisposable 对象处理。 调用 Dispose (到达此示例中 using 块的末尾来完成) 将释放序列使用的所有资源,包括基础事件处理程序。 这基本上负责代表你取消订阅事件。

另请参阅

概念

使用 LINQ 运算符查询可观测序列