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 线程关联的 Dispatcher
。 Interaction.MsgBox
后面的代码可能是吞下错误的罪魁祸首。无论哪种方式,我建议删除 rx-xaml
以避免混淆。
我正在尝试跟随 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 线程关联的 Dispatcher
。 Interaction.MsgBox
后面的代码可能是吞下错误的罪魁祸首。无论哪种方式,我建议删除 rx-xaml
以避免混淆。