C# 为什么在Observable.Dispose()上从未取消此CancellationDisposable?
Im在WinForms应用程序中使用RXFramew。我试图运行一个可观察的异步,并在用户单击按钮时使用CancellationDisposable来取消操作。但它不起作用 假设我有一个有两个按钮和一个进度条的表单。按钮1\u单击订阅新线程上的观察者。按钮2\u单击后立即按下以取消操作。 为什么cancel.Token.IsCancellationRequested从来都不是真的C# 为什么在Observable.Dispose()上从未取消此CancellationDisposable?,c#,.net,windows,system.reactive,C#,.net,Windows,System.reactive,Im在WinForms应用程序中使用RXFramew。我试图运行一个可观察的异步,并在用户单击按钮时使用CancellationDisposable来取消操作。但它不起作用 假设我有一个有两个按钮和一个进度条的表单。按钮1\u单击订阅新线程上的观察者。按钮2\u单击后立即按下以取消操作。 为什么cancel.Token.IsCancellationRequested从来都不是真的 private IDisposable obs = null; private void button1_Click
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();
}
private-IDisposable obs=null;
私有无效按钮1\u单击(对象发送者,事件参数e){
var countObserver=Observable.Create(observator=>{
var cancel=new CancellationDisposable();
如果(!cancel.Token.IsCancellationRequested){
//使用大量资源的长时间运行流程的步骤1。。。
OnNext观察员(1);
}
如果(!cancel.Token.IsCancellationRequested){
//使用大量资源的长时间运行流程的步骤2。。。
OnNext观察员(1);
}
如果(!cancel.Token.IsCancellationRequested){
//使用大量资源的长时间运行流程的步骤3。。。
OnNext观察员(1);
}
observer.OnCompleted();
返回取消;
});
obs=可计数观察者
.ObserveOn(新的ControlScheduler(此))
.SubscribeOn(Scheduler.ThreadPool)
.订阅(i=>{
//在此处更新进度条。。。
});
}
私有无效按钮2\u单击(对象发送者,事件参数e){
如果(obs!=null)
obs.Dispose();
}
相反,上面的代码有很多错误,但实际上有一个更好的方法可以做到这一点(警告:在前面的TextArea中编码):
countObservable=Observable.Timer(新的ControlScheduler(this));
var buttonObservable=Observable.FromEventPattern(
x=>button1.点击+=x,x=>button1.点击-=x);
可数可观测
.TakeUntil(按钮不可维修)
.订阅(x=>/*做一些事情*/);
之所以会出现这种情况,是因为传递给的lambda是可观察的。Create
不会返回CancellationDisposable
,直到它完成所有步骤。因此,行动顺序如下:
Subscribe
ThreadPool
线程上,执行进入lambda取消一次性
已创建cancel
从lambda返回obs
获取其值按钮2
并调用obs.Dispose
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...
});
}
private void按钮1\u单击(对象发送者,事件参数e){
var countObserver=Observable.Create(observator=>{
var cancel=new CancellationDisposable();
//神奇之处在于:在后台安排工作并快速返回
var scheduledItem=Scheduler.ThreadPool.Schedule(()=>
{
如果(!cancel.Token.IsCancellationRequested){
//使用大量资源的长时间运行流程的步骤1。。。
OnNext观察员(1);
}
如果(!cancel.Token.IsCancellationRequested){
//使用大量资源的长时间运行流程的步骤2。。。
OnNext观察员(1);
}
如果(!cancel.Token.IsCancellationRequested){
//使用大量资源的长时间运行流程的步骤3。。。
OnNext观察员(1);
}
observer.OnCompleted();
});
返回新的CompositeDisposable(取消,scheduledItem);
});
obs=可计数观察者
.ObserveOn(新的ControlScheduler(此))
.订阅(i=>{
//在此处更新进度条。。。
});
}
此解决方案对于上面的示例非常有效,我有一个简单的计数器(我想我给出了一个不好的示例),但问题是当我有一个非常长的运行过程,我在使用数据库和服务,我需要在进入下一步之前进行检查。。。我将更改上面的示例…如果提前处理可观察对象,是否应调用OnCompleted?《处方指南》在这里说了什么?@BentRasmussen我不确定,但我想他们什么也没说。这取决于你决定你的可观察序列何时结束。如果取消时不调用OnCompleted
,则不会结束。根据您的具体任务,它可能是好的,也可能是坏的。就我个人而言,我倾向于认为它应该在这种情况下结束,也许有一个特殊的标志来区分成功完成和取消完成。
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...
});
}