232

如何将我的 WPF 应用程序带到桌面的前面?到目前为止,我已经尝试过:

SwitchToThisWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle, true);

SetWindowPos(new WindowInteropHelper(Application.Current.MainWindow).Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle);

没有一个在做这项工作(Marshal.GetLastWin32Error()是说这些操作成功完成,并且每个定义的 P/Invoke 属性确实有SetLastError=true)。

如果我创建一个新的空白 WPF 应用程序并SwitchToThisWindow使用计时器调用,它会完全按预期工作,所以我不确定为什么它在我原来的情况下不起作用。

编辑:我正在与全局热键一起执行此操作。

4

19 回答 19

334
myWindow.Activate();

尝试将窗口置于前台并激活它。

这应该可以解决问题,除非我误解了并且您想要始终处于最佳状态。在这种情况下,您想要:

myWindow.TopMost = true;
于 2008-12-20T20:32:51.970 回答
186

我找到了一个将窗口置于顶部的解决方案,但它的行为与普通窗口一样:

if (!Window.IsVisible)
{
    Window.Show();
}

if (Window.WindowState == WindowState.Minimized)
{
    Window.WindowState = WindowState.Normal;
}

Window.Activate();
Window.Topmost = true;  // important
Window.Topmost = false; // important
Window.Focus();         // important
于 2011-01-28T18:39:46.390 回答
38

如果您需要在第一次加载时将窗口放在前面,那么您应该使用以下内容:

private void Window_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
}

private void Window_Initialized(object sender, EventArgs e)
{
    this.Topmost = true;
}

或者通过覆盖方法:

protected override void OnContentRendered(EventArgs e)
{
    base.OnContentRendered(e);
    Topmost = false;
}

protected override void OnInitialized(EventArgs e)
{
    base.OnInitialized(e);
    Topmost = true;
}
于 2009-10-14T09:29:00.813 回答
27

我知道这个问题已经很老了,但我刚刚遇到了这个精确的场景,并想分享我实施的解决方案。

正如本页评论中提到的,提出的几个解决方案不适用于 XP,我需要在我的场景中支持它。虽然我同意@Matthew Xavier 的观点,即这通常是一种糟糕的用户体验实践,但有时它完全是一个合理的用户体验。

将 WPF 窗口置于顶部的解决方案实际上是由我用来提供全局热键的相同代码提供给我的。Joseph Cooney 的博客文章包含指向他的代码示例的链接,其中包含原始代码。

我已经对代码进行了一些清理和修改,并将其实现为 System.Windows.Window 的扩展方法。我已经在 XP 32 位和 Win7 64 位上对此进行了测试,两者都可以正常工作。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace System.Windows
{
    public static class SystemWindows
    {
        #region Constants

        const UInt32 SWP_NOSIZE = 0x0001;
        const UInt32 SWP_NOMOVE = 0x0002;
        const UInt32 SWP_SHOWWINDOW = 0x0040;

        #endregion

        /// <summary>
        /// Activate a window from anywhere by attaching to the foreground window
        /// </summary>
        public static void GlobalActivate(this Window w)
        {
            //Get the process ID for this window's thread
            var interopHelper = new WindowInteropHelper(w);
            var thisWindowThreadId = GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);

            //Get the process ID for the foreground window's thread
            var currentForegroundWindow = GetForegroundWindow();
            var currentForegroundWindowThreadId = GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);

            //Attach this window's thread to the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);

            //Set the window position
            SetWindowPos(interopHelper.Handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);

            //Detach this window's thread from the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);

            //Show and activate the window
            if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
            w.Show();
            w.Activate();
        }

        #region Imports

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

        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

        [DllImport("user32.dll")]
        private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        #endregion
    }
}

我希望这段代码可以帮助遇到这个问题的其他人。

于 2012-07-19T01:56:55.567 回答
23

为了使它成为一个快速的复制粘贴 -
使用这个类的DoOnProcess方法将进程的主窗口移动到前台(但不要从其他窗口窃取焦点)

public class MoveToForeground
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);

    const int SWP_NOMOVE        = 0x0002;
    const int SWP_NOSIZE        = 0x0001;            
    const int SWP_SHOWWINDOW    = 0x0040;
    const int SWP_NOACTIVATE    = 0x0010;
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

    public static void DoOnProcess(string processName)
    {
        var allProcs = Process.GetProcessesByName(processName);
        if (allProcs.Length > 0)
        {
            Process proc = allProcs[0];
            int hWnd = FindWindow(null, proc.MainWindowTitle.ToString());
            // Change behavior by settings the wFlags params. See http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx
            SetWindowPos(new IntPtr(hWnd), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
        }
    }
}

高温高压

于 2011-09-26T18:47:08.900 回答
13

如果用户正在与另一个应用程序交互,则可能无法将您的应用程序置于最前面。作为一般规则,如果该进程已经是前台进程,则该进程只能期望设置前台窗口。(Microsoft 在SetForegroundWindow() MSDN 条目中记录了限制。)这是因为:

  1. 用户“拥有”前景。例如,如果另一个程序在用户打字时偷走了前台,至少会打断她的工作流程,并且可能导致意想不到的后果,因为攻击者会误解她对一个应用程序的击键,直到她注意到更改为止.
  2. 想象一下,两个程序中的每一个都检查它的窗口是否是前台,如果不是,则尝试将其设置为前台。一旦第二个程序运行,计算机就会变得毫无用处,因为在每次任务切换时前景在两者之间反弹。
于 2009-01-06T04:43:34.283 回答
13

为什么此页面上的某些答案是错误的!

  • 任何使用的答案window.Focus()都是错误的。

    • 为什么?如果弹出通知消息,window.Focus()则将焦点从用户当时正在输入的任何内容上移开。这对于最终用户来说是非常令人沮丧的,尤其是在弹出窗口频繁出现的情况下。
  • 任何使用的答案window.Activate()都是错误的。

    • 为什么?它也会使任何父窗口可见。
  • 任何省略的答案window.ShowActivated = false都是错误的。
    • 为什么?当消息弹出时,它会将焦点从另一个窗口中移开,这非常烦人!
  • 任何不Visibility.Visible用于隐藏/显示窗口的答案都是错误的。
    • 为什么?如果我们使用Citrix,如果窗口关闭时没有折叠,它会在屏幕上留下一个奇怪的黑色矩形。因此,我们不能使用window.Show()and window.Hide()

本质上:

  • 窗口在激活时不应将焦点从任何其他窗口中抢走;
  • 窗口在显示时不应激活其父级;
  • 该窗口应与 Citrix 兼容。

MVVM 解决方案

此代码与 Citrix 100% 兼容(屏幕没有空白区域)。它使用普通 WPF 和 DevExpress 进行了测试。

此答案适用于我们想要一个始终位于其他窗口前面的小通知窗口(如果用户在首选项中选择它)的任何用例。

如果这个答案看起来比其他答案更复杂,那是因为它是健壮的企业级代码。此页面上的其他一些答案很简单,但实际上不起作用。

XAML - 附加属性

将此附加属性添加到UserControl窗口中的任何内容。附加的财产将:

  • 等到Loaded事件被触发(否则它无法查找可视化树以找到父窗口)。
  • 添加一个事件处理程序以确保窗口可见或不可见。

在任何时候,您都可以通过翻转附加属性的值来设置窗口是否在前面。

<UserControl x:Class="..."
         ...
         attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
             "{Binding EnsureWindowInForeground, Mode=OneWay}">

C# - 辅助方法

public static class HideAndShowWindowHelper
{
    /// <summary>
    ///     Intent: Ensure that small notification window is on top of other windows.
    /// </summary>
    /// <param name="window"></param>
    public static void ShiftWindowIntoForeground(Window window)
    {
        try
        {
            // Prevent the window from grabbing focus away from other windows the first time is created.
            window.ShowActivated = false;

            // Do not use .Show() and .Hide() - not compatible with Citrix!
            if (window.Visibility != Visibility.Visible)
            {
                window.Visibility = Visibility.Visible;
            }

            // We can't allow the window to be maximized, as there is no de-maximize button!
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;
            }

            window.Topmost = true;
        }
        catch (Exception)
        {
            // Gulp. Avoids "Cannot set visibility while window is closing".
        }
    }

    /// <summary>
    ///     Intent: Ensure that small notification window can be hidden by other windows.
    /// </summary>
    /// <param name="window"></param>
    public static void ShiftWindowIntoBackground(Window window)
    {
        try
        {
            // Prevent the window from grabbing focus away from other windows the first time is created.
            window.ShowActivated = false;

            // Do not use .Show() and .Hide() - not compatible with Citrix!
            if (window.Visibility != Visibility.Collapsed)
            {
                window.Visibility = Visibility.Collapsed;
            }

            // We can't allow the window to be maximized, as there is no de-maximize button!
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;
            }

            window.Topmost = false;
        }
        catch (Exception)
        {
            // Gulp. Avoids "Cannot set visibility while window is closing".
        }
    }
}

用法

为了使用它,您需要在 ViewModel 中创建窗口:

private ToastView _toastViewWindow;
private void ShowWindow()
{
    if (_toastViewWindow == null)
    {
        _toastViewWindow = new ToastView();
        _dialogService.Show<ToastView>(this, this, _toastViewWindow, true);
    }
    ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(_toastViewWindow);
    HideAndShowWindowHelper.ShiftWindowIntoForeground(_toastViewWindow);
}

private void HideWindow()
{
    if (_toastViewWindow != null)
    {
        HideAndShowWindowHelper.ShiftWindowIntoBackground(_toastViewWindow);
    }
}

附加链接

有关如何确保通知窗口始终移回可见屏幕的提示,请参阅我的回答:在 WPF 中,如果窗口不在屏幕上,如何将窗口移到屏幕上?.

于 2016-04-20T10:18:34.460 回答
8

我知道这是迟到的答案,可能对研究人员有帮助

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }
于 2014-12-11T10:17:53.263 回答
7

我在通过 Shell 对象从 Access 应用程序调用的 WPF 应用程序中遇到了类似的问题。

我的解决方案如下 - 适用于 XP 和 Win7 x64,应用程序编译为 x86 目标。

我宁愿这样做也不愿模拟 alt-tab。

void Window_Loaded(object sender, RoutedEventArgs e)
{
    // make sure the window is normal or maximised
    // this was the core of the problem for me;
    // even though the default was "Normal", starting it via shell minimised it
    this.WindowState = WindowState.Normal;

    // only required for some scenarios
    this.Activate();
}
于 2010-10-07T23:41:01.793 回答
5

好吧,因为这是一个如此热门的话题......这对我有用。如果我不这样做,我会收到错误,因为如果您看不到窗口,Activate() 会在您身上出错。

xml:

<Window .... 
        Topmost="True" 
        .... 
        ContentRendered="mainWindow_ContentRendered"> .... </Window>

代码隐藏:

private void mainWindow_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
    this.Activate();
    _UsernameTextBox.Focus();
}

这是我让窗口显示在顶部的唯一方法。然后激活它,这样您就可以在框中键入,而无需用鼠标设置焦点。除非窗口是 Active(),否则 control.Focus() 将不起作用;

于 2012-08-16T15:51:08.897 回答
3

好吧,我想出了一个解决方法。我正在从用于实现热键的键盘挂钩进行调用。如果我暂停将其放入 BackgroundWorker,该调用将按预期工作。这是一个kludge,但我不知道为什么它最初不起作用。

void hotkey_execute()
{
    IntPtr handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
    BackgroundWorker bg = new BackgroundWorker();
    bg.DoWork += new DoWorkEventHandler(delegate
        {
            Thread.Sleep(10);
            SwitchToThisWindow(handle, true);
        });
    bg.RunWorkerAsync();
}
于 2008-11-03T01:40:26.450 回答
2

要显示任何当前打开的窗口,请导入这些 DLL:

public partial class Form1 : Form
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);
    [DllImportAttribute("User32.dll")]
    private static extern int SetForegroundWindow(int hWnd);

并在程序中搜索具有指定标题的应用程序(写标题不带首字母(索引> 0))

  foreach (Process proc in Process.GetProcesses())
                {
                    tx = proc.MainWindowTitle.ToString();
                    if (tx.IndexOf("Title of Your app WITHOUT FIRST LETTER") > 0)
                    {
                        tx = proc.MainWindowTitle;
                        hWnd = proc.Handle.ToInt32(); break;
                    }
                }
                hWnd = FindWindow(null, tx);
                if (hWnd > 0)
                {
                    SetForegroundWindow(hWnd);
                }
于 2010-11-11T17:32:59.883 回答
2

只是想为这个问题添加另一个解决方案。此实现适用于我的场景,其中 CaliBurn 负责显示主窗口。

protected override void OnStartup(object sender, StartupEventArgs e)
{
    DisplayRootViewFor<IMainWindowViewModel>();

    Application.MainWindow.Topmost = true;
    Application.MainWindow.Activate();
    Application.MainWindow.Activated += OnMainWindowActivated;
}

private static void OnMainWindowActivated(object sender, EventArgs e)
{
    var window = sender as Window;
    if (window != null)
    {
        window.Activated -= OnMainWindowActivated;
        window.Topmost = false;
        window.Focus();
    }
}
于 2017-04-12T21:19:44.260 回答
1

问题可能是从钩子调用您的代码的线程尚未由运行时初始化,因此调用运行时方法不起作用。

也许您可以尝试执行 Invoke 以将您的代码编组到 UI 线程,以调用将窗口带到前台的代码。

于 2009-02-27T21:03:31.177 回答
1

这些代码将始终正常工作。

首先在 XAML 中设置激活的事件处理程序:

Activated="Window_Activated"

将以下行添加到您的主窗口构造函数块:

public MainWindow()
{
    InitializeComponent();
    this.LocationChanged += (sender, e) => this.Window_Activated(sender, e);
}

在激活的事件处理程序中复制以下代码:

private void Window_Activated(object sender, EventArgs e)
{
    if (Application.Current.Windows.Count > 1)
    {
        foreach (Window win in Application.Current.Windows)
            try
            {
                if (!win.Equals(this))
                {
                    if (!win.IsVisible)
                    {
                        win.ShowDialog();
                    }

                    if (win.WindowState == WindowState.Minimized)
                    {
                        win.WindowState = WindowState.Normal;
                    }

                    win.Activate();
                    win.Topmost = true;
                    win.Topmost = false;
                    win.Focus();
                }
            }
            catch { }
    }
    else
        this.Focus();
}

这些步骤可以正常工作,并将所有其他窗口带到其父窗口的前面。

于 2017-02-05T09:37:38.953 回答
0

如果您试图隐藏窗口,例如最小化窗口,我发现使用

    this.Hide();

将正确隐藏它,然后只需使用

    this.Show();

然后将再次将窗口显示为最顶部的项目。

于 2014-09-24T18:31:06.270 回答
0

请记住不要将显示该窗口的代码放在 PreviewMouseDoubleClick 处理程序中,因为活动窗口将切换回处理该事件的窗口。只需将它放在 MouseDoubleClick 事件处理程序中或通过将 e.Handled 设置为 True 来停止冒泡。

在我的情况下,我正在处理 Listview 上的 PreviewMouseDoubleClick 并且没有设置 e.Handled = true 然后它引发了 MouseDoubleClick 事件女巫坐在焦点回到原始窗口。

于 2017-04-24T19:45:34.057 回答
0

这是上述几个建议的组合,效果很好并且很简单。只有当这些事件触发时它才会出现在前面,所以在事件之后弹出的任何窗口当然都会保持在最前面。

public partial class MainWindow : Window
{
    protected override void OnContentRendered(EventArgs e)
    {
        base.OnContentRendered(e);

        Topmost = true;
        Topmost = false;
    }
    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);

        Topmost = true;
        Topmost = false;
    }

    ....
}
于 2021-12-16T16:11:48.803 回答
-2

我构建了一个扩展方法以便于重用。

using System.Windows.Forms;
    namespace YourNamespace{
        public static class WindowsFormExtensions {
            public static void PutOnTop(this Form form) {
                form.Show();
                form.Activate();
            }// END PutOnTop()       
        }// END class
    }// END namespace

调用表单构造函数

namespace YourNamespace{
       public partial class FormName : Form {
       public FormName(){
            this.PutOnTop();
            InitalizeComponents();
        }// END Constructor
    } // END Form            
}// END namespace
于 2017-05-18T17:53:01.030 回答