为什么这个CancellationDisposable永远不会取消Observable.Dispose()?

我在一个WinForms应用程序中使用RxFramework。 我试图运行Observableasynchronous,并使用CancellationDisposable取消操作时,用户单击button。 但它不工作!

假设我有一个带有2个button和一个ProgressBar的窗体。 Button1_click订阅一个新线程的观察者。 然后立即按下Button2_click以取消操作。 为什么cancel.Token.IsCancellationRequested从来不是真的?

private IDisposable obs = null; private void button1_Click(object sender, EventArgs e) { var countObserver = Observable.Create<int>(observer => { var cancel = new CancellationDisposable(); if (!cancel.Token.IsCancellationRequested) { //Step 1 of a long running process using lot of resources... observer.OnNext(1); } if (!cancel.Token.IsCancellationRequested) { //Step 2 of a long running process using lot of resources... observer.OnNext(1); } if (!cancel.Token.IsCancellationRequested) { //Step 3 of a long running process using lot of resources... observer.OnNext(1); } observer.OnCompleted(); return cancel; }); obs = countObserver .ObserveOn(new ControlScheduler(this)) .SubscribeOn(Scheduler.ThreadPool) .Subscribe(i => { //Update a progress bar here... }); } private void button2_Click(object sender, EventArgs e) { if (obs != null) obs.Dispose(); } 

发生这种情况是因为传递给Observable.Create的lambda不会返回CancellationDisposable 直到完成所有步骤。 所以,行动的顺序如下:

  1. 你打电话Subscribe
  2. UI线程块
  3. 在一个ThreadPool线程上,执行进入lambda
  4. CancellationDisposable被创建
  5. 您多次检查取消,并执行整个过程。 在此期间,您的进度栏会更新。
  6. cancel从lambda返回
  7. UI线程被释放, obs获得它的价值
  8. 您单击Button2并调用obs.Dispose
  9. cancel获取cancel.Token.IsCancellationRequested=true 。 但是什么也没有发生,因为一切已经发生

这是固定的代码:

 private void button1_Click(object sender, EventArgs e) { var countObserver = Observable.Create<int>(observer => { var cancel = new CancellationDisposable(); // Here's the magic: schedule the job in background and return quickly var scheduledItem = Scheduler.ThreadPool.Schedule(() => { if (!cancel.Token.IsCancellationRequested) { //Step 1 of a long running process using lot of resources... observer.OnNext(1); } if (!cancel.Token.IsCancellationRequested) { //Step 2 of a long running process using lot of resources... observer.OnNext(1); } if (!cancel.Token.IsCancellationRequested) { //Step 3 of a long running process using lot of resources... observer.OnNext(1); } observer.OnCompleted(); }); return new CompositeDisposable(cancel, scheduledItem); }); obs = countObserver .ObserveOn(new ControlScheduler(this)) .Subscribe(i => { //Update a progress bar here... }); } 

但是,如果这样做的话,上面的代码有一些错误,但是实际上有更好的方法来完成这个工作(警告:TextArea提前编码):

 countObservable = Observable.Timer(new ControlScheduler(this)); var buttonObservable = Observable.FromEventPattern<EventArgs>( x => button1.Click += x, x => button1.Click -= x); countObservable .TakeUntil(buttonObservable) .Subscribe(x => /* Do stuff */);