2011-10-13 1 views
6

Sto riscontrando alcuni problemi nel far funzionare correttamente una casella di notifica in C#. Fondamentalmente sto mostrando una scheda senza bordo nella parte in basso a destra dello schermo, che mostra un messaggio per alcuni secondi e poi scompare. Il problema è che ho bisogno che appaia in cima alle altre finestre senza che sia mai in grado di rubare lo stato attivo. Idealmente, voglio che sia un codice puramente gestito, anche se osservando esempi simili dubito che ciò sia possibile.Finestra di notifica - Impedire alla finestra di ottenere sempre lo stato attivo

Al momento sto impedendogli di rubare messa a fuoco quando si chiama Form.Show() con un override:

protected override bool ShowWithoutActivation // stops the window from stealing focus 
{ 
    get { return true; } 
} 

e quindi ignorando clic del mouse con:

private const int WM_MOUSEACTIVATE = 0x0021; 
    private const int MA_NOACTIVATEANDEAT = 0x0004; 

    protected override void WndProc(ref Message m) 
    { 
     if (m.Msg == WM_MOUSEACTIVATE) 
     { 
      m.Result = (IntPtr)MA_NOACTIVATEANDEAT; 
      return; 
     } 
     base.WndProc(ref m); 
    } 

Tuttavia trovo che se li uso insieme a TopMost = true (di cui ho bisogno), ottiene comunque la messa a fuoco, e se tutte le altre finestre sono ridotte a icona, ottiene anche l'attenzione.

Quindi, esiste un modo per evitare che un modulo ottenga mai la messa a fuoco (sia tramite clic del mouse, alt-tab, ecc.), Pur rimanendo il più alto/secondo in alto nella maggior parte dei moduli? Anche solo dare fuoco immediatamente alla finestra che ha rubato avrebbe funzionato (anche se introdurre sfarfallio).

Qualsiasi suggerimento sarebbe molto apprezzato, sono davvero bloccato con questo.

EDIT:

Ok, così ho finalmente riuscito a ottenere questo lavoro utilizzando:

protected override bool ShowWithoutActivation // stops the window from stealing focus 
{ 
    get { return true; } 
} 

// and 

const int WS_EX_NOACTIVATE = 0x08000000; 
const int WS_EX_TOPMOST = 0x00000008; 

protected override CreateParams CreateParams 
{ 
    get 
    { 
     CreateParams param = base.CreateParams; 
     param.ExStyle |= WS_EX_TOPMOST; // make the form topmost 
     param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated 
     return param; 
    } 
} 

// and 

[DllImport("user32.dll")] 
private extern static IntPtr SetActiveWindow(IntPtr handle); 
private const int WM_ACTIVATE = 6; 
private const int WA_INACTIVE = 0; 

private const int WM_MOUSEACTIVATE = 0x0021; 
private const int MA_NOACTIVATEANDEAT = 0x0004; 

protected override void WndProc(ref Message m) 
{ 
    if (m.Msg == WM_MOUSEACTIVATE) 
    { 
     m.Result = (IntPtr)MA_NOACTIVATEANDEAT; // prevent the form from being clicked and gaining focus 
     return; 
    } 
    if (m.Msg == WM_ACTIVATE) // if a message gets through to activate the form somehow 
    { 
     if (((int)m.WParam & 0xFFFF) != WA_INACTIVE) 
     { 

      if (m.LParam != IntPtr.Zero) 
      { 
       SetActiveWindow(m.LParam); 
      } 
      else 
      { 
       // Could not find sender, just in-activate it. 
       SetActiveWindow(IntPtr.Zero); 
      } 

     } 
    } 

Ho anche aggiunto Form.Hide() per l'evento attivato in modo che, anche se lo fa in qualche modo ottenere attenzione , semplicemente si chiude e esce dagli utenti appena possibile.

Inoltre, se qualcuno si chiede, le costanti per tutti gli stili di finestra ecc. Possono essere trovate in WINUSER.H, è in linea a http://www.woodmann.com/fravia/sources/WINUSER.H se non riesci a trovarlo.

Tuttavia, se qualcuno può vedere un modo più elegante di farlo, sarebbe apprezzato.

risposta

2

Forse WS_EX_NOACTIVATE lo stile di finestra esteso è quello che stai cercando. La finestra con questo stile non è attivata quando si fa clic. Ad esempio, la finestra Tastiera virtuale ha questo stile.

Per applicare questo stile alla finestra, eseguire l'override della funzione CreateParams e modificare baseParams.ExStyle.

+1

Grazie, questo è perfetto per evitare che si accenda, non appare nemmeno in alt-tab ora che è fantastico. L'unico problema minore che sto ancora avendo è che TopMost = true sembra sovrascrivere ShowWithoutActivation, quindi ottiene ancora lo stato attivo quando viene chiamato form.Show(). C'è un modo per aggirare questo? – yebetrollin

+0

Vedi la risposta di Ziketo per quello. Ricorda anche di votare le domande delle persone che hanno aiutato. –

3

In WPF provare questo:

ShowActivated="False" 
0

Io non sto cercando per i punti qui come il manifesto originale già inviato una soluzione che ha funzionato per loro, ma ho voluto condividere la mia esperienza con questo problema. L'uso della soluzione sopra (che è in fondo alla domanda invece che nel modulo di risposta) mi dà un Win32Exception: Error creating window handle error. quando si utilizza il codice WndProc così come viene pubblicato lì. La parte ShowWithoutActivation e CreateParams funziona in modo ottimale per impedire l'attivazione di un modulo e mantenerlo in primo piano.

mi si avvicinò con una soluzione alternativa per evitare una forma di essere cliccato utilizzando SetWindowLong che rende la forma trasparente e quindi può essere cliccato attraverso e SetLayeredWindowAttributes che definisce la trasparenza torna alla normalità in modo da poter vedere di nuovo, ma ancora la forma mantenere la possibilità di fare clic sul modulo.

NOTA: È -non possono- interagire con la forma a tutti in questo stato e anche cercando di fare clic sul pulsante 'X' sarà solo cliccare su ciò che è dietro la forma in quella posizione per cui sarà necessario utilizzare il codice per chiudere il modulo:

public partial class Form1 : Form 
{ 
    private enum GWL : int 
    { 
     ExStyle = -20 
    } 

    private enum WS_EX : int 
    { 
     Transparent = 0x20, 
     Layered = 0x80000 
    } 

    public enum LWA : int 
    { 
     ColorKey = 0x1, 
     Alpha = 0x2 
    } 

    [DllImport("user32.dll")] 
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); 

    [DllImport("user32.dll")] 
    static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags); 

    protected override bool ShowWithoutActivation 
    { 
     get { return true; } 
    } 

    const int WS_EX_NOACTIVATE = 0x08000000; 
    const int WS_EX_TOPMOST = 0x00000008; 

    protected override CreateParams CreateParams 
    { 
     get 
     { 
      CreateParams param = base.CreateParams; 
      param.ExStyle |= WS_EX_TOPMOST; // make the form topmost 
      param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated 
      return param; 
     } 
    } 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     // Prevent form from showing up in taskbar which also prevents activation by Alt+Tab 

     this.ShowInTaskbar = false; 

     // Allow the form to be clicked through so that the message never physically interferes with work being done on the computer 

     SetWindowLong(this.Handle, (int)GWL.ExStyle, (int)WS_EX.Layered | (int)WS_EX.Transparent); 

     // Set the opacity of the form 

     byte nOpacity = 255; // 0 = invisible, 255 = solid, anything inbetween will show the form with transparency 
     SetLayeredWindowAttributes(this.Handle, 0, nOpacity, (uint)LWA.Alpha); 
    } 
} 

sono stato anche in grado di ottenere l'approccio originale di lavoro facendo una piccola modifica al codice di WndProc sopra.

NOTA: Questo rende anche la forma cliccabile, ma il comportamento è diverso in quanto si può effettivamente fare clic sui pulsanti 'X' min, max e ma non accade nulla quando si fa. Il cursore del mouse cambia anche quando ci si trova sul bordo del modulo come per ridimensionare ma non consente il ridimensionamento:

public partial class Form1 : Form 
{ 
    protected override bool ShowWithoutActivation 
    { 
     get { return true; } 
    } 

    const int WS_EX_NOACTIVATE = 0x08000000; 
    const int WS_EX_TOPMOST = 0x00000008; 

    protected override CreateParams CreateParams 
    { 
     get 
     { 
      CreateParams param = base.CreateParams; 
      param.ExStyle |= WS_EX_TOPMOST; // make the form topmost 
      param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated 
      return param; 
     } 
    } 

    [DllImport("user32.dll")] 
    private extern static IntPtr SetActiveWindow(IntPtr handle); 
    private const int WM_ACTIVATE = 6; 
    private const int WA_INACTIVE = 0; 

    private const int WM_MOUSEACTIVATE = 0x0021; 
    private const int MA_NOACTIVATEANDEAT = 0x0004; 

    protected override void WndProc(ref Message m) 
    { 
     if (m.Msg == WM_MOUSEACTIVATE) 
     { 
      m.Result = (IntPtr)MA_NOACTIVATEANDEAT; // prevent the form from being clicked and gaining focus 
      return; 
     } 
     if (m.Msg == WM_ACTIVATE) // if a message gets through to activate the form somehow 
     { 
      if (((int)m.WParam & 0xFFFF) != WA_INACTIVE) 
      { 

       if (m.LParam != IntPtr.Zero) 
       { 
        SetActiveWindow(m.LParam); 
       } 
       else 
       { 
        // Could not find sender, just in-activate it. 
        SetActiveWindow(IntPtr.Zero); 
       } 

      } 
     } 
     else 
     { 
      base.WndProc(ref m); 
     } 
    } 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     // Prevent form from showing up in taskbar which also prevents activation by Alt+Tab 

     this.ShowInTaskbar = false; 
    } 
}