【问题标题】:Silverlight Confirm Dialog to Pause ThreadSilverlight 确认对话框以暂停线程
【发布时间】:2011-01-07 23:34:23
【问题描述】:

我正在尝试使用 Silverlight 的 ChildWindow 对象进行确认对话框。

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

例如:

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

如果用户点击 OK,将在 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 将是错误的,并且循环将继续超过 3。

我只是想知道,我该如何正确地解决这个问题。 Silverlight 是单线程的,所以我不能只是让线程进入睡眠状态,然后在我准备好时将其唤醒,所以我只是想知道人们还有什么可以推荐的吗?

我考虑过颠倒逻辑 - 即将我想要发生的动作传递给 Yes/No 事件,但在我的具体情况下,这不太可行。

提前致谢!

【问题讨论】:

    标签: silverlight dialog confirm childwindow


    【解决方案1】:

    我认为您无法像使用 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工作流。
    • +1。次要观点:你不是说yield return confirm in YourMethod吗?
    【解决方案2】:

    您可以使用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)。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 这与问题无关 - 他要求阻止呼叫。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-09
      • 2019-05-01
      • 1970-01-01
      • 2011-05-24
      • 2016-02-02
      • 2023-04-03
      相关资源
      最近更新 更多