web-dev-qa-db-fra.com

Comment faire pour qu'une fenêtre reste toujours au top dans .Net?

J'ai une application C # Winforms qui exécute une macro dans un autre programme. L’autre programme ouvre continuellement des fenêtres et donne l’impression que, faute de meilleur mot, il est fou. Je souhaite implémenter un bouton d'annulation qui arrêtera le processus, mais je n'arrive pas à obtenir la fenêtre pour rester au top. Comment puis-je faire cela en C #?

Edit: j'ai essayé TopMost = true; , mais l’autre programme continue d’ouvrir ses propres fenêtres par-dessus. Est-il possible d'envoyer ma fenêtre au sommet toutes les n millisecondes?

Modifier: La façon dont j'ai résolu ce problème consistait à ajouter une icône de la barre d'état système qui annulera le processus en double-cliquant dessus. L'icône de la barre d'état système ne soit pas masquée. Merci à tous ceux qui ont répondu. J'ai lu l'article sur la raison pour laquelle il n'y a pas de fenêtre "super-dessus" ... cela ne fonctionne logiquement pas.

81
jle

Form.TopMost fonctionnera à moins que l’autre programme ne crée les plus hautes fenêtres.

Il n'y a aucun moyen de créer une fenêtre qui n'est pas couverte par les nouvelles fenêtres les plus hautes d'un autre processus. Raymond Chen expliqué pourquoi.

149
RossFabricant

Je cherchais à rendre mon application WinForms "toujours au top" mais le réglage "TopMost" ne me faisait rien. Je savais que c'était possible parce que WinAmp le fait (avec un hôte d'autres applications).

Ce que j'ai fait était d'appeler "user32.dll". Je n'ai eu aucun scrupule à le faire et cela fonctionne très bien. C'est une option, de toute façon.

Commencez par importer l’espace de noms suivant:

using System.Runtime.InteropServices;

Ajoutez quelques variables à votre déclaration de classe:

private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;

Ajouter un prototype pour la fonction user32.dll:

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

Puis dans votre code (j'ai ajouté l'appel dans Form_Load ()), ajoutez l'appel:

SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);

J'espère que ça t'as aidé. référence

37
clamum

Si vous entendez par "devenir fou" que chaque fenêtre continue de voler le focus de l'autre, TopMost ne résoudra pas le problème.

Au lieu de cela, essayez:

CalledForm.Owner = CallerForm;
CalledForm.Show();

Cela montrera la forme 'enfant' sans que cela vole le focus. Le formulaire enfant restera également au-dessus de son parent, même si le parent est activé ou ciblé. Ce code ne fonctionne facilement que si vous avez créé une instance du formulaire enfant à partir du formulaire propriétaire. Sinon, vous devrez peut-être définir le propriétaire à l'aide de l'API.

21
Victor Stoddard

Définissez Form.TopMost

16
Reed Copsey

J'ai eu un laps de temps de 5 minutes et j'ai oublié de spécifier le formulaire dans son intégralité, comme ceci:

  myformName.ActiveForm.TopMost = true;

Mais ce que je voulais vraiment c'était CECI!

  this.TopMost = true;
6
Dave

Définissez le formulaire .TopMost propriété à true.

Vous ne voulez probablement pas le laisser ainsi tout le temps: définissez-le lorsque votre processus externe démarre et remettez-le à la fin.

6
Joel Coehoorn

J'ai résolu ce problème en créant une icône dans la barre d'état système dotée d'une option d'annulation.

5
jle

Le code suivant fait que la fenêtre reste toujours au dessus et la rend sans cadre.

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace StayOnTop
{
    public partial class Form1 : Form
    {
        private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
        private const UInt32 SWP_NOSIZE = 0x0001;
        private const UInt32 SWP_NOMOVE = 0x0002;
        private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        public Form1()
        {
            InitializeComponent();
            FormBorderStyle = FormBorderStyle.None;
            TopMost = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            SetWindowPos(this.Handle, HWND_TOPMOST, 100, 100, 300, 300, TOPMOST_FLAGS);
        }

        protected override void WndProc(ref Message m)
        {
            const int RESIZE_HANDLE_SIZE = 10;

            switch (m.Msg)
            {
                case 0x0084/*NCHITTEST*/ :
                    base.WndProc(ref m);

                    if ((int)m.Result == 0x01/*HTCLIENT*/)
                    {
                        Point screenPoint = new Point(m.LParam.ToInt32());
                        Point clientPoint = this.PointToClient(screenPoint);
                        if (clientPoint.Y <= RESIZE_HANDLE_SIZE)
                        {
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)13/*HTTOPLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)12/*HTTOP*/ ;
                            else
                                m.Result = (IntPtr)14/*HTTOPRIGHT*/ ;
                        }
                        else if (clientPoint.Y <= (Size.Height - RESIZE_HANDLE_SIZE))
                        {
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)10/*HTLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)2/*HTCAPTION*/ ;
                            else
                                m.Result = (IntPtr)11/*HTRIGHT*/ ;
                        }
                        else
                        {
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)16/*HTBOTTOMLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)15/*HTBOTTOM*/ ;
                            else
                                m.Result = (IntPtr)17/*HTBOTTOMRIGHT*/ ;
                        }
                    }
                    return;
            }
            base.WndProc(ref m);
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.Style |= 0x20000; // <--- use 0x20000
                return cp;
            }
        }
    }
}
5
BK Krish

Quelle est l’autre application que vous essayez de supprimer la visibilité? Avez-vous étudié d'autres moyens d'obtenir l'effet souhaité? Faites-le avant de soumettre vos utilisateurs à un comportement indésirable tel que vous le décrivez: ce que vous essayez de faire ressemble à ce que certains sites coquins font avec des fenêtres de navigateur ...

Au moins essayer d'adhérer à la règle de moindre surprise . Les utilisateurs s'attendent à pouvoir déterminer eux-mêmes l'ordre z de la plupart des applications. Vous ne savez pas ce qui est le plus important pour eux. Si vous changez quelque chose, vous devez vous concentrer sur l'autre application plutôt que sur la promotion de la vôtre.

Ceci est bien sûr plus compliqué, car Windows ne dispose pas d'un gestionnaire de fenêtres particulièrement sophistiqué. Deux approches se proposent:

  1. énumérant les fenêtres de niveau supérieur et vérifiant à quel processus ils appartiennent , en supprimant leur ordre z si c'est le cas . (Je ne sais pas s'il existe des méthodes de structure pour ces fonctions WinAPI.)
  2. Bricoler avec les autorisations des processus enfants pour l'empêcher d'accéder au bureau ... mais je n'essaierai pas cela jusqu'à ce que la procédure soit échouée, car le processus enfant risque de se retrouver dans l'état de zombie tout en nécessitant une interaction de l'utilisateur.
4
Pontus Gagge

Pourquoi ne pas faire de votre formulaire une boîte de dialogue:

myForm.ShowDialog();
4
Salim

Voici l'équivalent de SetForegroundWindow:

form.Activate();

J'ai vu des gens faire des choses étranges comme:

this.TopMost = true;
this.Focus();
this.BringToFront();
this.TopMost = false;

http://blog.jorgearimany.com/2010/10/win32-setforegroundwindow-equivalent-in.html

3
user2070066

Je sais que c'est vieux, mais je n'ai pas vu cette réponse.

Dans la fenêtre (xaml), ajoutez:

Deactivated="Window_Deactivated"

Dans le code derrière Window_Deactivated:

private void Window_Deactivated(object sender, EventArgs e)
    {
        Window window = (Window)sender;
        window.Activate();
    }

Cela gardera votre fenêtre au top.

1
waitWhat

Basé sur la réponse de clamum , et de commentaire de Kevin Vuilleumier à propos de l'autre indicateur responsable du comportement, j'ai créé cette bascule qui bascule entre top et pas sur le dessus en appuyant sur un bouton.

private void button1_Click(object sender, EventArgs e)
    {
        if (on)
        {
            button1.Text = "yes on top";
            IntPtr HwndTopmost = new IntPtr(-1);
            SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags);
            on = false;
        }
        else
        {
            button1.Text = "not on top";
            IntPtr HwndTopmost = new IntPtr(-2);
            SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags);
            on = true;
        }
    }
0
Tóth Dániel