Вопрос

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

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

Это было полезно?

Решение 11

Ну, я разобрался. Я звоню с помощью клавиатуры, используемой для реализации горячей клавиши. Вызов работает как положено, если я помещаю его в BackgroundWorker с паузой. Это клочок, но я понятия не имею, почему он изначально не работал.

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

Другие советы

myWindow.Activate();

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

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

myWindow.TopMost = true;

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

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

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

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

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

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

HTH

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

Как уже упоминалось в комментариях на этой странице, некоторые из предложенных решений не работают на 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
    }
}

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

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

<Ол>
  • Пользователь " владеет " на переднем плане. Например, было бы очень неприятно, если другая программа украла передний план, пока пользователь печатал, по крайней мере прерывая его рабочий процесс, и, возможно, вызывала непреднамеренные последствия, поскольку ее нажатия клавиш, предназначенные для одного приложения, были неверно истолкованы нарушителем, пока она не заметила изменение .
  • Представьте, что каждая из двух программ проверяет, является ли ее окно передним планом, и пытается установить его на передний план, если это не так. Как только запускается вторая программа, компьютер становится бесполезным, так как передний план отскакивает между ними при каждом переключении задач.
  • У меня была похожая проблема с приложением 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();
    }
    

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

     if (!WindowName.IsVisible)
     {
         WindowName.Show();
         WindowName.Activate();
     }
    

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

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

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

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

    По существу:

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

    Решение MVVM

    Этот код на 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, как переместить окно на экран, если оно находится вне экрана?.

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

    Xaml:

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

    Кодовая Привязка:

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

    Для меня это был единственный способ заставить окно отображаться сверху.Затем активируйте его, чтобы вы могли вводить текст в поле без необходимости устанавливать фокус с помощью мыши.управление.Функция фокусировки () не будет работать, если окно не активно ();

    Чтобы показать ЛЮБОЕ открытое окно, импортируйте эти 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);
                    }
    

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

    Возможно, вы могли бы попытаться выполнить Invoke для перенаправления вашего кода в поток пользовательского интерфейса для вызова кода, который выводит окно на передний план.

    Эти коды будут нормально работать все время.

    Сначала установите активированный обработчик событий в 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();
    }
    

    Эти шаги будут хорошо работать и перенесут все остальные окна в окно их родителей.

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

        this.Hide();
    

    будет правильно скрывать, а затем просто использовать

        this.Show();
    

    затем снова покажет окно как самый верхний элемент.

    Просто хотел добавить другое решение этого вопроса. Эта реализация работает для моего сценария, где 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();
        }
    }
    

    Не забудьте не помещать код, который показывает это окно, в обработчик PreviewMouseDoubleClick, поскольку активное окно переключится обратно на окно, обработавшее событие. Просто поместите его в обработчик событий MouseDoubleClick или прекратите пузыриться, установив для e.Handled значение True.

    В моем случае я обрабатывал PreviewMouseDoubleClick для ListView и не устанавливал e.Handled = true, после чего он вызывал событие MouseDoubleClick, которое снова фокусировалось на исходном окне.

    Я создал метод расширения, облегчающий повторное использование.

    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
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top