Rx 示例不工作

Rx Example not working

我正在尝试跟随 Jonathan Worthington 在 An Event-driven and Reactive Future

中的机场公告示例

编译通过。

问题:SayGateChange 从未被调用。我是 Rx 的新手。我一定是遗漏了什么。我这里有他的代码,正如我可以转录的那样。遗憾的是,网上没有可用的资源。

AddGateChange 应该将一个新项目推送到 EventStreams.GateChanged 上,而 EventStreams.GateChanged 又应该被 Announcer.Announcements 观看,而 Announcer.Announcements 应该被 [=11= 观看].

我使用的是 Windows 表单,而不是 WPF,如果有区别的话。

如果可以的话,我很乐意将其放入控制台应用程序或 LinqPad。

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading;

public class frmAnnouncements
{

    Announcer _Announcer = new Announcer();

    ObservableCollection<string> Announcements = new ObservableCollection<string>();

    private void frmRx_Load(System.Object sender, System.EventArgs e)
    {
        PopulateAnnouncements();

        AddGateChange();

    }

    private void AddGateChange()
    {
        EventStreams.GateChanged.OnNext(new GateChanged {
            Destination = "DAL",
            FlightCode = 1503
        });
    }

    private void PopulateAnnouncements()
    {
        _Announcer.Announcements.ObserveOnDispatcher().Subscribe(SayGateChange);
    }

    private void SayGateChange(string Message)
    {
        Interaction.MsgBox(Message);
    }

    public class GateChanged
    {
        public string FlightCode;
        public string Destination;
    }

    public class EventStreams
    {
        public static Subject<GateChanged> GateChanged = new Subject<GateChanged>();
    }

    public class Announcer
    {

        public Announcer()
        {
            this.Announcements = EventStreams.GateChanged.Select(e => string.Format("gate change {0} to {1} ", e.FlightCode, e.Destination));
        }


        public IObservable<string> Announcements;
    }
    public frmAnnouncements()
    {
        Load += frmRx_Load;
    }

}

正如@Enigmativity 所说,使用 ObserveOnDispatcher() 是一个问题 - 尽管不看 Interaction.MsgBox 很难 100% 确定它是整个故事 - 我猜它可能在视频中,不过有点长,没看完

ObservableOnDispatcher() 的使用表明您为 Rx 引入了错误的 nuget 包:

  • 对于 WPF 应用程序,使用 rx-xaml(已弃用的同义词 rx-wpf),它提供扩展方法 ObserveOnDispatcher()
  • 对于 Winforms 应用程序,使用 rx-winforms,它提供扩展方法重载 ObserveOn(Control)

Winforms 和 WPF 都有相似的设计,用户界面在专用线程上运行。在 Winforms 中,这称为 "UI Thread",在 WPF 中称为 "Dispatcher"。尽管概念非常相似,但实现方式却大不相同。

WPF 中的

ObserveOnDispatcher 将导致在调度程序线程上调用观察者通知 OnXXX

在您使用 ObserveOn(this) 的 WinForms 中,this 通常是表单本身。对于任何 WinForms 控件,这将找到控件的 SynchronizationContext 和 Post OnXXX 通知。

这两个重载都很聪明,因为如果您碰巧在正确的 Dispatcher 线程上或已经在 UI 线程上,调用是直接的。

我似乎确实记得 WinForms 更容忍从 UI 线程更新 UI - 尽管这个问题也出现在 WPF 中。这不是一件好事,因为它会导致难以调试的不可预测的结果。我注意到 WinForms MessageBox.Show 方法,例如,不关心它在哪个线程上被调用,因为它创建了它自己的 window。通常,在 UI 场景中始终建议使用某种形式的 ObserveOn/ObserveOnDispatcher

因此,最好详细了解它们的工作原理。为此,要了解相关的 SubscribeOn,请查看 this question

我很惊讶你没有得到一个信息 InvalidOperationException 说明 "The current thread has no Dispatcher associated with it." 我只能认为你的代码的其他部分正在吞噬异常,或者你正在使用 WPF 代码应用程序以及与 Winforms UI 线程关联的 DispatcherInteraction.MsgBox 后面的代码可能是吞下错误的罪魁祸首。无论哪种方式,我建议删除 rx-xaml 以避免混淆。