Відповіді:
Хммм, чи не просто переосмислити Form.ShowWithoutActivation досить?
protected override bool ShowWithoutActivation
{
get { return true; }
}
Якщо ви також не хочете, щоб користувач натискав це вікно сповіщень, ви можете змінити команду 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
щоб внутрішні органи контролю не могли вкрасти фокус
WS_EX_NOACTIVATE
і WS_EX_TOOLWINDOW
є, 0x08000000
і 0x00000080
відповідно.
Викрадений з Pinvoke.net «s ShowWindow методи:
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);
}
(Алекс Лайман відповів на це, я просто розширюю його, безпосередньо вставляючи код. Хтось із правами редагування може скопіювати його там і видалити все, що мені цікаво;))
Якщо ви готові використовувати Win32 P / Invoke , тоді ви можете використовувати метод ShowWindow (перший зразок коду робить саме те, що ви хочете).
Це те, що працювало для мене. Він забезпечує TopMost, але без крадіжки фокусу.
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;
}
}
Не забудьте пропустити налаштування TopMost у дизайнера Visual Studio або в іншому місці.
Це вкрадено, помилково, запозичено звідси (натисніть на Обхідні шляхи):
Робити це, здається, хак, але, здається, працює:
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
Редагувати: Зауважте, це просто піднімає вже створену форму без крадіжки фокусу.
Зразок коду з pinvoke.net у відповідях Алекса Лимана / TheSoftwareJedi зробить вікно "найвищим" вікном, тобто, ви не зможете помістити його за звичайні вікна після того, як воно спливе. Враховуючи опис Матіаса, для чого він хоче це використовувати, це може бути те, що він хоче. Але якщо ви хочете, щоб користувач міг поставити ваше вікно за іншими вікнами після того, як ви його вискочили, просто використовуйте HWND_TOP (0) замість HWND_TOPMOST (-1) у зразку.
У WPF ви можете вирішити це так:
У вікно помістіть ці атрибути:
<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>
Останній атрибут - це той, який вам потрібен ShowActivate = "False".
Створіть та запустіть форму сповіщення в окремому потоці та поверніть фокус назад до основної форми після відкриття форми. Запропонуйте Формі сповіщення надати подію OnFormOpened, яку звільняють від Form.Shown
події. Щось на зразок цього:
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
}
Ви також можете тримати ручку об’єкта NotifcationForm навколо, щоб він міг бути програмно закритий головним Form ( frm.Close()
).
Деякі деталі відсутні, але, сподіваємось, це приведе вас у правильне русло.
Ви можете розглянути, яке саме повідомлення ви хочете відобразити.
Якщо абсолютно важливо повідомити користувачеві про якусь подію, використовуючи Messagebox.Показати рекомендованим способом було б через блокування будь-яких інших подій у головному вікні, поки користувач не підтвердить це. Однак пам’ятайте про спливаючу сліпоту.
Якщо це менш критично, ви можете скористатися альтернативним способом відображення сповіщень, наприклад панелі інструментів у нижній частині вікна. Ви писали, що ви відображаєте сповіщення в правому нижньому куті екрана - стандартним способом зробити це буде використання кульової підказки з комбінацією значка системного лотка .
Це добре працює.
Дивіться: OpenIcon - MSDN та 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);
}
Ви також можете впоратися з цим лише за логікою, хоча я мушу визнати, що наведені вище пропозиції, де ви закінчуєте метод BringToFront без фактичного крадіжки фокусу, є найелегантнішим.
У всякому разі, я зіткнувся з цим і вирішив це, використовуючи властивість DateTime, щоб не дозволяти подальші дзвінки BringToFront, якщо дзвінки були зроблені недавно.
Припустимо базовий клас, 'Core', який обробляє, наприклад, три форми, 'Form1, 2 і 3'. Кожна форма потребує властивості DateTime та події Activate, що викликає Core, щоб вивести вікна на передній план:
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;
}
А потім створіть роботу в Core Class:
internal static void BringAllToFront(Form inForm)
{
Form1.BringToFront();
Form2.BringToFront();
Form3.BringToFront();
inForm.Focus();
}
У бічній примітці, якщо ви хочете відновити мінімізоване вікно до його початкового стану (не максимізованого), використовуйте:
inForm.WindowState = FormWindowState.Normal;
Знову ж таки, я знаю, що це лише патч-рішення у відсутності BringToFrontWithoutFocus. Це означає, як пропозиція, якщо ви хочете уникнути файлу DLL.
Я не знаю, чи розглядають це як некро-опублікування, але це те, що я робив з тих пір, як я не можу це працювати з методами "ShowWindow" та "SetWindowPos" user32. І ні, переорієнтування "ShowWithoutActivation" не працює в цьому випадку, оскільки нове вікно має бути завжди вгорі. У будь-якому випадку я створив хелперний метод, який приймає форму як параметр; коли дзвонить, він показує форму, виводить її на передню частину і робить її TopMost, не крадучи фокус поточного вікна (мабуть, так, але користувач цього не помітить).
[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);
}
}
Я знаю, що це може здатися дурним, але це спрацювало:
this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
Мені потрібно було це зробити зі своїм вікном TopMost. Я реалізував вищевказаний метод PInvoke, але виявив, що моя подія Load не називається вище, як Talha. Нарешті мені це вдалося. Можливо, це комусь допоможе. Ось моє рішення:
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
Коли ви створюєте нову форму, використовуючи
Form f = new Form();
f.ShowDialog();
він краде фокус, оскільки ваш код не може продовжувати виконувати основну форму, поки ця форма не буде закрита.
Виняток - використання нитки для створення нової форми, а потім Form.Show (). Переконайтеся, що нитка є всесвітньо видимою, тому що якщо ви оголосите її в межах функції, як тільки ваша функція завершиться, ваш потік закінчиться і форма зникне.
Фігурне це: window.WindowState = WindowState.Minimized;
.