Окно уведомления – предотrotation фокуса windows

У меня возникли проблемы с получением windows уведомлений, чтобы корректно вести себя в c #. В основном я показываю безграничную форму в нижней правой части экрана, которая отображает сообщение в течение нескольких секунд, а затем исчезает. Проблема в том, что мне нужно, чтобы он появлялся поверх других окон, не имея возможности воровать фокус. В идеале я хочу, чтобы это был чисто управляемый код, хотя, просматривая похожие примеры, я сомневаюсь, что это будет возможно.

В настоящий момент я мешаю ему воровать фокус при вызове Form.Show () с переопределением:

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

а затем игнорируя щелчки мыши с помощью:

  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); } 

Однако я нахожу, что если я использую их в сочетании с TopMost = true (что мне нужно), он все равно получает фокус, и если все остальные windows сведены к минимуму, он также получает фокус.

Таким образом, существует ли какой-либо способ избавиться от препятствия, чтобы форма из когда-либо набирала фокус (будь то с помощью щелчка мыши, alt-tab и т. Д.), Хотя она все еще является верхней частью самой лучшей / второй верхней формы? Даже просто отдав внимание сразу к окну, которое он украл, он будет работать (хотя и вводит мерцание).

Любые предложения были бы очень благодарны, я действительно застрял в этом.

РЕДАКТИРОВАТЬ:

Хорошо, поэтому мне, наконец, удалось получить эту работу, используя:

 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); } } } 

Я также добавил Form.Hide () в событие GotFocus, чтобы, даже если он каким-то образом фокусировался, он просто закрывается и выходит из пользовательского пути как можно скорее.

Кроме того, если кому-то интересно, константы для всех оконных стилей и т. Д. Можно найти в WINUSER.H, в Интернете по адресу http://www.woodmann.com/fravia/sources/WINUSER.H, если вы не можете найти Это.

Однако, если кто-то может увидеть более элегантный способ сделать это, это будет оценено.

В WPF попробуйте следующее:

 ShowActivated="False" 

Возможно, WS_EX_NOACTIVATE расширенный стиль windows – это то, что вы ищете. Окно с этим стилем не активируется при нажатии. Например, окно виртуальной клавиатуры имеет этот стиль.

Чтобы применить этот стиль к окну, переопределите функцию CreateParams и измените baseParams.ExStyle.

Я не ищу здесь точек, потому что исходный плакат уже опубликовал решение, которое сработало для них, но я хотел поделиться своим опытом с этой проблемой. Используя вышеприведенное решение (которое находится в нижней части вопроса, а не в форме ответа) дает мне Win32Exception: Error creating window handle error. при использовании кода WndProc поскольку он отправлен там. Часть ShowWithoutActivation и CreateParams работает, чтобы предотвратить активацию формы и сохранить ее сверху.

Я придумал альтернативное решение для предотвращения нажатия формы с помощью SetWindowLong что делает форму прозрачной и, следовательно, ее можно щелкнуть, и SetLayeredWindowAttributes которая устанавливает прозрачность обратно в нормальное состояние, чтобы вы могли снова увидеть форму, но при этом сохраняете возможность щелкните по форме.

ПРИМЕЧАНИЕ. Вы -CANNOT- взаимодействуете с формой вообще в этом состоянии, и даже нажатие кнопки «X» просто щелкнет все, что находится за формой в этой позиции, поэтому вам нужно будет использовать код для закрытия формы:

 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); } } 

Я также смог получить оригинальный подход, сделав небольшое изменение кода WndProc выше.

ПРИМЕЧАНИЕ. Это также делает форму непривлекательной, но поведение отличается тем, что вы можете нажимать кнопки min, max и ‘X’, но ничего не происходит, когда вы делаете. Курсор мыши также изменяется, когда вы находитесь на краю формы, как будто для изменения размера, но не позволяет изменять размер:

 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; } }