如何确定WPF窗口是否为模态窗口?

34

如何最简单地确定一个窗口是否以模态方式打开?

澄清:

我通过调用

myWindow.ShowDialog();

我有一个带有“确定”和“取消”按钮的页脚,只想在窗口以模态方式打开时显示。现在我意识到可以通过以下方式设置属性:

myWindow.IsModal = true;
myWindow.ShowDialog();

但我希望窗口本身做出决定。我想在窗口的Loaded事件中检查它是否是模态的。

更新

IsModal属性实际上并不存在于WPF窗口中。这是我创建的属性。ShowDialog()阻塞了当前线程。

我猜我可以通过检查当前线程是否被阻塞来确定窗口是否是通过ShowDialog()打开的。 我该如何做到这一点?

9个回答

41

当WPF窗口作为模态对话框时,有一个私有字段_showingAsDialog。您可以通过反射获取该值,并将其合并到扩展方法中:

当WPF窗口作为模式对话框显示时,会存在一个名为_showingAsDialog的私有字段。您可以通过反射获取该值并将其整合到扩展方法中:

public static bool IsModal(this Window window)
{
    return (bool)typeof(Window).GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(window);
}

当窗口以模态形式显示(使用ShowDialog)时,该值设置为true,并在窗口关闭后设置为false。


2
不够优雅,但是一种检测的方法。如果你升级了 .Net 框架,Microsoft 可能会尝试更改私有字段的名称,例如此处的字段,因此您的代码可能会在以后出现问题,请注意。 - Tore Aurstad

32

正是我在寻找的内容。太棒了! - Micah
4
在调用ShowModal后,某些作品不会立即起效。有些事件仍然无法确定模态... - Matze
8
如果有模态对话框正在显示,则此无模式对话框将无法运行! - MTR
2
这是不可靠的。 - Christian Findlay
尝试使用主应用程序窗口创建的模态对话框,但此方法在“已加载”中错误地报告“false”。也许有些改变了? @CMerat的答案给出了正确的答案。(Win10,WPF4.5) - fadden

5

好的,既然我的上一个想法被投票否决了,我证明了它。这个方法是可行的 - 我在一个新的WPF应用程序中测试过,所以我知道它可行:

在我的主窗口(Window1)的Loaded事件中,我执行了以下操作:

Dim frm As New Window2
frm.ShowDialog()

在我的 Window2 中,我使用了 ShowDialog() 方法。
Private _IsModal As Boolean = False 'This will be changed in the IsModal method

Public Property IsModal() As Boolean
  Get
    Return _IsModal
  End Get
  Set(ByVal value As Boolean)
    _IsModal = value
  End Set
End Property

Public Shadows Sub ShowDialog()
  IsModal = True
  MyBase.ShowDialog()
End Sub

在我的Loaded事件中,我触发了一个消息框来确保IsModal属性从False更改为True,并且它给了我True,所以我知道IsModal已经设置。 MyBase.ShowDialog()然后强制基类作为模态加载。Shadows允许我们覆盖默认行为,即使ShowDialog()方法没有声明为可重写。
虽然它不是“自我确定”的,但它不需要您从外部传递任何布尔值,并且不需要您从外部设置IsModal,它在内部设置它自己,如果您选择使用它,它可以从外部访问。它仅在使用ShowDialog()方法加载时设置该值,而不是使用Show()方法。我怀疑你会找到一个更简单的方法来做到这一点。

2
今日免费次数已满, 请开通会员/明日再来
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Window window = value as Window;
        if (window != null)
        {               
            var showingAsDialogFieldInfo = typeof(System.Windows.Window).GetField("_showingAsDialog",
                BindingFlags.NonPublic | BindingFlags.Instance);
            if ((bool) showingAsDialogFieldInfo.GetValue(window) == false)
            {
                return Visibility.Visible;
            }
        }
        return Visibility.Hidden;
    }

0

你也可以创建一个新类Dialog,它继承自Window。在Dialog类中创建一个私有变量IsDialog,并使用new关键字重写ShowDialog函数。当调用ShowDialog时,将IsDialog变量设置为true:

public class Dialog : Window
{
    private bool IsDialog;

    new public bool? ShowDialog()
    {
        IsDialog = true;
        return base.ShowDialog();
    }
}

0

如果窗口不是使用ShowDialog()打开的,Window将不允许您设置Window.DialogResult的值。因此,您可以尝试设置Window.DialogResult并查看是否会引发异常。


0

模态窗口将在关闭之前停止处理。

此示例显示非模态窗口的显示。

dim f as myWindow
f.show
someOtherMethod()

在这个例子中,someOtherMethod会在窗口启动后立即运行。
这个例子展示了如何显示一个模态框:
dim f as myWindow
f.showDialog
someOtherMethod()

在这个例子中,直到ShowDialog方法返回(也就是模态窗口已经关闭),someOtherMethod()才会运行。
编辑由于澄清:覆盖ShowDialog并传入一个布尔值。
dim f as MyWindow
f.ShowDialog(true)

然后在窗口中

Public Function Shadows ShowDialog(myVar as boolean) As Boolean
    if myVar then ShowButtons()
    return mybase.ShowDialog()
End Function 

+1 我认为这比需要使用 IsModal() 属性更可取。 - BenAlabaster

0

在Windows中使用UI自动化,我想到了这样的解决方案:

void Window2_Loaded(object sender, RoutedEventArgs e)
{
    var hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
    var el = AutomationElement.FromHandle(hwnd);

    Object oPattern = null;

    if (el.TryGetCurrentPattern(WindowPattern.Pattern, out oPattern))
    {
        var pattern = oPattern as WindowPattern;

        this.Title = pattern.Current.IsModal.ToString();
    }
}

但是这似乎不起作用。有一个IsModal属性http://msdn.microsoft.com/en-us/library/system.windows.automation.provider.iwindowprovider.ismodal.aspx,必须有一种适当的方法来获取窗口的AutomationElement并通过自动化检查其IsModal属性是否为true。


-1

能否检查窗口的父级以查看其是否被禁用?我不确定是否可以通过WPF API完成此操作,但如果没有其他方法,您可以获取WPF窗口的HWND,通过Win32 P/Invoke(或其他方式)获取其父级,然后检查其是否已禁用。

绝对不是一种干净的方法,但似乎可以起作用。


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