17 ответов:
Хммм, это не просто переопределение формы.Достаточно 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; } }
украдено у 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); }(Алекс Лайман ответил на это, я просто расширяю его, непосредственно вставляя код. Кто-то с правами редактирования может скопировать его туда и удалить это для всех меня волнует ;) )
Если вы используете Win32P / Invoke, вы можете использовать ShowWindow Метод (первый пример кода делает именно то, что вы хотите).
Это то, что работал для меня. Он обеспечивает самый верхний, но без кражи фокуса.
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; } }Не забудьте опустить параметр самый верхний в Visual Studio designer или в другом месте.
это украдено, err, заимствовано, отсюда (нажмите на обходные пути):
делать это похоже на хак, но это, кажется, работает:
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 topEdit: Примечание, это просто поднимает уже созданную форму без кражи фокуса.
пример кода из pinvoke.net в ответах Alex Lyman / 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>последний атрибут-это тот, который вам нужен ShowActivated= "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, чтобы он мог быть программно закрыт основной формой (
frm.Close()).некоторые детали отсутствуют, но, надеюсь, это поможет вам в правильное направление.
вы можете рассмотреть, какие уведомления вы хотели бы отобразить.
Если это абсолютно важно, чтобы пользователь знал о каком-либо событии, используя Messagebox.Показать было бы рекомендуемым способом, из-за его природы, чтобы блокировать любые другие события в главном окне, пока пользователь не подтвердит это. Однако помните о всплывающей слепоте.
Если это менее критично, вы можете использовать альтернативный способ отображения уведомлений, например панель инструментов на панели управления. нижней части окна. Вы написали, что вы отображаете уведомления в нижней правой части экрана-стандартный способ сделать это будет использовать воздушный шар наконечником с комбинацией a трее.
У меня есть что-то подобное, и я просто показываю форму уведомления, а затем делаю
this.Focus();чтобы вернуть фокус на основную форму.
Это хорошо работает:
[System.Runtime.InteropServices.DllImport("user32")] public static extern long OpenIcon(long hwnd); [System.Runtime.InteropServices.DllImport("user32")] public static extern long SetForegroundWindow(long hwnd); public static void ActivateInstance() { long MyHndl = 0; long result = 0; Process objProcess = Process.GetCurrentProcess(); MyHndl = objProcess.MainWindowHandle.ToInt32(); result = OpenIcon(MyHndl); // Restore the program. result = SetForegroundWindow(MyHndl); // Activate the application. //System.Environment.Exit(0); // End the current instance of the application. }
вы можете обрабатывать его только логикой тоже, хотя я должен признать, что предложения выше, где вы в конечном итоге с BringToFront метод без фактического кражи фокуса является наиболее элегантным.
во всяком случае, я столкнулся с этим и решил его с помощью свойства DateTime, чтобы не разрешать дальнейшие вызовы BringToFront, если вызовы были сделаны уже недавно.
предположим, что основной класс, 'Core', который обрабатывает, например, три формы,'Form1, 2 и 3'. Каждая форма нуждается свойство DateTime и событие Activate, которое вызывает Core для вывода 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; }а затем создать работу в основном классе:
internal static void BringAllToFront(Form inForm) { Form1.BringToFront(); Form2.BringToFront(); Form3.BringToFront(); inForm.Focus(); }на боковой ноте, если вы хотите восстановить свернутое окно в исходное состояние (не развернутое), используйте:
inForm.WindowState = FormWindowState.Normal;опять же, я знаю, что это просто патч решение в отсутствие BringToFrontWithoutFocus. Это подразумевается как предложение, если вы хотите избежать DLL-файла.
Я не знаю, считается ли это некро-проводкой, но это то, что я сделал, так как я не мог заставить его работать с методами user32 "ShowWindow" и "SetWindowPos". И нет, переопределение "ShowWithoutActivation" не работает в этом случае, так как новое окно должно быть всегда сверху. В любом случае, я создал вспомогательный метод, который принимает форму в качестве параметра; при вызове он показывает форму, выводит ее на передний план и делает ее самой верхней, не крадя фокус текущего окна (по-видимому, это так, но пользователь не заметит).
[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();
Мне нужно было сделать это с моим окном сверху. Я реализовал метод 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();он крадет фокус, потому что ваш код не может продолжать выполнение в основной форме, пока эта форма не будет закрыта.
исключение заключается в использовании потоков для создания новой формы, а затем формы.Шоу.)( Убедитесь, что поток глобально виден, потому что если вы объявите его в функции, как только ваша функция выйдет, ваш поток закончится, и форма исчезнет.
Comments