Réponses:
Hmmm, il ne suffit pas de remplacer Form.ShowWithoutActivation?
protected override bool ShowWithoutActivation
{
get { return true; }
}
Et si vous ne voulez pas non plus que l'utilisateur clique sur cette fenêtre de notification, vous pouvez remplacer CreateParams:
protected override CreateParams CreateParams
{
get
{
CreateParams baseParams = base.CreateParams;
const int WS_EX_NOACTIVATE = 0x08000000;
const int WS_EX_TOOLWINDOW = 0x00000080;
baseParams.ExStyle |= ( int )( WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW );
return baseParams;
}
}
form1.Enabled = false
pour empêcher les commandes internes de voler la mise au point
WS_EX_NOACTIVATE
et WS_EX_TOOLWINDOW
sont 0x08000000
et 0x00000080
respectivement.
Stolen de PInvoke.net de ShowWindow procédé:
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
int hWnd, // Window handle
int hWndInsertAfter, // Placement-order handle
int X, // Horizontal position
int Y, // Vertical position
int cx, // Width
int cy, // Height
uint uFlags); // Window positioning flags
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
static void ShowInactiveTopmost(Form frm)
{
ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST,
frm.Left, frm.Top, frm.Width, frm.Height,
SWP_NOACTIVATE);
}
(Alex Lyman a répondu à cette question, je ne fais que l'étendre en collant directement le code. Quelqu'un avec les droits d'édition peut le copier là-bas et le supprimer pour tout ce que je veux;))
Si vous souhaitez utiliser Win32 P / Invoke , vous pouvez utiliser la méthode ShowWindow (le premier exemple de code fait exactement ce que vous voulez).
C'est ce qui a fonctionné pour moi. Il fournit TopMost mais sans vol de concentration.
protected override bool ShowWithoutActivation
{
get { return true; }
}
private const int WS_EX_TOPMOST = 0x00000008;
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= WS_EX_TOPMOST;
return createParams;
}
}
N'oubliez pas d'omettre de définir TopMost dans le concepteur Visual Studio ou ailleurs.
Ceci est volé, err, emprunté, à partir d'ici (cliquez sur Solutions de contournement):
Faire cela semble être un hack, mais cela semble fonctionner:
this.TopMost = true; // as a result the form gets thrown to the front
this.TopMost = false; // but we don't actually want our form to always be on top
Edit: Notez que cela soulève simplement un formulaire déjà créé sans voler le focus.
L'exemple de code de pinvoke.net dans les réponses d'Alex Lyman / TheSoftwareJedi fera de la fenêtre une fenêtre "la plus haute", ce qui signifie que vous ne pouvez pas la mettre derrière des fenêtres normales après qu'elle soit apparue. Étant donné la description de Matias de ce qu'il veut utiliser, cela pourrait être ce qu'il veut. Mais si vous souhaitez que l'utilisateur puisse placer votre fenêtre derrière d'autres fenêtres après l'avoir ouverte, utilisez simplement HWND_TOP (0) au lieu de HWND_TOPMOST (-1) dans l'exemple.
Dans WPF, vous pouvez le résoudre comme ceci:
Dans la fenêtre, mettez ces attributs:
<Window
x:Class="myApplication.winNotification"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Notification Popup" Width="300" SizeToContent="Height"
WindowStyle="None" AllowsTransparency="True" Background="Transparent" ShowInTaskbar="False" Topmost="True" Focusable="False" ShowActivated="False" >
</Window>
Le dernier attribut est celui dont vous avez besoin ShowActivated = "False".
Créez et démarrez le formulaire de notification dans un thread distinct et réinitialisez le focus sur votre formulaire principal une fois le formulaire ouvert. Demandez au formulaire de notification de fournir un événement OnFormOpened qui est déclenché à partir de l' Form.Shown
événement. Quelque chose comme ça:
private void StartNotfication()
{
Thread th = new Thread(new ThreadStart(delegate
{
NotificationForm frm = new NotificationForm();
frm.OnFormOpen += NotificationOpened;
frm.ShowDialog();
}));
th.Name = "NotificationForm";
th.Start();
}
private void NotificationOpened()
{
this.Focus(); // Put focus back on the original calling Form
}
Vous pouvez également conserver un handle vers votre objet NotifcationForm afin qu'il puisse être fermé par programme par le formulaire principal ( frm.Close()
).
Certains détails manquent, mais j'espère que cela vous permettra d'aller dans la bonne direction.
Vous voudrez peut-être envisager le type de notification que vous souhaitez afficher.
S'il est absolument essentiel d'informer l'utilisateur d'un événement, l'utilisation de Messagebox.Show serait la méthode recommandée, en raison de sa nature, pour bloquer tout autre événement dans la fenêtre principale, jusqu'à ce que l'utilisateur le confirme. Soyez conscient de la cécité pop-up, cependant.
Si c'est moins que critique, vous pouvez utiliser un autre moyen d'afficher les notifications, comme une barre d'outils en bas de la fenêtre. Vous avez écrit que vous affichez des notifications en bas à droite de l'écran - la manière standard de le faire serait d'utiliser une info-bulle avec la combinaison d'une icône de la barre d'état système .
Cela fonctionne bien.
Voir: OpenIcon - MSDN et SetForegroundWindow - MSDN
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
static extern bool OpenIcon(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
public static void ActivateInstance()
{
IntPtr hWnd = IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle;
// Restore the program.
bool result = OpenIcon(hWnd);
// Activate the application.
result = SetForegroundWindow(hWnd);
// End the current instance of the application.
//System.Environment.Exit(0);
}
Vous pouvez également le gérer uniquement par la logique, bien que je doive admettre que les suggestions ci-dessus où vous vous retrouvez avec une méthode BringToFront sans réellement voler le focus sont les plus élégantes.
Quoi qu'il en soit, je suis tombé sur ce problème et l'ai résolu en utilisant une propriété DateTime pour ne pas autoriser d'autres appels BringToFront si des appels ont déjà été effectués récemment.
Supposons une classe principale, «Core», qui gère par exemple trois formulaires, «Form1, 2 et 3». Chaque formulaire a besoin d'une propriété DateTime et d'un événement Activate qui appellent Core pour mettre les fenêtres au premier plan:
internal static DateTime LastBringToFrontTime { get; set; }
private void Form1_Activated(object sender, EventArgs e)
{
var eventTime = DateTime.Now;
if ((eventTime - LastBringToFrontTime).TotalMilliseconds > 500)
Core.BringAllToFront(this);
LastBringToFrontTime = eventTime;
}
Et puis créez le travail dans la classe principale:
internal static void BringAllToFront(Form inForm)
{
Form1.BringToFront();
Form2.BringToFront();
Form3.BringToFront();
inForm.Focus();
}
En passant, si vous souhaitez restaurer une fenêtre réduite à son état d'origine (non agrandi), utilisez:
inForm.WindowState = FormWindowState.Normal;
Encore une fois, je sais que ce n'est qu'une solution corrective en l'absence de BringToFrontWithoutFocus. Il s'agit d'une suggestion si vous souhaitez éviter le fichier DLL.
Je ne sais pas si cela est considéré comme une nécro-publication, mais c'est ce que j'ai fait car je ne pouvais pas le faire fonctionner avec les méthodes "ShowWindow" et "SetWindowPos" de user32. Et non, le remplacement de "ShowWithoutActivation" ne fonctionne pas dans ce cas puisque la nouvelle fenêtre doit être toujours en haut. Quoi qu'il en soit, j'ai créé une méthode d'assistance qui prend la forme d'un paramètre; lorsqu'il est appelé, il montre le formulaire, l'amène au premier plan et le rend TopMost sans voler le focus de la fenêtre actuelle (apparemment, c'est le cas, mais l'utilisateur ne le remarquera pas).
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern IntPtr SetForegroundWindow(IntPtr hWnd);
public static void ShowTopmostNoFocus(Form f)
{
IntPtr activeWin = GetForegroundWindow();
f.Show();
f.BringToFront();
f.TopMost = true;
if (activeWin.ToInt32() > 0)
{
SetForegroundWindow(activeWin);
}
}
Je sais que cela peut sembler stupide, mais cela a fonctionné:
this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
J'avais besoin de le faire avec ma fenêtre TopMost. J'ai implémenté la méthode PInvoke ci-dessus, mais j'ai trouvé que mon événement Load n'était pas appelé comme Talha ci-dessus. J'ai finalement réussi. Peut-être que cela aidera quelqu'un. Voici ma solution:
form.Visible = false;
form.TopMost = false;
ShowWindow(form.Handle, ShowNoActivate);
SetWindowPos(form.Handle, HWND_TOPMOST,
form.Left, form.Top, form.Width, form.Height,
NoActivate);
form.Visible = true; //So that Load event happens
Lorsque vous créez un nouveau formulaire en utilisant
Form f = new Form();
f.ShowDialog();
il vole le focus car votre code ne peut pas continuer à s'exécuter sur le formulaire principal tant que ce formulaire n'est pas fermé.
L'exception consiste à utiliser le thread pour créer un nouveau formulaire, puis Form.Show (). Assurez-vous cependant que le thread est globalement visible, car si vous le déclarez dans une fonction, dès que votre fonction se termine, votre thread se terminera et le formulaire disparaîtra.
Figured it out: window.WindowState = WindowState.Minimized;
.