Porta una finestra in primo piano in WPF

Come posso portare la mia applicazione WPF nella parte anteriore del desktop? Finora ho provato:

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

Nessuno dei due sta svolgendo il lavoro ( Marshal.GetLastWin32Error() sta dicendo che queste operazioni sono state completate correttamente e che gli attributi P / Invoke per ogni definizione hanno SetLastError=true ).

Se creo una nuova applicazione WPF vuota e chiami SwitchToThisWindow con un timer, funziona esattamente come previsto, quindi non sono sicuro del motivo per cui non funziona nel mio caso originale.

Edit : lo sto facendo in combinazione con un hotkey globale.

 myWindow.Activate(); 

Tenta di portare la finestra in primo piano e triggersrla.

Questo dovrebbe fare il trucco, a meno che non abbia frainteso e tu voglia sempre il comportamento Top. In quel caso vuoi:

 myWindow.TopMost = true; 

Ho trovato una soluzione che porta la finestra in alto, ma si comporta come una finestra normale:

 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 

Nel caso in cui sia necessario che la finestra si trovi di fronte la prima volta che carica, è necessario utilizzare quanto segue:

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

Per fare questo un rapido copia-incolla uno –
Utilizzare questo metodo DoOnProcess per spostare la finestra principale del processo in primo piano (ma non per rubare lo stato attivo da altre windows)

 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

So che questa domanda è piuttosto vecchia, ma ho appena trovato questo preciso scenario e ho voluto condividere la soluzione che ho implementato.

Come menzionato nei commenti su questa pagina, molte delle soluzioni proposte non funzionano su XP, che devo supportare nel mio scenario. Mentre sono d’accordo con il sentimento di @Matthew Xavier che generalmente questa è una brutta pratica UX, ci sono momentjs in cui è interamente una UX plausibile.

La soluzione per portare una finestra WPF in cima mi è stata in realtà fornita dallo stesso codice che sto usando per fornire il tasto di scelta rapida globale. Un articolo del blog di Joseph Cooney contiene un link ai suoi esempi di codice che contengono il codice originale.

Ho ripulito e modificato il codice un po ‘e l’ho implementato come un metodo di estensione a System.Windows.Window. Ho provato questo su XP 32 bit e Win7 64 bit, entrambi funzionano correttamente.

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

Spero che questo codice aiuti gli altri che incontrano questo problema.

Se l’utente sta interagendo con un’altra applicazione, potrebbe non essere ansible portarla in primo piano. Come regola generale, un processo può solo prevedere di impostare la finestra in primo piano se quel processo è già il processo in primo piano. (Microsoft documenta le restrizioni nella voce MSDN SetForegroundWindow () .) Questo perché:

  1. L’utente “possiede” il primo piano. Ad esempio, sarebbe estremamente fastidioso se un altro programma rubasse il primo piano mentre l’utente stava digitando, interrompendo almeno il suo stream di lavoro, e probabilmente causando conseguenze indesiderate, dato che le sue combinazioni di tasti per un’applicazione vengono interpretate erroneamente dal trasgressore finché non si accorge del cambiamento .
  2. Immagina che ognuno dei due programmi controlli se la sua finestra è in primo piano e tenta di impostarlo in primo piano se non lo è. Non appena il secondo programma è in esecuzione, il computer è reso inutilizzabile mentre il primo piano rimbalza tra i due ad ogni cambio di attività.

Ho avuto un problema simile con un’applicazione WPF che viene richiamata da un’applicazione Access tramite l’object Shell.

La mia soluzione è di sotto – funziona in XP e Win7 x64 con l’applicazione compilata a destinazione x86.

Preferirei farlo piuttosto che simulare un 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(); } 

So che questa è una risposta tardiva, forse utile per i ricercatori

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

Perché alcune delle risposte in questa pagina sono sbagliate!

  • Qualsiasi risposta che utilizza window.Focus() è errata.

    • Perché? Se viene visualizzato un messaggio di notifica, window.Focus() l’attenzione da qualsiasi cosa l’utente stia digitando in quel momento. Questo è follemente frustrante per gli utenti finali, soprattutto se i popup si verificano abbastanza frequentemente.
  • Qualsiasi risposta che utilizza la window.Activate() è errata.

    • Perché? Renderà visibili anche le windows dei genitori.
  • Qualsiasi risposta che omette window.ShowActivated = false è errata.
    • Perché? Afferra l’attenzione da un’altra finestra quando viene visualizzato il messaggio che è molto fastidioso!
  • Qualsiasi risposta che non usa Visibility.Visible per hide / mostrare la finestra è sbagliata.
    • Perché? Se stiamo usando Citrix, se la finestra non viene compressa quando è chiusa, lascerà una strana attesa rettangular nera sullo schermo. Pertanto, non possiamo usare window.Show() e window.Hide() .

Essenzialmente:

  • La finestra non dovrebbe afferrare lo stato attivo da qualsiasi altra finestra quando si triggers;
  • La finestra non dovrebbe triggersre il suo genitore quando viene mostrato;
  • La finestra dovrebbe essere compatibile con Citrix.

Soluzione MVVM

Questo codice è compatibile al 100% con Citrix (nessuna area vuota dello schermo). È testato sia con il normale WPF che con DevExpress.

Questa risposta è intesa per qualsiasi caso d’uso in cui vogliamo una piccola finestra di notifica che sia sempre di fronte ad altre windows (se l’utente lo seleziona nelle preferenze).

Se questa risposta sembra più complessa delle altre, è perché è robusta, codice di livello aziendale. Alcune delle altre risposte in questa pagina sono semplici, ma in realtà non funzionano.

XAML – Proprietà allegata

Aggiungi questa proprietà associata a qualsiasi UserControl all’interno della finestra. La proprietà allegata:

  • Attendi fino a quando viene Loaded evento Loaded (altrimenti non può cercare la struttura ad albero per trovare la finestra genitore).
  • Aggiungi un gestore di eventi che assicuri che la finestra sia visibile o meno.

In qualsiasi momento, puoi impostare la finestra in modo che sia davanti o no, capovolgendo il valore della proprietà associata.

  

C # – Metodo di supporto

 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

Per poter utilizzare questo, è necessario creare la finestra nel 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); } } 

Link aggiuntivi

Per suggerimenti su come assicurarsi che una finestra di notifica torni sempre sullo schermo visibile, vedere la mia risposta: In WPF, come spostare una finestra sullo schermo se è fuori dallo schermo? .

Bene, dal momento che questo è un argomento molto caldo … ecco cosa funziona per me. Ho degli errori se non l’ho fatto in questo modo perché Activate () ti sbaglierà se non riesci a vedere la finestra.

xaml:

  ....  

codebehind:

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

Questo era l’unico modo per me di mostrare la finestra in alto. Quindi triggerslo in modo da poter digitare nella casella senza dover mettere a fuoco con il mouse. control.Focus () non funzionerà se la finestra non è Active ();

Bene, ho capito un lavoro. Sto effettuando la chiamata da un hook della tastiera utilizzato per implementare un tasto di scelta rapida. La chiamata funziona come previsto se la metto in un Background Worker con una pausa. È un kludge, ma non ho idea del motivo per cui non funzionava in origine.

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

Per visualizzare QUALSIASI finestra attualmente aperta importare quelle 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 in programma Cerchiamo app con il titolo specificato (scrivi titolo senza prima lettera (indice> 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); } 

Il problema potrebbe essere che il thread che chiama il codice dall’hook non è stato inizializzato dal runtime, quindi i metodi di runtime non funzionano.

Forse potresti provare a fare un richiamo per eseguire il marshalling del tuo codice sul thread dell’interfaccia utente per chiamare il tuo codice che porta la finestra in primo piano.

Questi codici funzioneranno bene tutte le volte.

Per prima cosa imposta il gestore di eventi triggersto in XAML:

 Activated="Window_Activated" 

Aggiungi sotto la riga al blocco costruttore della finestra principale:

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

E all’interno del gestore di eventi triggersto copia questo codice:

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

Questi passaggi funzioneranno correttamente e porteranno in primo piano tutte le altre windows nella finestra dei loro genitori.

Se stai cercando di hide la finestra, ad esempio riduci la finestra, ho trovato che l’utilizzo

  this.Hide(); 

lo nasconderò correttamente, quindi semplicemente usando

  this.Show(); 

mostrerà quindi la finestra come l’elemento più in alto, ancora una volta.

Volevo solo aggiungere un’altra soluzione a questa domanda. Questa implementazione funziona per il mio scenario, in cui CaliBurn è responsabile della visualizzazione della finestra principale.

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

Ricordati di non inserire il codice che mostra quella finestra all’interno di un gestore di PreviewMouseDoubleClick, poiché la finestra triggers tornerà alla finestra che ha gestito l’evento. Basta inserirlo nel gestore di eventi MouseDoubleClick o interrompere il bubbling impostando e.Handled su True.

Nel mio caso stavo gestendo il PreviewMouseDoubleClick su un Listview e non stavo impostando il e.Handled = true, quindi ha sollevato l’evento MouseDoubleClick mantenendo il focus sulla finestra originale.

Ho creato un metodo di estensione per renderlo facile da riutilizzare.

 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 

Chiama il Costruttore di moduli

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