Traga uma janela para a frente no WPF

Como posso levar meu aplicativo WPF para a frente da área de trabalho? Até agora eu tentei:

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

Nenhum deles está fazendo o trabalho ( Marshal.GetLastWin32Error() está dizendo que essas operações foram concluídas com sucesso, e os atributos P / Invoke para cada definição têm SetLastError=true ).

Se eu criar um novo aplicativo WPF em branco e chamar SwitchToThisWindow com um timer, ele funcionará exatamente como esperado, por isso não sei por que ele não está funcionando no meu caso original.

Edit : Eu estou fazendo isso em conjunto com uma tecla de atalho global.

 myWindow.Activate(); 

Tenta trazer a janela para o primeiro plano e a ativa.

Isso deve fazer o truque, a menos que eu entendi mal e você quer o comportamento Always On Top. Nesse caso, você quer:

 myWindow.TopMost = true; 

Eu encontrei uma solução que traz a janela para o topo, mas se comporta como uma janela normal:

 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 

Caso você precise que a janela esteja na frente na primeira vez que for carregada, você deve usar o seguinte:

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

Para fazer isso, copie e cole rapidamente
Use esta class ‘método DoOnProcess para mover a janela principal do processo para o primeiro plano (mas não para roubar o foco de outras janelas)

 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

Eu sei que esta questão é bastante antiga, mas acabei de encontrar este cenário preciso e queria compartilhar a solução que implementei.

Como mencionado nos comentários desta página, várias das soluções propostas não funcionam no XP, que eu preciso suportar no meu cenário. Embora eu concorde com o sentimento de @Matthew Xavier, que geralmente é uma prática de UX ruim, há momentos em que é uma UX plausível.

A solução para trazer uma janela do WPF para o topo foi realmente fornecida para mim pelo mesmo código que estou usando para fornecer a tecla de atalho global. Um artigo do blog de Joseph Cooney contém um link para seus exemplos de código que contém o código original.

Eu limpei e modifiquei o código um pouco e o implementei como um método de extensão para o System.Windows.Window. Eu testei isso no XP 32 bit e no Win7 64 bit, ambos funcionando corretamente.

 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 ///  /// Activate a window from anywhere by attaching to the foreground window ///  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 } } 

Espero que esse código ajude outras pessoas que encontram esse problema.

Se o usuário estiver interagindo com outro aplicativo, talvez não seja possível levar o seu para a frente. Como regra geral, um processo só pode esperar definir a janela de primeiro plano se esse processo já for o processo de primeiro plano. (Microsoft documenta as restrições na input MSDN SetForegroundWindow () .) Isso porque:

  1. O usuário “possui” o primeiro plano. Por exemplo, seria extremamente irritante se outro programa roubasse o primeiro plano enquanto o usuário estivesse digitando, no mínimo interrompendo seu stream de trabalho e possivelmente causando consequências indesejadas, pois as teclas digitadas para um aplicativo são mal interpretadas pelo ofensor até que ela perceba a alteração. .
  2. Imagine que cada um dos dois programas verifique se sua janela é o primeiro plano e tente configurá-la para o primeiro plano, se não estiver. Assim que o segundo programa é executado, o computador é inutilizado, pois o primeiro plano é refletido entre os dois em cada alternância de tarefas.

Eu tive um problema semelhante com um aplicativo WPF que é chamado de um aplicativo do Access por meio do object Shell.

Minha solução está abaixo – funciona no XP e Win7 x64 com aplicativo compilado para x86 alvo.

Eu prefiro fazer isso do que simular um 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(); } 

Eu sei que esta é uma resposta tardia, talvez útil para pesquisadores

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

Por que algumas das respostas nesta página estão erradas!

  • Qualquer resposta que usa window.Focus() está errada.

    • Por quê? Se uma mensagem de notificação for exibida, window.Focus() o foco de qualquer coisa que o usuário esteja digitando no momento. Isso é insanamente frustrante para os usuários finais, especialmente se os pop-ups ocorrerem com bastante frequência.
  • Qualquer resposta que use window.Activate() está errada.

    • Por quê? Isso tornará qualquer janela pai visível também.
  • Qualquer resposta que omite window.ShowActivated = false está errada.
    • Por quê? Ele vai tirar o foco de outra janela quando a mensagem aparecer, o que é muito chato!
  • Qualquer resposta que não use Visibility.Visible para ocultar / mostrar a janela está errada.
    • Por quê? Se estivermos usando o Citrix, se a janela não for recolhida quando for fechada, ela deixará um estranho retângulo preto na canvas. Assim, não podemos usar window.Show() e window.Hide() .

Essencialmente:

  • A janela não deve tirar o foco de qualquer outra janela quando for ativada;
  • A janela não deve ativar seu pai quando ele é mostrado;
  • A janela deve ser compatível com o Citrix.

Solução MVVM

Este código é 100% compatível com o Citrix (sem áreas em branco da canvas). É testado com WPF normal e DevExpress.

Esta resposta é destinada a qualquer caso de uso em que queremos uma pequena janela de notificação que esteja sempre na frente de outras janelas (se o usuário selecionar isso nas preferências).

Se essa resposta parece mais complexa que as outras, é porque é um código de nível corporativo robusto. Algumas das outras respostas nesta página são simples, mas na verdade não funcionam.

XAML – Propriedade anexada

Adicione esta propriedade anexada a qualquer UserControl dentro da janela. A propriedade anexada irá:

  • Aguarde até que o evento Loaded seja acionado (caso contrário, não será possível procurar a tree visual para localizar a janela pai).
  • Adicione um manipulador de events que garanta que a janela esteja visível ou não.

A qualquer momento, você pode definir a janela para frente ou não, invertendo o valor da propriedade anexada.

  

Método auxiliar

 public static class HideAndShowWindowHelper { ///  /// Intent: Ensure that small notification window is on top of other windows. ///  ///  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". } } ///  /// Intent: Ensure that small notification window can be hidden by other windows. ///  ///  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". } } } 

Uso

Para usar isso, você precisa criar a janela no seu ViewModel:

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

Links adicionais

Para obter dicas sobre como garantir que uma janela de notificação volte sempre para a canvas visível, veja minha resposta: No WPF, como deslocar uma janela para a canvas se ela estiver fora da canvas? .

Bem, desde que este é um tema tão quente … aqui é o que funciona para mim. Eu tenho erros se eu não fiz assim porque Ativar () irá errar em você se você não puder ver a janela.

Xaml:

  ....  

Código por trás:

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

Esta foi a única maneira de eu conseguir a janela para mostrar no topo. Em seguida, ative-o para que você possa digitar na checkbox sem ter que definir o foco com o mouse. control.Focus () não funcionará a menos que a janela seja Active ();

Bem, eu descobri um trabalho por aí. Eu estou fazendo a chamada de um gancho de teclado usado para implementar uma tecla de atalho. A chamada funciona como esperado se eu a colocar em um BackgroundWorker com uma pausa. É um kludge, mas não tenho ideia do motivo pelo qual não estava funcionando originalmente.

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

Para mostrar QUALQUER janela atualmente aberta, importe essa 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); 

e no programa Nós procuramos por aplicativo com o título especificado (escrever título sem primeira letra (índice> 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); } 

O problema poderia ser que o segmento que chama seu código do gancho não tenha sido inicializado pelo tempo de execução, portanto, os methods de tempo de execução de chamada não funcionam.

Talvez você possa tentar fazer um Invoke para empacotar seu código no thread da interface do usuário para chamar seu código que traz a janela para o primeiro plano.

Esses códigos funcionarão bem o tempo todo.

Primeiro, defina o manipulador de events ativado no XAML:

 Activated="Window_Activated" 

Adicione a linha abaixo ao seu bloco de construtor da janela principal:

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

E dentro do manipulador de events ativado copie estes códigos:

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

Essas etapas funcionarão bem e trarão para a frente todas as outras janelas na janela dos pais.

Se você está tentando esconder a janela, por exemplo, você minimizar a janela, descobri que usando

  this.Hide(); 

irá escondê-lo corretamente, então simplesmente usando

  this.Show(); 

Em seguida, mostrará a janela como o item mais superior novamente.

Só queria adicionar outra solução para esta questão. Esta implementação funciona para o meu cenário, onde o CaliBurn é responsável por exibir a janela principal.

 protected override void OnStartup(object sender, StartupEventArgs e) { DisplayRootViewFor(); 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(); } } 

Lembre-se de não colocar o código que mostra essa janela dentro de um manipulador PreviewMouseDoubleClick, pois a janela ativa retornará à janela que tratou do evento. Basta colocá-lo no manipulador de events MouseDoubleClick ou parar de borbulhar definindo e.Handled como True.

No meu caso, eu estava lidando com o PreviewMouseDoubleClick em um ListView e não estava configurando o e.Handled = true, então ele levantou o evento MouseDoubleClick e colocou o foco de volta na janela original.

Eu construí um método de extensão para facilitar a reutilização.

 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 

Chame no construtor de formulário

 namespace YourNamespace{ public partial class FormName : Form { public FormName(){ this.PutOnTop(); InitalizeComponents(); }// END Constructor } // END Form }// END namespace