2011-06-20 443 views
23

我使用Window.ShowDialog()在我的WPF(MVVM)应用程序中打开模式窗口,但它使我可以使用Windows任务栏(Windows 7)导航到其他窗口。Modal对话框不显示在其他窗口顶部

考虑这个: 我有3个非模态窗口在我的应用程序中打开。现在其中一个使用Window.ShowDialog()打开一个模式窗口。我还将Application.MainWindow设置为模式窗口的所有者。这是因为我使用MVVM消息传递和消息处理程序来打开一个新窗口集中在App.xaml.cs。该窗口确实打开 - 没有问题。但是,Windows 7允许我从任务栏切换到其他应用程序窗口。这导致了模态窗口落在另一个窗口后面的情况,我不喜欢这个窗口。

只要我打开模式,我无法在其他窗口上做任何事情,但是如果模态窗口始终保持在最前面,只要打开它就好了。当模式打开时,我可以禁用任务栏切换吗?仅供参考 - 从应用程序启动的所有打开的窗口在任务栏上显示为单独的条目。

在此先感谢!

+0

我们可以从创建窗口的位置获取一些代码,该窗口将成为模式对话框? – user7116

+0

您需要的是让窗口超出所有其他应用程序。我需要的是让窗口在应用程序中的任何其他窗口之上,例如对话窗口。对于我的要求,这两行:Owner = Application.Current.MainWindow;和ShowInTaskbar = false;效果很好。为你+1。 –

回答

55

没有任何代码基础这一关的,但听起来好像你已经离开的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(); 
+0

你是一个救世主sixlettervariables!最高的是我失踪的。抱歉不发布代码,但你钉了它。不能相信我错过了它。再次感谢! – Pratz

+0

要删除标题按钮,您需要将其“ResizeMode”设置为“NoResize”而不是“WindowStyle”。一个ToolWindow不是一个对话框。 –

+0

@DavidAnderson:听起来不错,只要你不在意调整对话框的大小。 – user7116

9

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

所以,你可以尝试注册在主窗口中的情况下被激活:

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

这个简单的黑客假定所有的孩子窗户模式,但你可以写一个更复杂的逻辑。

+1

这应该是被接受的答案:它似乎是在使用任务栏激活应用程序之后,将对话窗口保持在主窗口顶部的唯一方法。这是一个已知问题:http://connect.microsoft.com/VisualStudio/feedback/details/474480/wpf-showdialog-and-owner – stijn

+0

从对话框本身的代码隐藏(在事件中使用+ =)可以更好地工作。这允许主窗口不关心其他窗口在做什么。 – Grault

+0

哦,并且在隐藏对话框时激活对话框(因为我不喜欢真正关闭对话框)会使主窗口无法操作,因此请检查IsVisible。 – Grault

10

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

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

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

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

我最终在这里结合使用了几个答案。首先接受的答案是有用的,但是由于这里的其他人已经指出设置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中的代码片段添加了。如果添加下列工具 - >代码段管理器 - >我的代码片断:

<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...”部分为您服务。

+1

这个人拯救了我的生命,因为我已经设定了所有人提到的选项,但从来没有看过什么主窗口。你的回答让我看到了 –