在WPF中如何引用活动窗口?

65

如何在C#中引用WPF应用程序的活动窗口,使用类似WinForms中的ActiveForm属性的方法?

5个回答

115

一种可能的方法是扫描应用程序中打开窗口的列表,并检查哪一个窗口具有 IsActive = true

Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);

不确定是否可能存在多个活动窗口,例如如果有一个模态对话框正在显示,则对话框的所有者和对话框本身可能是活动的。


2
重新查看我的旧答案,也许最好使用 OfType<Window>() 运算符而不是 Cast<Window>(),以防万一... - Aviad P.
太棒了!这让我不必传递窗口引用,使我的数据结构不受UI引用的影响。谢谢! - BrokeMyLegBiking
6
为了让它更加健壮,你可以使用 FirstOrDefault 替代 SingleOrDefault,如果有多个匹配项,后者会抛出异常。此外,FirstOrDefault 速度稍微快一些,因为它只接受第一个结果,不需要检查它是否是唯一的。 - ygoe
1
有时候 FirstOrDefaultSingleOrDefault 都会返回 null,这意味着没有 IsActive 为 true 的窗口。这是怎么可能的? - digitguy
1
如果应用程序本身没有处于活动状态,也许呢? - Aviad P.
谢谢你的回答。我使用了LastOrDefault()来从列表中获取最后一个活动子项。这样它就总是有适当的所有者,并且不会在父窗口后面打开子窗口。 - bbedson

30

使用PInvoke有更好的方法来解决这个问题。Aviad的答案并不总是有效(在某些边缘情况下存在一些对话框)。

IntPtr active = GetActiveWindow();

ActiveWindow = Application.Current.Windows.OfType<Window>()
    .SingleOrDefault(window => new WindowInteropHelper(window).Handle == active);

首先必须包含以下导入:

[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();

1
呵呵。我花了几个小时才自己发现这个问题。我实际上写了和你完全一样的东西,本来是来分享的,但你先发了,所以这里是我的投票 :P - Erti-Chris Eelmaa
7
请详细说明边缘案例是什么? - nchaud
2
@nchaud 我正在使用 AvalonDock,它允许您将工作区从主窗口拖出并放入新窗口。然而,这些窗口也被标记为 IsActive。使用另一种解决方案会抛出异常(如果有多个匹配谓词,则 SingleOrDefault 会抛出异常),或者在使用 FirstOrDefault 时没有给我实际的活动窗口。 - clcto

2

我知道这个问题有些老,但是我认为我的答案可以帮助到某些人。

我的问题是:我有一个WPF MVVM应用程序,我需要在第二个视图模型中获取我的MainWindow实例,以便将标题栏按钮的可见性设置为visible

这是我的解决方案:

MainWindow window = (MyApp.MainWindow)App.Current.MainWindow;
window.btnSearch.Visibility = System.Windows.Visibility.Visible;

希望这能对某些人有所帮助。


0

另一种方法是使用user32.dll中的本地GetActiveWindow函数。

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetActiveWindow();

要将其转换为实际的 WPF 窗口:

IntPtr handle = GetActiveWindow();

HwndSource hwndSource = HwndSource.FromHwnd(handle);
var window = hwndSource?.RootVisual as Window;

如果在WinForms应用程序中托管WPF窗口,则应使用WindowInteropHelper。这样可以使窗口所有者正常工作,例如:
var wih = new WindowInteropHelper(window)
{
    Owner = GetActiveWindow()
};

我编辑了我的旧答案,因为在 Visual Studio 更新后我遇到的边缘情况已经消失了,但是可以从答案历史记录中检查。在那里我遇到了一个问题,在调试时在某些情况下获取活动窗口时会得到 null。


0

我遇到了一个关于编程的问题,具体是这样的:"Application.Current.Windows.OfType().SingleOrDefault(x => x.IsActive);",特别是当我正在建立一个带有主窗口的应用程序时,当主窗口被选中时会出现问题。为了解决这个问题,我创建了以下代码:

在基类或App.xaml.cs文件中创建以下代码:

       public static Window ActivatedWindow {get;set;}

然后在您的基类中加入继承自 Window 或所有 Window 的 Activate 事件:

第一选项 - 个人窗口基类:

       public class MetroToolWindowBase
       {
         public MetroToolWindowBase()
         {   
            Activated += new EventHandler(MakeActive); 
         }   
         private void MakeActive(object sender, EventArgs e)
         {
        App.ActivatedWindow= this;
         }
       }

第二个选项- 在 Windows 的激活事件中:

   private void XWindow_Activated(object sender,EventArgs e)
    {
     App.ActivatedWindow= this;
    }

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