我只是在winforms应用程序中第一次使用Reactive Extensions。请注意,过去4年我一直在进行网络开发,而且我对淘汰赛中的观察能力和可观察模式非常熟悉,我猜这是造成我的困惑。
无论如何,问题和代码。我有一个简单的winforms实验(见下文),我正在建立这个实验来说明我的问题。下面的订阅直到启动new中的线程完成后才运行。我可以跟踪它对OnNext的调用,但订阅根本不会激活,直到有时20-30秒。有人可以向我解释这种行为吗?
public partial class Form1 : Form
{
private Subject<int> progress;
private CancellationToken cancellationToken;
private IScheduler _scheduler;
public Form1()
{
InitializeComponent();
CancellationTokenSource source = new CancellationTokenSource();
cancellationToken = source.Token;
_scheduler = new SynchronizationContextScheduler(SynchronizationContext.Current);
}
private void Start_Click(object sender, EventArgs e)
{
progress
.ObserveOn(_scheduler)
//.Throttle(TimeSpan.FromSeconds(5))
.Subscribe(
(i) => {
progressBar1.Do<ProgressBar>(ctl =>
{
ctl.Value = i;
});
},
(ex) => { },
cancellationToken
);
Task counterTask = Task.Factory.StartNew(() =>
{
for (var i = 1; i < 101; i++)
{
Thread.Sleep(500);
progress.OnNext(i);
}
}, cancellationToken,
TaskCreationOptions.LongRunning,
TaskScheduler.FromCurrentSynchronizationContext()
);
}
private void Form1_Load(object sender, EventArgs e)
{
progress = new Subject<int>();
}
}
public static class ControlExtensions
{
public static void Do<TControl>(this TControl control, Action<TControl> action)
where TControl : Control
{
if (control.InvokeRequired)
control.Invoke(action, control);
else
action(control);
}
}
答案 0 :(得分:0)
您的问题来自于您的任务在UI线程上运行,因为您正在使用TaskScheduler.FromCurrentSynchronizationContext()
。
因此,您的各种Sleep
调用阻塞了UI线程,冻结了UI(例如无法拖动窗口)并阻止您的可观察订阅执行(因为ObserveOn
,它应该执行在UI线程调度程序上)。
将TaskScheduler.FromCurrentSynchronizationContext()
替换为TaskScheduler.Default
(后台TaskPool线程),一切都会按预期工作。
请注意,您对Do
/ Invoke
的调用是不必要的,因为您已经通过自己提供的调度程序使用了UI线程。