【问题标题】:How do I determine if a WPF window is modal?如何确定 WPF 窗口是否是模态的?
【发布时间】:2008-12-15 16:31:35
【问题描述】:

判断窗口是否以模态方式打开的最简单方法是什么?

澄清:

我打开一个窗口调用

myWindow.ShowDialog();

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

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

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

更新

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

我猜我可以通过检查当前线程是否被阻塞来确定窗口是否通过ShowDialog() 打开。我该怎么做呢?

【问题讨论】:

    标签: .net wpf


    【解决方案1】:

    只要 WPF 窗口是模式对话框,就会有一个私有字段 _showingAsDialog。您可以通过反射获得该值并将其合并到扩展方法中:

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

    当窗口显示为模式 (ShowDialog) 时该值设置为 true,一旦窗口关闭,该值设置为 false。

    【讨论】:

    • 不优雅,但一种检测方式。请注意,如果您升级 .Net 框架,Microsoft 可能会尝试更改私有字段的名称,例如这个,因此您的代码可能会在以后中断。
    【解决方案2】:

    来自http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/c95f1acb-5dee-4670-b779-b07b06afafff/

    “System.Windows.Interop.ComponentDispatcher.IsThreadModal 可以告诉您调用线程当前是否正在运行模态 hwnd。”

    【讨论】:

    • 正是我想要的。太棒了!
    • 在调用 ShowModal 后不会立即工作。有些事件仍然无法判断模态...
    • 如果模态对话框显示此无模态对话框,这将不起作用!
    • 这不可靠
    • 尝试使用由主应用程序窗口创建的模式对话框,但这种方法在Loaded 中错误地报告了“false”。也许有些东西改变了? @CMerat 的回答给出了正确的答案。 (Win10, WPF4.5)
    【解决方案3】:

    好的,自从我的最后一个想法被否决后,我证明了这一点。这有效 - 我在一个新的 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() 然后强制基类作为模态加载。阴影允许我们覆盖默认行为,即使 ShowDialog() 方法未声明为可覆盖。

    虽然它不是“自我确定”,但它不需要您从外部传入任何布尔值,也不需要您从外部设置 IsModal,它会将其设置在自身内部,可以从外部访问如果您选择以这种方式使用它。它仅在我们使用 ShowDialog() 方法加载而不是在您使用 Show() 方法时设置值。我怀疑你会找到一个更简单的方法来做到这一点。

    【讨论】:

      【解决方案4】:

      下面是一个转换器片段,当 ShowDialog 方法调用窗口时,它可用于隐藏元素:

          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;
          }
      

      【讨论】:

        【解决方案5】:

        在 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 属性是否为真。

        【讨论】:

          【解决方案6】:

          模式窗口将停止处理,直到它关闭。

          这个例子显示了一个非模态窗口

          dim f as myWindow
          f.show
          someOtherMethod()
          

          在本例中,someOtherMethod 在窗口启动后立即运行。

          这个例子显示了一个模态的显示:

          dim f as myWindow
          f.showDialog
          someOtherMethod()
          

          在这个例子中, someOtherMethod() 直到 ShowDialog 方法返回(这意味着模态窗口已经关闭)才会运行

          编辑由于澄清: 覆盖 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() 属性更可取。
          【解决方案7】:

          您还可以创建一个继承自 Window 的新类 Dialog。在 Dialog 类中创建一个私有变量 IsDialog 并使用 new 覆盖 ShowDialog 函数。调用 ShowDialog 时将 IsDialog 变量设置为 true:

          public class Dialog : Window
          {
              private bool IsDialog;
          
              new public bool? ShowDialog()
              {
                  IsDialog = true;
                  return base.ShowDialog();
              }
          }
          

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              【解决方案9】:

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

              绝对不是一个干净的方法,但它似乎可以工作。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-08-12
                • 1970-01-01
                • 2011-06-08
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-09-27
                • 2018-07-15
                相关资源
                最近更新 更多