【问题标题】:Modal Dialog not showing on top of other windows模态对话框未显示在其他窗口之上
【发布时间】:2011-06-20 21:08:44
【问题描述】:

我正在使用Window.ShowDialog() 在我的 WPF (MVVM) 应用程序中打开一个模式窗口,但它允许我使用 Windows 任务栏 (Windows 7) 导航到其他窗口。

考虑一下: 我的应用程序中打开了 3 个非模态窗口。现在其中之一使用Window.ShowDialog() 打开一个模式窗口。我还将Application.MainWindow 设置为模态窗口的所有者。之所以如此,是因为我正在使用 MVVM 消息传递,并且打开新窗口的消息处理程序集中在 App.xaml.cs 中。窗口确实以模态方式打开-那里没有问题。但是,Windows 7 允许我从任务栏切换到其他应用程序窗口。这会导致模态窗口位于另一个窗口后面的情况,我不想这样做。

只要我打开模态窗口,我就不能在其他窗口上做任何事情,但是如果模态窗口只要打开就一直保持在顶部,那就太好了。有没有办法在模式打开时禁用任务栏切换?仅供参考 - 从应用程序启动的所有打开的窗口都在任务栏上显示为单独的条目。

提前致谢!

【问题讨论】:

  • 我们能否从您创建成为模态对话框的窗口中获取一些代码?
  • 您需要的是将窗口置于所有其他应用程序之上。我需要的是使窗口位于应用程序中的任何其他窗口之上,例如对话框窗口。对于我的要求,这两行: Owner = Application.Current.MainWindow;和 ShowInTaskbar = false;效果很好。为你 +1。

标签: wpf showdialog


【解决方案1】:

没有任何代码可以以此为基础,但听起来您在创建的 Window 上遗漏了一些属性,并希望 ShowDialog 应用额外的“对话”语义:

Window window = new Window()
{
    Title = "Modal Dialog",
    ShowInTaskbar = false,               // don't show the dialog on the taskbar
    Topmost = true,                      // ensure we're Always On Top
    ResizeMode = ResizeMode.NoResize,    // remove excess caption bar buttons
    Owner = Application.Current.MainWindow,
};

window.ShowDialog();

【讨论】:

  • 你是六个字母变量的救星!最重要的是我所缺少的。很抱歉没有发布代码,但你把它钉牢了。不敢相信我错过了。再次感谢!
  • 要删除标题按钮,您需要将其ResizeMode 设置为NoResize 而不是WindowStyle。 ToolWindow 不是对话框。
  • @DavidAnderson:听起来不错,前提是您不想调整对话框的大小。
  • 是的,这是一个很好的观点,但你也可以使用 Win32 API 来删除标题按钮并保持调整大小的能力,我猜 WPF 仍然有一些不稳定的东西。不过,一切都只是代码,所以总是一种做某事的方法。
  • 但是 System.Windows.Window.ShowDialog() 不接受任何参数。为什么?
【解决方案2】:

只需将 Window 的 owner 属性设置为调用窗口即可。然后在任务栏中激活 WPF 应用程序不仅会激活 MainWindow,还会激活模态子窗口并将其置于最前面。

ChildWindow C = new ChildWindow();
C.Owner = this;
C.ShowDialog();

【讨论】:

    【解决方案3】:

    将 Topmost 设置为 True (Topmost=True) 会使对话框位于系统中所有窗口的顶部(不仅在应用程序中)。

    所以你可以尝试在你的主窗口中注册事件Activated:

    Activated += WindowActivated;
    

    并在您的应用程序的另一个主窗口变为活动状态时激活模态对话框的所有者窗口。

    private void WindowActivated(object sender, EventArgs e)
    {
        Window window = Application.Current.Windows.OfType<YourMainWindow>().FirstOrDefault(p => p != this && !p.IsActive && p.OwnedWindows.Count > 0);
        if (window != null)
        {
            window.Activate();
        }
    }
    

    这个简单的技巧假设您所有的子窗口都是模态的,但您可以编写更复杂的逻辑。

    【讨论】:

    • 这应该是公认的答案:这似乎是使用任务栏激活应用程序后将对话框窗口保持在主窗口顶部的唯一方法。这是一个已知问题:connect.microsoft.com/VisualStudio/feedback/details/474480/…
    • 这在对话框本身的代码隐藏中效果更好(在事件上使用 +=)。这允许主窗口不关心其他窗口在做什么。
    • 哦,在它隐藏时激活对话框(因为我不喜欢真正关闭它)会使主窗口无法操作,因此需要检查 IsVisible。
    【解决方案4】:

    我最终在这里使用了几个答案的组合。接受的答案起初很有用,但正如这里的其他人指出的那样,设置Topmost = true 意味着该窗口始终位于运行的任何其他应用程序之上。我的解决方案是这样的:

    var myWindow = new MyWindowType();
    myWindow.Owner = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
    

    我最初使用:

    myWindow.Owner = Application.Current.MainWindow;
    

    但是,如果您像这样打开三个窗口,则此方法会导致问题:

    MainWindow
       |
       -----> ChildWindow1
    
                   |
                   ----->  ChildWindow2
    

    然后设置ChildWindow2.Owner = Application.Current.MainWindow会将窗口的所有者设置为其祖父窗口,而不是父窗口。

    为了加快速度,我在 Visual Studio 中将其添加为代码 sn-p。如果将以下内容添加到 Tools --> Code Snippet Manager --> My Code Snippets:

    <CodeSnippets
        xmlns="http://schemas.microsoft.com/VisualStudio/2010/CodeSnippet">
      <CodeSnippet Format="1.0.0">
        <Header>
          <Title>MVVM Set owner of page to be current active window</Title>
          <Shortcut>owner</Shortcut>
        </Header>
        <Snippet>
          <Code Language="CSharp">
            <![CDATA[System.Windows.Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);]]>
          </Code>
        </Snippet>
      </CodeSnippet>
    </CodeSnippets>
    

    键入“所有者”并双击 Tab 键会自动为您添加“Application.CurrentWindows...”部分。

    【讨论】:

    • 这个救了我的命,因为我已经设置了每个人提到的所有选项,但从未看过主窗口可能是什么。您的回答使我对此进行了调查
    【解决方案5】:

    不得不做一些修改。 我必须设置所有者并激活窗口。 检查弹出窗口并激活如下所示的窗口。

            var enumerator = Application.Current.Windows.GetEnumerator();
            while (enumerator.MoveNext())
            {
                Window window = (Window)enumerator.Current;
                if (window != null && window.GetType() == typeof(PopUpWindow))
                {
                    window.Activate();
                }
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-05
      • 1970-01-01
      • 2011-10-01
      相关资源
      最近更新 更多