Rx 示例不起作用



我试图遵循乔纳森·沃辛顿(Jonathan Worthington(在《事件驱动和反应式未来》中的机场公告示例

它编译。

问题是:SayGateChange永远不会被调用。我是Rx的新手。我一定遗漏了什么。我这里有他的代码,就像我可以转录的那样。可悲的是,网上没有可用的资源。

AddGateChange应该将一个新项目推到EventStreams.GateChanged上,而Announcer.Announcements又应该被监视,而SayGateChange应该被监视。

我使用的是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 线程",在WPF中称为"调度程序"。虽然概念非常相似,但实现却大不相同。

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

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

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

我似乎记得WinForms对从UI线程更新UI的容忍度要高得多 - 尽管此问题也发生在WPF中。这不是一件好事,因为它可能导致难以调试的不可预测的结果。例如,我注意到 WinForms MessageBox.Show 方法并不关心在哪个线程上调用它,因为它创建了自己的窗口。通常,始终建议在UI方案中使用某种形式的ObserveOn/ObserveOnDispatcher

出于这个原因,最好详细了解这些工作原理。为此,要了解相关SubscribeOn,请查看此问题。

我很惊讶您没有收到信息丰富的InvalidOperationException,说明"当前线程没有与之关联的调度程序"。我只能认为您的代码的其他部分正在吞噬异常,或者您在应用程序中也使用了 WPF 代码,并且已经创建了与 Winforms UI 线程关联的DispatcherInteraction.MsgBox背后的代码可能是吞下错误的罪魁祸首。无论哪种方式,我都建议删除rx-xaml以避免混淆。

相关内容

  • 没有找到相关文章

最新更新