Silverlight确认对话框以暂停线程

7

我正在尝试使用Silverlight的ChildWindow对象来创建确认对话框。

理想情况下,我希望它能像MessageBox.Show()一样工作,直到用户输入后整个应用程序才停止。

例如:

for (int i = 0; i < 5; i++)
{
    if (i==3 && MessageBox.Show("Exit early?",
        "Iterator", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
    {
        break;
    }
}

如果用户点击“确定”按钮,将在第3次迭代时停止...

然而,如果我要做类似以下的操作:

ChildWindow confirm = new ChildWindow();
confirm.Title = "Iterator";
confirm.HasCloseButton = false;
Grid container = new Grid();

Button closeBtn = new Button();
closeBtn.Content = "Exit early";
closeBtn.Click += delegate { confirm.DialogResult = true; confirm.Close(); };
container.Children.Add(closeBtn);

Button continueBtn = new Button();
continueBtn.Content = "Continue!";
continueBtn.Click += delegate { confirm.DialogResult = false; confirm.Close(); };
container.Children.Add(continueBtn);

confirm.Content = container;

for(int i=0;i<5;i++) {
  if (i==3) {
    confirm.Show();
    if (confirm.DialogResult.HasResult && (bool)confirm.DialogResult) {
      break;
    }
  }
}

这显然不可行,因为线程不会停止... confirm.DialogResult.HasResult 会是 false,循环会继续超过 3。

我只是想知道如何正确地解决这个问题。Silverlight 是单线程的,所以我不能只是把线程休眠,然后在我准备好时再唤醒它,所以我想知道是否有其他人可以推荐的方法?

我考虑过反转逻辑 - 即将我希望发生的操作传递给 Yes/No 事件,但在我的特定情况下,这不太可行。

谢谢!

3个回答

13

我认为你不能像WinForms的ShowDialog那样在消息循环中阻塞代码。

然而,你可以滥用迭代器来实现相同的效果:

interface IAction { void Execute(Action callback); }

public static void ExecAction(IEnumerator<IAction> enumerator) {
    if (enumerator.MoveNext())
        enumerator.Current.Execute(() => ExecAction(enumerator));
}

class DialogAction : ChildWindow, IAction {
    void IAction.Execute(Action callback) {
       //Show the window, then call callback when it's closed
    }
}

IEnumerator<IAction> YourMethod() { 
    ...
    var confirm = new DialogAction();
    yield return confirm;
    if (confirm.DialogResult.HasResult && (bool)confirm.DialogResult)
        yield break;
    ...
}
要使用此系统,您将编写ExecAction(YourMethod());。请注意,这将是半阻塞调用,并且我根本没有测试过。
C#5的新async功能完全以相同的方式运作(实际上,async编译器代码的最初版本是基于现有迭代器实现的),但具有更好的语法支持。

它可以轻松地被采用来在后台线程中执行枚举器,从而实现非常简单的多线程UI工作流程。 - SLaks
+1. 小问题:在 YourMethod 中,您是不是想说 yield return confirm - Drew Noakes

1

您可以使用RX Framework轻松实现此目标:

var continued = Observable.FromEvent<RoutedEventArgs>(continueBtn, "Click");

var iter = new Subject<int>();

var ask = iter.Where(i => i == 3).Do(_ => confirm.Show());

iter.Where(i => i != 3 && i < 10)
    .Merge(ask.Zip(continued, (i, _) => i))
    .Do(i => Debug.WriteLine("Do something for iteration {0}", i))
    .Select(i => i + 1)
    .Subscribe(iter);

iter.OnNext(0);

该解决方案可以轻松扩展以适用于任何规则,以确定何时显示对话框。例如,假设我们想要在每3次迭代时阻止迭代并请求用户确认。您需要做的就是将条件i == 3替换为i % 3 == 0(并将i != 3替换为i % 3 != 0)。


0

看看这个项目http://silverlightmsgbox.codeplex.com/。它提供了几个有用的消息框的简单但漂亮的实现,例如确认、错误、信息、用户输入等等,可能对你有所帮助。祝你好运。


那与问题无关 - 他正在寻求阻塞调用。 - SLaks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接