我有一个可观察的,用于显示确认对话框,大致是签名:
IObservable<DialogResult> ShowDialog(string title, string message);
这向用户显示了对话框,带有是/否按钮组合。
在我的主窗口中,我正在访问结束事件:
this.Events().Closing.[Do something here]
我希望能够:
CancelEventArgs.Cancel
属性设置为true。我尝试过直接订阅:
this.Events().Closing.Subscribe(e =>
{
var res = Dialogs.ShowDialog("Close?", "Really Close?").Wait();
e.Cancel = res == DialogResult.Ok;
});
但由于Wait()
调用而挂起,我还尝试了异步变体:
this.Events().Closing.Subscribe(async e =>
{
var res = await Dialogs.ShowDialog("Close?", "Really Close?");
e.Cancel = res == DialogResult.Ok;
});
哪个不好,因为它马上就会回来。
我真正想要的是:
this.Events().Closing.ThenDo(_ => Dialogs.ShowDialog("Close?", "Really Close?"))
.Subscribe((cancelEventArgs, dialogResult) =>
{
cancelEventArgs.Cancel == dialogResult == DialogResult.Ok;
});
但那不存在,我知道这里的关键在于我如何结合这两个可观察对象,但我不知道怎么做,而且文档有点亮实际例子。
答案 0 :(得分:2)
你需要来阻止关闭事件处理程序,因此异步(或Rx操作)在这里不会对你有所帮助。
但您还需要以仍处理UI事件的方式阻止它,因此UI不会冻结。
最常见的解决方案是使用Window.ShowDialog而不是Show,并且此代码有效:
this.Events().Closing.Subscribe(e =>
{
var ret = new Window().ShowDialog();
e.Cancel = true;
});
但是在你的ShowDialog Rx方法中使用它会使其订阅调用块,并且这不太可能你想要的(对于其他情况,在这种情况下,它 你需要的)。
或者你可以运行一个内部调度程序循环,如下所示:
this.Events().Closing.Subscribe(e =>
{
var dialog = Dialogs.ShowDialog("Close?", "Really Close?");
var dispatcherFrame = new DispatcherFrame();
dialog.Take(1).Subscribe(res => {
e.Cancel = res == DialogResult.Ok;
dispatcherFrame.Continue = false;
});
// this will process UI events till the above fires
Dispatcher.PushFrame(dispatcherFrame);
});
只有在两个窗口都使用相同的Dispatcher时才会起作用。
编辑:
或者,您可以通过总是取消关闭来避免阻止,并在以后自己关闭表单,这可能更多Rx-way,即:
var forceClose = default(bool);
this.Events().Closing
.Where(_ => !forceClose)
.Do(e => e.Cancel = true)
.SelectMany(_ => Dialogs.ShowDialog("Close?", "Really Close?"))
.Where(res => res == DialogResult.Ok)
.Do(_ => forceClose = true)
.Subscribe(_ => this.Close());
答案 1 :(得分:-1)
组合到可观察流的最佳方法是CombineLatest。 当使用每个流中的最后一个值更新任一个时,它将触发。