我如何把我的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,它完全按照预期工作,所以我不确定为什么它在我原来的情况下不工作。

编辑:我这样做与一个全局热键。


当前回答

为什么这一页上的一些答案是错误的!

Any answer that uses window.Focus() is wrong. Why? If a notification message pops up, window.Focus() will grab the focus away from whatever the user is typing at the time. This is insanely frustrating for end users, especially if the popups occur quite frequently. Any answer that uses window.Activate() is wrong. Why? It will make any parent windows visible as well. Any answer that omits window.ShowActivated = false is wrong. Why? It will grab the focus away from another window when the message pops up which is very annoying! Any answer that does not use Visibility.Visible to hide/show the window is wrong. Why? If we are using Citrix, if the window is not collapsed when it is closed, it will leave a weird black rectangular hold on the screen. Thus, we cannot use window.Show() and window.Hide().

从本质上讲:

当窗口激活时,它不应该从其他窗口抢夺焦点; 该窗口在显示时不应激活其父窗口; 该窗口应与Citrix兼容。

MVVM答案

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

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

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

XAML -附加属性

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

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

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

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

辅助方法

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中,如果窗口离开屏幕,如何将窗口移到屏幕上?

其他回答

问题可能是线程从钩子调用你的代码还没有被运行时初始化,所以调用运行时方法不起作用。

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

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

The user "owns" the foreground. For example, it would be extremely annoying if another program stole the foreground while the user is typing, at the very least interrupting her workflow, and possibly causing unintended consequences as her keystrokes meant for one application are misinterpreted by the offender until she notices the change. Imagine that each of two programs checks to see if its window is the foreground and attempts to set it to the foreground if it is not. As soon as the second program is running, the computer is rendered useless as the foreground bounces between the two at every task switch.

我有一个类似的问题与WPF应用程序,从访问应用程序通过Shell对象调用。

我的解决方案如下-工作在XP和Win7 x64应用程序编译到x86目标。

我宁愿这样做,而不是模拟一个alt选项卡。

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

只是想给这个问题加上一个解。这个实现适用于我的场景,其中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();
    }
}

这些代码在任何时候都能正常工作。

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

这些步骤将工作良好,并将前面所有其他窗口进入他们的父母窗口。