【问题标题】:How to make ChildWindow blocking如何使 ChildWindow 阻塞
【发布时间】:2009-08-13 17:59:23
【问题描述】:

ChildWindow 是一个模态窗口,但它不会阻塞。有没有办法让它阻塞?我基本上想要一个 ShowDialog() 方法,该方法将调用 ChildWindow.Show() 但在用户关闭 ChildWindow 之前不会返回。我尝试在 ChildWindow.Show() 之后使用 Monitor.Enter() 进行阻止,但 ChildWindow 从未呈现并且浏览器只是挂起。有人有什么想法吗?

【问题讨论】:

  • 您能解释一下您要达到的目标吗?
  • 只是一个类似于 MessageBox.Show() 或 Form.ShowDialog() 的简单模态阻塞窗口
  • 我已经尝试了所有方法,但从未找到解决方案。我试图制作自己的 MessageBox。我什至尝试过异步,但它总是被锁定。在读到蒂姆豪雅说不可能拥有真正的莫代尔后,我放弃了。

标签: silverlight silverlight-3.0


【解决方案1】:

我认为它不支持这种行为。您可以在 CodePlex 上vote for it。根据您的需要,您可以look at some of Tim Heuer's workarounds here,或使用不同的自定义控件,例如Silverlight Modal Control (on CodePlex)

【讨论】:

    【解决方案2】:

    您无法在 Silverlight 中做您想做的事情。您对 UI 所做的任何更改都将在 UI 线程上运行。如果您阻止 UI 线程,用户将无法与浏览器进行交互,因此他们无法采取任何措施来解除对线程的阻止。

    如果你真的想创建一个阻塞的对话窗口,唯一的方法是从一个非 UI 线程。例如。你可以创建一个看起来像这样的方法:

        private void ShowModalDialog()
        {
            AutoResetEvent waitHandle = new AutoResetEvent(false);
            Dispatcher.BeginInvoke(() =>
            {
                ChildWindow cw = new ChildWindow();
                cw.Content = "Modal Dialog";
                cw.Closed += (s, e) => waitHandle.Set();
                cw.Show();
            });
            waitHandle.WaitOne();
        }
    

    此方法将显示一个对话窗口,并且在对话窗口关闭之前不会返回。但是这个方法只能从非UI线程调用。从 UI 线程调用它会导致死锁(因为 UI 线程正在等待只能在 UI 线程上触发的事件)。

    或者,您应该考虑使您的逻辑异步而不是强制它同步。

    【讨论】:

    • 我喜欢这个解决方案,它看起来应该可以工作,但由于它不能在 UI 线程上调用,我不确定我是否可以使用它(即使我实际上并没有在我的问题中指定这一点(因为那时我什至没有考虑过))。无论哪种方式,都是很好的解决方法。
    【解决方案3】:

    如果您想对您的子窗口关闭执行一些操作,请使用以下代码。在调用之前隐藏不需要的控件并在子窗口关闭时显示,简单:)

    ChildWindow cw = new ChildWindow(); 
    cw.Closed += new EventHandler(cw_Closed);
    cw.Show();
    

    【讨论】:

      【解决方案4】:

      您可以尝试始终取消关闭事件并稍后设置 DialogResult。

      void ConfigTemplatePopup_Closing(object sender, System.ComponentModel.CancelEventArgs e)
          {
              if (tmpDialogResult != null || DialogResult == true) return;
              tmpDialogResult = DialogResult; //this is a field
              e.Cancel = true;
              var myMessageBox = new WspMessageBox("Are you sure you want to close?", true);
              myMessageBox.Closed += (s, e2) =>
                                          {
                                              if (wspMessageBox.DialogResult == true)
                                              {
                                                  DialogResult = tmpDialogResult;
                                              }else
                                              {
                                                  tmpDialogResult = null;
                                              }
                                          };
              myMessageBox.Show();
          }
      

      【讨论】:

        【解决方案5】:

        使用async and await in Silverlight 5,您可以轻松创建一个可以阻塞的静态 Show 方法,例如

        public partial class MyDialog {
          MyResultType result;
          readonly AutoResetEvent waitHandle;
        
          MyDialog() {
            InitializeComponent();
            waitHandle = new AutoResetEvent(false);
          }
        
          public static Task<MyResultType> Show() {
            var dialog = new MyDialog();
            dialog.Show();
            dialog.Closed += (s, e) => dialog.waitHandle.Set();
            return Task<MyResultType>.Factory.StartNew(() => { 
              dialog.waitHandle.WaitOne(); return dialog.result; });
          }
        
          void OkButton_Click(object sender, RoutedEventArgs e) {
              result = new MyResultType();
              // Initialize result...
        
              Close();
          }
        }
        

        然后像这样调用对话框

        public async void TestDialog() {
          var result = await ConfirmBox.Show();
        
          // This code will be performed after the Dialog is closed.
          // use result...   
        }
        

        【讨论】:

        • -1 恐怕,因为这个 sn-p 不能编译。 Task&lt;T&gt;.Factory.StartNew() 的输出不可等待。此外,虽然这个答案将 async/await 模式引入了混合中,但它并没有解决根本问题,即您无法在不冻结浏览器的情况下阻塞 UI 线程,因此这种方法在 Keith Mahoney 的解决方案之外没有提供任何实际价值。
        • 这个 sn-p 来自我的工作项目。我将它用作对话框的常见解决方案。要编译它,您需要“异步目标包”,您可以使用 nuget 将其添加到您的项目中。请使用我的答案中的链接阅读文章。
        【解决方案6】:

        我通过创建一个具有垂直和水平对齐方式的自定义控件来创建一个“阻塞”模式对话框,然后将其添加为当前控件布局的子项。

        例如

           <Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <Rectangle Fill="LightBlue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.3" />
            </Grid>
        

        然后在自定义控件中

        Utilities.UITools.MessageBox x = new Utilities.UITools.MessageBox();
        x.SetError(e.Result);
        this.LayoutRoot.Children.Add(x);
        

        根据必须在模态中显示的内容,我将控件动态添加到模态布局中。显然,这不是一个优雅的解决方案,但至少它有效。

        【讨论】:

        • 这会在某种程度上使它成为模态,但它似乎不会阻塞,因为在用户关闭消息框之前没有函数调用会阻塞。
        • 我通过将事件链接到消息框来阻止它。因此,它会阻塞程序的其余部分,直到事件触发
        猜你喜欢
        • 2013-11-16
        • 2019-03-07
        • 2012-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-19
        相关资源
        最近更新 更多