J'utilise un formulaire pour afficher des notifications (il apparaît en bas à droite de l'écran), mais lorsque je montre ce formulaire, il vole le focus du formulaire principal. Existe-t-il un moyen de montrer ce formulaire de "notification" sans voler le focus?
Hmmm, remplacer simplement Form.ShowWithoutActivation n'est pas suffisant?
protected override bool ShowWithoutActivation
{
get { return true; }
}
Et si vous ne voulez pas 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;
}
}
Volé de la méthode PInvoke.netShowWindow :
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 à cela, je le développe simplement en collant directement le code. Quelqu'un avec les droits de modification peut le copier là-bas et le supprimer pour tout ce qui me concerne;))
Si vous êtes prêt à utiliser Win32P/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 voler le focus.
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 de ne pas définir TopMost dans Visual Studio Designer ou ailleurs.
Ceci est volé, euh, emprunté, d'ici (cliquez sur les solutions de contournement):
Cela ressemble à un bidouillage, 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
Modifier: Remarque, cela soulève simplement une forme déjà créée sans voler le focus.
L'exemple de code extrait de pinvoke.net dans les réponses d'Alex Lyman/TheSoftwareJedi fera de la fenêtre une fenêtre "de premier plan", ce qui signifie que vous ne pourrez pas le placer derrière des fenêtres normales une fois qu'elle est apparue. Compte tenu de la description donnée par Matias de ce pour quoi il veut utiliser cela, cela pourrait être ce qu'il veut. Mais si vous voulez que l'utilisateur puisse placer votre fenêtre derrière d'autres fenêtres après l'avoir affichée, 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".
J'ai quelque chose de similaire, et je montre simplement le formulaire de notification, puis fais
this.Focus();
pour ramener l'attention sur la forme principale.
Vous voudrez peut-être examiner le type de notification que vous souhaitez afficher.
S'il est absolument essentiel d'informer l'utilisateur de certains événements, utiliser Messagebox.Show serait le moyen recommandé, 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é des pop-up, cependant.
Si ce n'est pas critique, vous pouvez utiliser une autre méthode d'affichage des notifications, telle qu'une barre d'outils au bas de la fenêtre. Vous avez écrit que vous affichez les notifications dans le coin inférieur droit de l'écran. Pour ce faire, la méthode standard consiste à utiliser l'icône info-bulle avec la combinaison d'une icône barre d'état système .
Créez et démarrez le formulaire de notification dans un thread séparé, puis 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'événement Form.Shown
. 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 une poignée pour 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.
Ça marche 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);
}
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, la substitution de "ShowWithoutActivation" ne fonctionne pas dans ce cas car la nouvelle fenêtre doit toujours être au premier plan. Quoi qu'il en soit, j'ai créé une méthode d'assistance qui prend une forme en tant que paramètre. lorsqu'il est appelé, il affiche le formulaire, l'amène au premier plan et en fait TopMost sans dérober le focus de la fenêtre en cours (apparemment, oui, 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);
}
}
Vous pouvez y faire face uniquement par la logique, même si je dois admettre que les suggestions ci-dessus, qui aboutissent à une méthode BringToFront sans voler réellement le focus, sont les suivantes: le plus élégant.
Quoi qu'il en soit, j'ai rencontré ce problème et je l'ai résolu en utilisant une propriété DateTime pour ne pas autoriser d'autres appels BringToFront si des appels avaient déjà été passés.
Supposons une classe de base, "Core", qui traite par exemple trois formes, "Form1, 2 et 3". Chaque formulaire nécessite une propriété DateTime et un événement Activate qui appelle Core pour afficher des fenêtres:
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 créez ensuite le travail dans la classe de base:
internal static void BringAllToFront(Form inForm)
{
Form1.BringToFront();
Form2.BringToFront();
Form3.BringToFront();
inForm.Focus();
}
Sur une note de côté, si vous souhaitez restaurer une fenêtre réduite à son état d'origine (non maximisée), utilisez:
inForm.WindowState = FormWindowState.Normal;
Encore une fois, je sais qu'il ne s'agit que d'une solution de correctif en l'absence de BringToFrontWithoutFocus. Il s’agit d’une suggestion si vous souhaitez éviter le fichier DLL.
Je sais que cela peut paraître stupide, mais cela a fonctionné:
this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
Je devais le faire avec ma fenêtre TopMost. J'ai implémenté la méthode PInvoke ci-dessus mais j'ai constaté que mon événement Load n'était pas appelé comme Talha ci-dessus. J'ai finalement réussi. Cela aidera peut-être 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