Apportez une fenêtre à l'avant de la WPF

Comment puis-je apporter mon application WPF sur le devant du bureau? Jusqu'à présent j'ai essayé:

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

dont aucun ne fait le travail ( Marshal.GetLastWin32Error() signifie que ces opérations sont terminées avec succès, et les attributs P/Invoke pour chaque définition ont SetLastError=true ).

si je crée une nouvelle application WPF vierge, et appelle SwitchToThisWindow avec une minuterie, cela fonctionne exactement comme prévu, donc je ne suis pas sûr pourquoi cela ne fonctionne pas dans mon original cas.

Edit : je le fais en conjonction avec un hotkey global.

181
demandé sur gmetax 2008-11-03 02:42:59

18 réponses

myWindow.Activate();

tente de mettre la fenêtre au premier plan et l'active.

ça devrait faire l'affaire, à moins que j'ai mal compris et que tu veuilles toujours avoir le meilleur comportement. Dans ce cas, vous voulez:

myWindow.TopMost = true;
264
répondu Morten Christiansen 2010-07-02 07:45:28

j'ai trouvé une solution qui amène la fenêtre vers le haut, mais elle se comporte comme une fenêtre 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
148
répondu Jader Dias 2015-06-23 15:54:17

dans le cas où vous avez besoin de la fenêtre d'être à l'avant la première fois qu'il charge, alors vous devez utiliser ce qui suit:

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

private void Window_Initialized(object sender, EventArgs e)
{
    this.Topmost = true;
}
21
répondu Amir 2017-08-15 09:42:40

pour en faire un copy-paste rapide -

Utilisez cette classe' DoOnProcess méthode pour déplacer la fenêtre principale du processus au premier plan (mais pas pour voler la mise au point des autres fenêtres)

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

18
répondu Hertzel Guinness 2011-10-03 14:44:02

je sais que cette question est assez ancienne, mais je viens de tomber sur ce scénario précis et je voulais partager la solution que j'ai mis en œuvre.

comme mentionné dans les commentaires sur cette page, plusieurs des solutions proposées ne fonctionnent pas sur XP, que je dois soutenir dans mon scénario. Bien que je sois d'accord avec le sentiment de @Matthew Xavier que, Généralement, il s'agit d'une mauvaise pratique des UX, il y a des moments où il s'agit entièrement d'un UX abondant.

la solution pour apporter une fenêtre WPF au sommet m'a été fourni par le même code que j'utilise pour fournir la clé globale. un article de blog par Joseph Cooney contient un lien vers son code samples qui contient le code original.

j'ai nettoyé et modifié un peu le code, et l'ai implémenté comme une méthode d'extension au système.Windows.Fenêtre. J'ai testé cela sur XP 32 bit et Win7 64 bit, qui fonctionnent tous les deux correctement.

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

j'espère que ce code aidera les autres qui rencontrent ce problème.

17
répondu Zodman 2012-07-19 01:56:55

si l'utilisateur interagit avec une autre application, il ne sera peut-être pas possible d'amener la vôtre à l'avant. En règle générale, un processus ne peut s'attendre à définir la fenêtre de premier plan que si ce processus est déjà le processus de premier plan. (Microsoft documente les restrictions dans L'entrée MSDN SetForegroundWindow () .) C'est parce que:

  1. l'utilisateur "possède" le premier plan. Par exemple, il serait extrêmement ennuyeux si un autre le programme a volé le premier plan pendant que l'utilisateur tapait, à tout le moins interrompre son flux de travail, et peut-être causer des conséquences involontaires que ses frappes destinées à une application sont mal interprétées par le délinquant jusqu'à ce qu'elle remarque le changement.
  2. Imaginez que chacun des deux programmes vérifie pour voir si sa fenêtre est le premier plan et tente de le placer au premier plan si ce n'est pas le cas. Dès que le deuxième programme est en cours d'exécution, l'ordinateur est rendue inutile que l' premier plan rebondit entre les deux à chaque tâche de l'interrupteur.
13
répondu Matthew Xavier 2009-01-06 04:43:34

j'ai eu un problème similaire avec une application WPF qui est invoquée à partir d'une application D'accès via L'objet Shell.

ma solution est ci-dessous-fonctionne dans XP et Win7 x64 avec l'application compilée à la cible x86.

je préférerais faire ça plutôt que de simuler 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();
}
6
répondu Seth 2010-10-07 23:41:01

je sais que c'est une réponse tardive, peut-être utile pour les chercheurs

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }
5
répondu Jamaxack 2016-04-05 03:03:43

Pourquoi certaines réponses sur cette page sont faux!

  • toute réponse qui utilise window.Focus() est erronée.

    • pourquoi? Si un message de notification apparaît, window.Focus() détournera l'attention de ce que l'utilisateur tape à ce moment-là. Ceci est incroyablement frustrant pour les utilisateurs finaux, surtout si les popups se produisent assez fréquemment.
  • Toute réponse qui utilise window.Activate() est erronée.

    • pourquoi? Il fera tout parent fenêtres visibles.
  • toute réponse qui omet window.ShowActivated = false est fausse.
    • pourquoi? Il va saisir le foyer loin d'une autre fenêtre lorsque le message apparaît ce qui est très ennuyeux!
  • toute réponse qui n'utilise pas Visibility.Visible pour masquer / montrer la fenêtre est mal.
    • pourquoi? Si nous utilisons Citrix, si la fenêtre n'est pas effondrée quand elle est fermée, elle laissera une prise noire rectangulaire bizarre sur l'écran. Nous ne pouvons donc pas utiliser window.Show() et window.Hide() .

essentiellement:

  • la fenêtre ne doit pas détourner le foyer d'une autre fenêtre lorsqu'elle s'active;
  • la fenêtre ne doit pas activer son parent lorsqu'il est affiché;
  • la fenêtre doit être compatible avec Citrix.

MVVM Solution

ce code est 100% compatible avec Citrix (aucune zone vierge de l'écran). Il est testé avec le WPF normal et DevExpress.

Cette réponse est destinée aux cas d'utilisation où nous voulons une petite fenêtre de notification qui est toujours devant les autres fenêtres (si l'utilisateur choisit cette dans les préférences).

si cette réponse semble plus complexe que les autres, c'est parce qu'elle est robuste, code d'entreprise. Certains des autres réponses sur cette page sont simples, mais ne l'est pas réellement.

XAML de la Propriété Attachée

ajouter cette propriété jointe à tout UserControl dans la fenêtre. La propriété ci-jointe sera:

  • attendez que l'événement Loaded soit déclenché (sinon, il ne peut pas rechercher l'arborescence visuelle pour trouver la fenêtre parent).
  • Ajouter un gestionnaire d'événements qui assure que la fenêtre est visible ou non.

en tout point, vous pouvez placer la fenêtre devant ou non, en retournant la valeur de la propriété attachée.

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

C# À L'Aide De La Méthode

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

Utilisation

pour utiliser ceci, vous devez créer la fenêtre dans votre 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);
    }
}

liens supplémentaires

Pour des conseils sur comment s'assurer qu'une fenêtre de notification tourne toujours en arrière sur l'écran visible, voir ma réponse: Dans WPF, comment déplacer une fenêtre sur l'écran si elle est hors de l'écran? .

5
répondu Contango 2017-05-23 12:26:26

bien, puisque c'est un sujet brûlant... voici ce qui fonctionne pour moi. J'ai eu des erreurs si Je ne l'ai pas fait de cette façon parce que Activate() va faire une erreur sur vous si vous ne pouvez pas voir la fenêtre.

Xaml:

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

Codebehind:

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

C'était le seul moyen pour moi d'obtenir la fenêtre à afficher sur le dessus. Puis activez-le pour que vous puissiez taper dans la boîte sans avoir à mettre la mise au point avec la souris. contrôle.Focus() ne fonctionnent pas sauf si la fenêtre est Active ();

4
répondu Omzig 2013-11-26 15:16:03

J'ai trouvé un travail. Je fais l'appel à partir d'un crochet de clavier utilisé pour implémenter un hotkey. L'appel fonctionne comme prévu si je le mets dans un BackgroundWorker avec une pause. C'est un kludge, mais je ne sais pas pourquoi ça ne marchait pas à l'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();
}
2
répondu Factor Mystic 2008-11-03 01:40:26

pour montrer toute fenêtre actuellement ouverte importer ces 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);

et dans le programme nous cherchons app avec le titre spécifié (écrire le titre sans première lettre (index > 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);
                }
2
répondu rahmud 2010-11-11 17:32:59

le problème pourrait être que le thread appelant votre code depuis le crochet n'a pas été initialisé par l'exécution, donc appeler les méthodes d'exécution ne fonctionne pas.

peut-être pourriez-vous essayer de faire une invocation pour marshaliser votre code sur le fil UI pour appeler votre code qui amène la fenêtre au premier plan.

1
répondu joshperry 2009-02-27 21:03:31

ces codes fonctionneront très bien à tout moment.

d'abord régler le gestionnaire d'événements activé dans XAML:

Activated="Window_Activated"

ajoutez ci-dessous la ligne à votre bloc constructeur de fenêtre principale:

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

et copiez ce code dans le gestionnaire d'événements activé:

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

Ces étapes fonctionne très bien et devant toutes les autres fenêtres de leurs parents fenêtre.

1
répondu Matrix 2017-02-05 09:56:03

Si vous essayez de cacher la fenêtre, par exemple, vous réduisez la fenêtre, j'ai trouvé que l'utilisation de

    this.Hide();

va le cacher correctement, puis simplement en utilisant

    this.Show();

montrera alors la fenêtre comme le plus haut article une fois de plus.

0
répondu Chris 2014-09-24 18:31:06

voulait juste ajouter une autre solution à cette question. Cette implémentation fonctionne pour mon scénario, où CaliBurn est responsable de l'affichage de la fenêtre principale.

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();
    }
}
0
répondu d.moncada 2017-04-12 21:19:44

se rappeler de ne pas mettre le code qui montre que la fenêtre à l'intérieur D'un handler PreviewMouseDoubleClick comme la fenêtre active reviendra à la fenêtre qui a manipulé l'événement. Il suffit de le mettre dans le gestionnaire D'événements MouseDoubleClick ou d'arrêter de barboter en plaçant E. Manipulé à vrai.

dans mon cas, je manipulais le clic de souris précédent sur un Listview et je ne paramétrais pas le E. Handled = true then it raised the MouseDoubleClick event witch sat focus back to the original fenêtre.

0
répondu Michel P. 2017-04-24 19:45:34

j'ai construit une méthode d'extension pour faciliter la réutilisation.

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

appel dans la forme constructeur

namespace YourNamespace{
       public partial class FormName : Form {
       public FormName(){
            this.PutOnTop();
            InitalizeComponents();
        }// END Constructor
    } // END Form            
}// END namespace
0
répondu Mike 2017-05-19 21:27:29