Вывести окно на передний план в WPF - PullRequest
191 голосов
/ 03 ноября 2008

Как я могу перенести мое приложение 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 с таймером, он работает точно так, как ожидалось, поэтому я не уверен, почему он не работает в моем исходном случае.

Редактировать : Я делаю это в сочетании с глобальной горячей клавишей.

Ответы [ 18 ]

282 голосов
/ 20 декабря 2008
myWindow.Activate();

Пытается вывести окно на передний план и активировать его.

Это должно сработать, если я не правильно понял, и вы хотите, чтобы поведение всегда было сверху. В этом случае вы хотите:

myWindow.TopMost = true;
152 голосов
/ 28 января 2011

Я нашел решение, которое выводит окно наверх, но оно ведет себя как обычное окно:

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
25 голосов
/ 14 октября 2009

Если вам нужно, чтобы окно отображалось впереди при первой загрузке, используйте следующее:

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

private void Window_Initialized(object sender, EventArgs e)
{
    this.Topmost = true;
}
20 голосов
/ 26 сентября 2011

Для быстрого копирования и вставки -
Используйте этот класс 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);
        }
    }
}

НТН

17 голосов
/ 19 июля 2012

Я знаю, что этот вопрос довольно старый, но я только что натолкнулся на этот точный сценарий и хотел поделиться решением, которое я реализовал.

Как уже упоминалось в комментариях на этой странице, некоторые из предложенных решений не работают на XP, которую я должен поддерживать в моем сценарии. Хотя я согласен с мнением @Matthew Xavier о том, что в целом это плохая практика UX, бывают случаи, когда это вполне правдоподобный UX.

Решение поднять окно WPF наверх было фактически предоставлено мне тем же кодом, который я использую для предоставления глобальной горячей клавиши. Статья в блоге Джозефа Куни содержит ссылку на его примеры кода , в которой содержится оригинальный код.

Я немного очистил и изменил код и реализовал его как метод расширения для System.Windows.Window. Я проверил это на 32-битной XP и 64-битной Win7, обе из которых работают правильно.

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
    }
}

Надеюсь, этот код поможет другим, кто столкнулся с этой проблемой.

13 голосов
/ 06 января 2009

Если пользователь взаимодействует с другим приложением, может оказаться невозможным вывести ваше приложение вперед. Как правило, процесс может ожидать установки окна переднего плана, только если этот процесс уже является процессом переднего плана. (Microsoft документирует ограничения в записи SetForegroundWindow () MSDN.) Это потому, что:

  1. Пользователь "владеет" передним планом. Например, было бы очень неприятно, если другая программа украла передний план, пока пользователь печатал, по крайней мере прерывая его рабочий процесс, и, возможно, вызывала непреднамеренные последствия, поскольку ее нажатия клавиш, предназначенные для одного приложения, были неверно истолкованы нарушителем, пока она не заметила изменение .
  2. Представьте, что каждая из двух программ проверяет, является ли ее окно передним планом, и пытается установить его на передний план, если это не так. Как только запускается вторая программа, компьютер становится бесполезным, так как передний план отскакивает между ними при каждом переключении задач.
6 голосов
/ 08 октября 2010

У меня была похожая проблема с приложением WPF, которое вызывается из приложения Access через объект Shell.

Мое решение ниже - работает в 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();
}
6 голосов
/ 20 апреля 2016

Почему некоторые ответы на этой странице неверны!

  • Любой ответ, который использует window.Focus(), является неправильным.

    • Почему? Если всплывающее уведомление появляется, window.Focus() отвлечет внимание от всего, что пользователь печатает в данный момент. Это безумно расстраивает конечных пользователей, особенно если всплывающие окна появляются довольно часто.
  • Любой ответ, который использует window.Activate(), неверен.

    • Почему? Это также сделает видимыми все родительские окна.
  • Любой ответ, который пропускает window.ShowActivated = false, неверен.
    • Почему? Когда выскочит сообщение, оно будет отвлекать внимание от другого окна, что очень раздражает!
  • Любой ответ, который не использует Visibility.Visible, чтобы скрыть / показать окно, неверен.
    • Почему? Если мы используем Citrix, если окно не свернуто, когда оно закрыто, оно оставит странную черную прямоугольную задержку на экране. Таким образом, мы не можем использовать window.Show() и window.Hide().

По существу:

  • Окно не должно захватывать фокус от любого другого окна, когда оно активируется;
  • Окно не должно активировать своего родителя, когда оно отображается;
  • Окно должно быть совместимо с Citrix.

MVVM Solution

Этот код на 100% совместим с Citrix (нет пустых областей экрана). Он протестирован как с обычным 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 переместить окно на экран, если оно не на экране? .

6 голосов
/ 11 декабря 2014

Я знаю, что это поздний ответ, может быть полезным для исследователей

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }
4 голосов
/ 16 августа 2012

Ну, так как это такая горячая тема ... вот что у меня работает. Я получаю ошибки, если я не сделал это таким образом, потому что Activate () выдаст ошибку, если вы не видите окно.

Xaml:

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

Codebehind:

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

Это был единственный способ для меня, чтобы окно показывалось сверху. Затем активируйте его, чтобы вы могли ввести текст в поле без необходимости фокусировки мышью. control.Focus () не будет работать, если окно не Active ();

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...