我正在尝试更新一段代码,以便它模拟模式对话框,而 Reactive Extensions 感觉像是一个合适的工具,但我无法让它工作。
目前,代码如下所示:
public bool ShowConfirmationDialogs(IEnumerable<ItemType> items)
{
bool canContinue = true;
foreach (var item in items)
{
Dialog dialog = new Dialog();
dialog.Prepare(item); // Prepares a "dialog" specific to each item
IObservable<bool> o = Service.ShowDialog(dialog, result =>
{
// do stuff with result that may impact next iteration, e.g.
canContinue = !result.Condition;
});
// tried using the following line to wait for observable to complete
// but it blocks the UI thread
o.FirstOrDefault();
if (!canContinue)
break;
}
if (!canContinue)
{
// do something that changes current object's state
}
return canContinue;
}
到目前为止,当 显示的“对话框”ShowDialog
关闭时,来自 lambda 表达式的代码被用来做一些事情。调用ShowDialog
是非阻塞的,用于返回void
。
在幕后发生的事情ShowDialog
是一个对象被添加到一个ObservableCollection
,以便它显示在屏幕上。
我进行了修改ShowDialog
,以便在对话框关闭时返回订阅者的IObservable<bool>
who 呼叫OnCompleted
。这行得通。我使用以下代码对其进行了测试:
o.Subscribe(b => Console.WriteLine(b), () => Console.WriteLine("Completed"));
"Completed"
当对话框关闭时,我可以看到字符串。我的问题是上面的行是非阻塞的,所以我可能会显示几个我不想做的对话框。
我尝试了以下方法:
o.FirstOrDefault();
假设程序会在那里等到 observable 发送一些东西或完成。该程序可以阻止,但它也会冻结 UI,这意味着我永远看不到我的对话框,我永远无法关闭,所以 observable 永远不会完成。
我尝试了几种变体ObserveOn
,并SubscribeOn
尝试让 UI 线程完成其工作,但没有运气。任何想法都将不胜感激,我的主要目标是保持代码看起来连续,有点像使用Window.ShowDialog
.
总结一下:(并在评论中回答克里斯)
问题在于它ShowDialog
是非阻塞的,如上所述,预期的行为与使用Window.ShowDialog
. 现在,我要么不阻塞——但循环继续,我得到几个对话框——或者我可以阻塞(用FirstOrDefault
),但它也会阻塞 UI,这会阻止我关闭对话框以完成 observable。
更多解释:(对于 Enigmativity)
当我调用时ShowDialog
,显示的控件是模态的——从某种意义上说,它阻止用户访问应用程序的其余部分——但对该方法的调用是非阻塞的,因此执行会立即继续。在我的示例中,由于循环,这可能会显示多个对话框。该方法是非阻塞的,因为它所做的只是将一个对象添加到集合中,而我无法更改此行为。
但是,希望使用 Rx,我做了它,以便ShowDialog
返回一个IObservable
. 所以现在该方法立即返回,但我有一个对象,一旦关闭OnCompleted
由 的操作显示的控件,就会调用任何观察者。ShowDialog
我正在Subject
为此使用 a ,以防万一。
我现在想要的是在继续之前等待返回IObservable
完成,因此模拟阻塞调用。FirstOrDefault
等待部分成功,但不幸的是,它也阻塞了 UI 线程,阻止控件实际显示,从而阻止用户关闭它,从而阻止IObservable
完成。
我知道我的想法离我不远了,因为我可以通过在x秒后自动关闭对话框来让事情顺利进行。我现在需要的只是“等待”部分不要阻塞 UI,以便用户可以关闭控件而不是计时器。