Respostas:
Hmmm, não basta substituir Form.ShowWithoutActivation o suficiente?
protected override bool ShowWithoutActivation
{
get { return true; }
}
E se você não quiser que o usuário clique nessa janela de notificação, você pode substituir 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
para evitar controles internos da enfoque roubar
WS_EX_NOACTIVATE
e WS_EX_TOOLWINDOW
são 0x08000000
e 0x00000080
respectivamente.
Stolen de PInvoke.net 's ShowWindow método:
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 respondeu a isso, estou apenas expandindo-o colando diretamente o código. Alguém com direitos de edição pode copiá-lo por lá e excluí-lo para todo o que me importo;))
Se você estiver disposto a usar o Win32 P / Invoke , poderá usar o método ShowWindow (o primeiro exemplo de código faz exatamente o que você deseja).
Isto é o que funcionou para mim. Ele fornece o TopMost, mas sem roubar o foco.
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;
}
}
Lembre-se de omitir a configuração do TopMost no designer do Visual Studio ou em outro lugar.
Isso é roubado, errado, emprestado, a partir daqui (clique em Soluções alternativas):
Fazer isso parece um hack, mas parece funcionar:
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: Note, isso apenas gera um formulário já criado sem roubar o foco.
O código de exemplo do pinvoke.net nas respostas de Alex Lyman / TheSoftwareJedi tornará a janela uma janela "no topo", o que significa que você não pode colocá-lo atrás das janelas normais depois que ele aparecer. Dada a descrição de Matias sobre o que ele quer usar, pode ser o que ele quer. Mas se você deseja que o usuário possa colocar sua janela atrás de outras janelas depois que você a abriu, basta usar HWND_TOP (0) em vez de HWND_TOPMOST (-1) na amostra.
No WPF, você pode resolvê-lo assim:
Na janela, coloque estes atributos:
<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>
O último atributo é o que você precisa ShowActivated = "False".
Crie e inicie o formulário de notificação em um thread separado e redefina o foco novamente para o formulário principal após a abertura do formulário. Peça ao Formulário de notificação que forneça um evento OnFormOpened que seja acionado a partir do Form.Shown
evento. Algo assim:
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
}
Você também pode manter um identificador no objeto NotifcationForm, para que ele possa ser fechado programaticamente pelo formulário principal (frm.Close()
).
Alguns detalhes estão faltando, mas espero que isso o leve à direção certa.
Você pode considerar que tipo de notificação você gostaria de exibir.
Se for absolutamente crítico informar ao usuário sobre algum evento, usar o Messagebox.Show seria a maneira recomendada, devido à sua natureza para bloquear outros eventos na janela principal, até que o usuário o confirme. Esteja ciente da cegueira pop-up, no entanto.
Se for menos que crítico, convém usar uma maneira alternativa de exibir notificações, como uma barra de ferramentas na parte inferior da janela. Você escreveu que exibe notificações no canto inferior direito da tela - a maneira padrão de fazer isso seria usar uma dica de balão com a combinação de um ícone na bandeja do sistema .
Isso funciona bem.
Consulte: 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);
}
Você também pode lidar com isso apenas pela lógica, embora eu deva admitir que as sugestões acima, onde você acaba com um método BringToFront sem realmente roubar o foco, são as mais elegantes.
De qualquer forma, eu me deparei com isso e o resolvi usando uma propriedade DateTime para não permitir mais chamadas BringToFront se as chamadas já tivessem sido feitas recentemente.
Suponha uma classe principal, 'Core', que lida com, por exemplo, três formulários, 'Form1, 2 e 3'. Cada formulário precisa de uma propriedade DateTime e de um evento Activate que chame o Core para trazer janelas para a frente:
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, em seguida, crie o trabalho na Classe Principal:
internal static void BringAllToFront(Form inForm)
{
Form1.BringToFront();
Form2.BringToFront();
Form3.BringToFront();
inForm.Focus();
}
Em uma nota lateral, se você deseja restaurar uma janela minimizada para seu estado original (não maximizado), use:
inForm.WindowState = FormWindowState.Normal;
Novamente, eu sei que essa é apenas uma solução de patch na falta de um BringToFrontWithoutFocus. É uma sugestão para evitar o arquivo DLL.
Não sei se isso é considerado como necro-postagem, mas foi o que fiz porque não consegui fazê-lo funcionar com os métodos "ShowWindow" e "SetWindowPos" do user32. E não, substituir "ShowWithoutActivation" não funciona nesse caso, pois a nova janela deve estar sempre em cima. Enfim, criei um método auxiliar que assume um formulário como parâmetro; quando chamado, mostra o formulário, o traz para a frente e o torna TopMost sem roubar o foco da janela atual (aparentemente, mas o usuário não notará).
[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);
}
}
Eu sei que pode parecer estúpido, mas isso funcionou:
this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
Eu precisava fazer isso com minha janela TopMost. Eu implementei o método PInvoke acima, mas descobri que meu evento Load não estava sendo chamado como Talha acima. Eu finalmente consegui. Talvez isso ajude alguém. Aqui está a minha solução:
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 você cria um novo formulário usando
Form f = new Form();
f.ShowDialog();
rouba o foco porque seu código não pode continuar em execução no formulário principal até que este seja fechado.
A exceção é usar o threading para criar um novo formulário e, em seguida, Form.Show (). Porém, verifique se o thread está visível globalmente, porque se você o declarar em uma função, assim que sua função terminar, seu thread terminará e o formulário desaparecerá.
Descobri-lo: window.WindowState = WindowState.Minimized;
.