2010-05-15 8 views
5

J'ai une application winforms C# qui fonctionne en arrière-plan, en écoutant les raccourcis clavier à appuyer. Quand une touche de raccourci est pressée, ma forme fait une brève apparition. Le formulaire est toujours en cours d'exécution, mais mis à masqué jusqu'à ce que je reçois un événement de raccourci clavier, à ce moment, j'ai défini la propriété visible sur true. Le code ressemble à ceci:Comment empêcher mon application winforms C# de dérober le focus lorsque je mets le visible correctement à true?

void hook_volumeDown(object sender, KeyPressedEventArgs e) 
{ 
    this.Visible = true; 
} 

Il convient de noter que la propriété la plus haute de cette forme est définie sur true.

La partie vraiment étrange est, après que mon application C# a volé le focus d'une autre application, il ne le fera plus jamais. Par exemple: je lance mon application, puis lance une application fullscreep comme Team Fortress 2. Ensuite, j'appuie sur mon raccourci clavier. Team Fortress 2 minimise, et je vois ma forme. Ensuite, je peux restaurer TF2, et appuyer à nouveau sur ma touche de raccourci tout ce que je veux (avec l'effet désiré), et TF2 restera focalisé.

En tout cas, je cherche un moyen de résoudre ce problème. J'ai trouvé beaucoup de questions ici couvrant des problèmes similaires, mais toutes sont liées à la création/lancement d'un nouveau formulaire, et non à la création d'un formulaire existant (sauf si j'ai manqué quelque chose). Je pourrais retravailler l'application pour créer un nouveau formulaire à chaque fois que j'en aurais besoin, mais cela impliquerait de créer un autre formulaire invisible tout le temps juste pour attendre les raccourcis clavier, donc je préfère laisser ça tel quel.

Des idées?

+0

Je ne suis pas sûr que je suis ... dites-vous que cela fonctionne comme il se doit * sauf * pour la toute première fois? –

Répondre

6

Je pense que votre problème est lié au fait que Visible = true se comporte différemment entre le premier et les appels suivants. La première fois visible est appelée et le handle de fenêtre n'a pas été créé, la fenêtre est créée en appelant CreateWindowEx qui a certains paramètres de style qui contrôle comment la fenêtre doit se comporter. Je pense que vous devez vous assurer que la fenêtre est créée avec le style WS_EX_NOACTIVATE, ce que vous pouvez faire en remplaçant CreateParams.

Autres choses à essayer:

1) La fonction ShowWindow (utilisée par Visible = true) ne tient pas compte du paramètre de mise au point la première fois qu'il est appelé (http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx) si le programme fournit une structure STARTUPINFO. Creusez dans le réflecteur et découvrez si la classe Form fournit une structure STARTUPINFO et si oui, comment la manipuler.

2) Le formulaire a une propriété ShowWithoutActivation qui peut être redéfinie et définie sur true, avez-vous surchargé cela?

Désolé pour le "pas de réponse exacte", mais j'espère que cela vous donne au moins quelques points de départ pour une enquête plus approfondie. Bonne chance.

+1

Merci, écrasant ShowWithoutActivation s'est avéré être la solution parfaite. Une ligne de code et tout est fixé. – Fopedush

+0

Overriding ShowWithoutActivation est la solution parfaite pour moi aussi. – beppe9000

1

Voyant KeyPressedEventArgs utilisé dans votre fonction ressemble vraiment étrange. Les touches d'accès rapide peuvent être implémentées en appelant la fonction API RegisterHotKey(). Il envoie un message à votre fenêtre lorsque vous appuyez sur la touche de raccourci. Voici un exemple de formulaire invisible au démarrage, qui apparaît lorsque vous appuyez sur la touche de raccourci. Ctrl + Alt + U dans ce cas:

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

namespace WindowsFormsApplication1 { 
    public partial class Form1 : Form { 
     private const int MYKEYID = 0; // In case you want to register more than one... 
     public Form1() { 
      InitializeComponent(); 
      this.FormClosing += (s, args) => UnregisterHotKey(this.Handle, MYKEYID); 
     } 
     protected override void SetVisibleCore(bool value) { 
      if (value && !this.IsHandleCreated) { 
       this.CreateHandle(); 
       RegisterHotKey(this.Handle, MYKEYID, MOD_CONTROL + MOD_SHIFT, Keys.U); 
       value = false; 
      } 
      base.SetVisibleCore(value); 
     } 
     protected override void WndProc(ref Message m) { 
      if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == MYKEYID) { 
       this.Visible = true; 
       if (this.WindowState == FormWindowState.Minimized) 
        this.WindowState = FormWindowState.Normal; 
       SetForegroundWindow(this.Handle); 
      } 
      base.WndProc(ref m); 
     } 
     // P/Invoke declarations 
     private const int WM_HOTKEY = 0x312; 
     private const int MOD_ALT = 1; 
     private const int MOD_CONTROL = 2; 
     private const int MOD_SHIFT = 4; 
     [DllImport("user32.dll")] 
     private static extern int RegisterHotKey(IntPtr hWnd, int id, int modifier, Keys vk); 
     [DllImport("user32.dll")] 
     private static extern bool UnregisterHotKey(IntPtr hWnd, int id); 
     [DllImport("user32.dll")] 
     private static extern bool SetForegroundWindow(IntPtr hWnd); 
    } 
} 

Notez que la fonction SetForegroundWindow() est que le bât blesse, peut-être aussi la source du problème que vous décrivez dans votre question. Windows n'autorise pas une application à pousser une fenêtre dans le visage de l'utilisateur lorsque celui-ci utilise activement une autre fenêtre. Au moins plusieurs secondes d'inactivité doivent expirer avant que la fenêtre ne vole le focus. Avec le code donné, c'est assez facile à voir, le bouton de la barre des tâches de votre formulaire clignotera. Évitez de définir la propriété ShowInTaskbar sur false. Il n'est pas nécessaire de le faire avec ce code, le bouton de la barre des tâches n'apparaîtra pas tant que la touche de raccourci n'aura pas été enfoncée.

+0

Upvoting pour la minutie de votre réponse, même si je ne l'ai pas essayé. J'utilise une classe wrapper pour les raccourcis clavier qui fait essentiellement la même chose que vous avez montrée, puis déclenche un événement. Dans le cadre de cette application, il est important que l'entrée de la barre des tâches ne soit pas affichée, même lorsque la touche de raccourci est enfoncée. – Fopedush

+0

Je ne vois pas comment il est logique que votre fenêtre popup se perde derrière une plus grande fenêtre de premier plan sans aucun moyen pour l'utilisateur de pouvoir l'activer. Tant pis. –

+0

topmost est défini sur true, donc à moins de circonstances inhabituelles (application en plein écran), il sera visible. La fenêtre agit comme un OSD pour le volume du système, mes raccourcis augmentent/diminuent/le coupent. Le formulaire est littéralement juste une petite chose sans bordure avec une barre de progression et une étiquette indiquant le volume%. – Fopedush