Risposte:
Hmmm, non è semplicemente scavalcando Form.ShowWithoutActivation abbastanza?
protected override bool ShowWithoutActivation
{
get { return true; }
}
E se non vuoi che l'utente faccia clic su questa finestra di notifica, puoi ignorare 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
per impedire ai controlli interni di rubare la messa a fuoco
WS_EX_NOACTIVATE
e WS_EX_TOOLWINDOW
sono 0x08000000
e 0x00000080
rispettivamente.
Stolen da PInvoke.net 's ShowWindow metodo:
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 ha risposto a questo, lo sto semplicemente espandendo incollando direttamente il codice. Qualcuno con diritti di modifica può copiarlo lì ed eliminarlo per quello che mi interessa;))
Se si desidera utilizzare Win32 P / Invoke , è possibile utilizzare il metodo ShowWindow (il primo esempio di codice fa esattamente quello che si desidera).
Questo è ciò che ha funzionato per me. Fornisce TopMost ma senza rubare la concentrazione.
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;
}
}
Ricorda di omettere l'impostazione TopMost nella finestra di progettazione di Visual Studio o altrove.
Questo viene rubato, err, preso in prestito, da qui (fare clic su Soluzioni alternative):
Fare questo sembra un trucco, ma sembra funzionare:
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
Modifica: Nota, questo solleva semplicemente una forma già creata senza rubare lo stato attivo.
Il codice di esempio di pinvoke.net nelle risposte di Alex Lyman / TheSoftwareJedi renderà la finestra una finestra "più in alto", il che significa che non puoi metterla dietro le finestre normali dopo che è spuntata. Data la descrizione di Matias di ciò per cui vuole usarlo, potrebbe essere quello che vuole. Ma se vuoi che l'utente sia in grado di mettere la tua finestra dietro altre finestre dopo averla spuntata, usa HWND_TOP (0) invece di HWND_TOPMOST (-1) nell'esempio.
In WPF puoi risolverlo in questo modo:
Nella finestra inserisci questi attributi:
<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>
L'ultimo attributo è quello che ti serve ShowActivated = "False".
Creare e avviare il modulo di notifica in un thread separato e reimpostare lo stato attivo sul modulo principale dopo l'apertura del modulo. Chiedi al modulo di notifica di fornire un evento OnFormOpened che viene generato Form.Shown
dall'evento. Qualcosa come questo:
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
}
Puoi anche mantenere un handle per il tuo oggetto NotifcationForm in modo che possa essere programmaticamente chiuso dal modulo principale (frm.Close()
).
Mancano alcuni dettagli, ma speriamo che questo ti porti nella giusta direzione.
Potresti prendere in considerazione il tipo di notifica che desideri visualizzare.
Se è assolutamente fondamentale informare l'utente di qualche evento, utilizzare Messagebox.Show sarebbe il modo consigliato, a causa della sua natura per bloccare qualsiasi altro evento nella finestra principale, fino a quando l'utente non lo conferma. Fai attenzione alla cecità dei pop-up, però.
Se è meno che critico, potresti voler utilizzare un modo alternativo per visualizzare le notifiche, come una barra degli strumenti nella parte inferiore della finestra. Hai scritto che visualizzi le notifiche nella parte in basso a destra dello schermo: il modo standard per farlo è quello di utilizzare una punta a palloncino con la combinazione di un'icona nella barra delle applicazioni .
Funziona bene
Vedi: OpenIcon - MSDN e 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);
}
È possibile gestire da sola logica troppo, anche se devo ammettere che i suggerimenti di cui sopra in cui si finisce con un metodo BringToFront senza in realtà rubare messa a fuoco è la più elegante.
Ad ogni modo, mi sono imbattuto in questo e l'ho risolto utilizzando una proprietà DateTime per non consentire ulteriori chiamate BringToFront se le chiamate sono state effettuate già di recente.
Supponi una classe principale, "Core", che gestisce ad esempio tre forme, "Form1, 2 e 3". Ogni modulo richiede una proprietà DateTime e un evento Activate che chiama Core per mettere in primo piano Windows:
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;
}
E quindi creare il lavoro nella classe principale:
internal static void BringAllToFront(Form inForm)
{
Form1.BringToFront();
Form2.BringToFront();
Form3.BringToFront();
inForm.Focus();
}
In una nota a margine, se si desidera ripristinare una finestra ridotta a icona al suo stato originale (non ingrandita), utilizzare:
inForm.WindowState = FormWindowState.Normal;
Ancora una volta, so che questa è solo una soluzione di patch in mancanza di BringToFrontWithoutFocus. È inteso come suggerimento se si desidera evitare il file DLL.
Non so se questo sia considerato necro-posting, ma questo è quello che ho fatto da quando non riesco a farlo funzionare con i metodi "ShowWindow" e "SetWindowPos" di user32. E no, in questo caso l'override di "ShowWithoutActivation" non funziona poiché la nuova finestra dovrebbe essere sempre in primo piano. Comunque, ho creato un metodo di supporto che assume una forma come parametro; quando viene chiamato, mostra il modulo, lo porta in primo piano e lo rende TopMost senza rubare il focus della finestra corrente (apparentemente lo fa, ma l'utente non se ne accorgerà).
[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);
}
}
So che può sembrare stupido, ma ha funzionato:
this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
Ho dovuto farlo con la mia finestra TopMost. Ho implementato il metodo PInvoke sopra ma ho scoperto che il mio evento Load non veniva chiamato come Talha sopra. Alla fine ci sono riuscito. Forse questo aiuterà qualcuno. Ecco la mia soluzione:
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
Quando si crea un nuovo modulo utilizzando
Form f = new Form();
f.ShowDialog();
ruba lo stato attivo perché il codice non può continuare l'esecuzione sul modulo principale fino a quando questo modulo non viene chiuso.
L'eccezione è l'utilizzo del threading per creare un nuovo modulo, quindi Form.Show (). Assicurati che il thread sia visibile globalmente, perché se lo dichiari all'interno di una funzione, non appena la tua funzione viene chiusa, il thread terminerà e il modulo scomparirà.
Capito: window.WindowState = WindowState.Minimized;
.