Ookii.Dialogs - 确保在“进度”对话框上方显示另一个对话框

时间:2012-03-07 03:08:19

标签: wpf c#-4.0 modal-dialog

如果您不熟悉 Ookii.Dialogs ,我建议您先look at this web page。它是开源,您可以在那里找到源代码,编译的二进制文档和文档示例应用程序。

在我的应用程序中,我正在使用 Ookii.Dialogs.Wpf.ProgressDialog ShowDialog(this)一个进程对话框,对文件进行一些处理(这个始终是应用程序的主窗口)。正如预期的那样,进度对话框在实际可见之前大约需要一秒钟(即使它已经在处理我的文件)。

在进度对话框的 DoWork 线程中,我还检查输出文件是否已存在,并询问用户是否覆盖每个文件或跳过输出。我使用 Ookii.Dialogs.Wpf.TaskDialog ShowDialog(this) “带命令链接的任务对话框”(看起来像{{3} })并询问用户覆盖问题 - 除非操作系统不支持它,我回到常规 MessageBox 该问题同样适用于消息框)。

  

当我的应用程序在进度对话框的 DoWork 线程的开头找到现有文件时,会出现问题。当出现任务对话框询问用户是否覆盖:

     

预期行为:任务对话框必须保持最佳状态。当出现进度对话框时(延迟1秒后),它必须出现在任务对话框后面。

     

实际行为:任务对话框不会保持最佳状态。当1s延迟后出现进度对话框时,它出现在任务对话框的顶部。

当进度对话框已经可见时,后续覆盖请求中不会发生实际行为。尽管用户可以在两个对话框之间来回切换(只是无法从其中任何一个切换到主窗口),任务对话框会在后续对话框的进度对话框中正确显示。

我正在寻找:

  • 最佳解决方案:使任务对话框在进度对话框中显示为模式 。如果用户尝试切换到进度对话框,则不允许用户这样做。
  • 第二好:即使在1秒延迟后出现进度对话框,也会使第一次出现的任务对话框保持在最顶层。

正在寻找以下内容:

  • 设置任务对话框的always-on-top标志。我不希望任务对话框始终显示在用户计算机上的每个窗口的顶部。
  • 在任务对话框出现之前添加延迟。我已经尝试了 Thread.Sleep(),即使在一个循环中,它只是挂起了所有内容的执行而没有解决问题。
  • 等到显示任务对话框之前出现进度对话框。可以在理论上工作,除了我没有找到方法来知道进度对话框是否已经出现。
  • 使对话框无模式。我希望他们都是模态的。 (除此之外,我试过让它们无模式;它无助于解决问题。)
  • 适用于任务对话框 的解决方案。它也必须适用于常规消息框。

2 个答案:

答案 0 :(得分:1)

我知道这可能会有点迟到,但我只是在我自己的程序中抢先一个类似的问题,它让我想起了这个问题。 我使用Windows FindWindowEx API函数对任务对话窗口标题属性找到对话框窗口句柄,然后使用我自己的类来创建一个Iwin32Window,然后可以将其用作消息框或任务对话的父级。 适当的代码如下(VB.NET)

    'allows us to use the handle as a window
    class window
        Implements IWin32Window
        private _handle

        public sub new(handle as intptr)
            _handle = handle
        end sub

        Public ReadOnly Property Handle As System.IntPtr Implements System.Windows.Forms.IWin32Window.Handle
            Get
                Return _h
            End Get
        End Property
    end class

    'Declare the needed DLL import
    class NativeMethods
        <DllImport("user32.dll", SetLastError:=True, ThrowOnUnmappableChar:=True, CharSet:=CharSet.Unicode, bestFitMapping:=False)>
        Public Shared Function FindWindowEx(hwndParent As IntPtr, hwndChildAfter As IntPtr, lpszClass As String, lpszWindow As String) As IntPtr
        End Function
    end class

    'Make sure you've set a window title when you run your task
    sub runTask()
        dim myDlg as Ookii.Dialogs.ProgressDialog
        'Do what you need to here
        myDlg.WindowTitle = "make sure you set a title"
    end sub
    sub myTask(sender as object, e As System.ComponentModel.DoWorkEventArgs)
         'Checks and balances here
         if fileExists then
              'this is the dialog that's running our task
              Dim dlg As Ookii.Dialogs.ProgressDialog = DirectCast(sender, Ookii.Dialogs.ProgressDialog)
              'Find the window handle
              Dim dlgHandle As IntPtr = NativeMethods.FindWindowEx(IntPtr.Zero, IntPtr.Zero, Nothing, dlg.WindowTitle)
              'make it an Iwin32Window
              dim dlgWindow as new window(dlgHandle)
              'That can then be used as a parent for the message box or the task dialog
              MessageBox.Show(dlgWindow,"The file exists, overwrite?")
         end if
    end sub

我不是很擅长评论我的代码或理解我的解释所以如果您对正在发生的事情有任何疑问,我会尽力帮助。

答案 1 :(得分:0)

今天我已经阅读了这个问题并为我找到了解决方案。尝试使用TaskDialog,这是有效的。没试过其他对话框。 我写了一个DialogControler来处理MVVM。 这个DialogControlar有一个名为'Owner'的属性,它包含WPF-MainWindow。 然后我用它来调用(在我的情况下,我来自viewmodel中的backgroundthread)并在ShowDialog中设置它。

我的代码:

using (var dialog = new Ookii.Dialogs.Wpf.TaskDialog())
        {
            dialog.WindowTitle = "My title";
            dialog.MainInstruction = "My text";
            var okButton = new Ookii.Dialogs.Wpf.TaskDialogButton(Ookii.Dialogs.Wpf.ButtonType.Ok);
            dialog.Buttons.Add(okButton);
            Owner.Dispatcher.Invoke(new Action(() => dialog.ShowDialog(Owner)));

        }

有了这个,我得到了一个最顶层的窗口。