Odpowiedzi:
Hmmm, czy nie wystarczy po prostu nadpisać Form.ShowBoyoutActivation?
protected override bool ShowWithoutActivation
{
get { return true; }
}
A jeśli nie chcesz, aby użytkownik klikał również to okno powiadomienia, możesz nadpisać 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
aby wewnętrzne sterowanie nie kradło ostrości
WS_EX_NOACTIVATE
i WS_EX_TOOLWINDOW
są odpowiednio 0x08000000
i 0x00000080
.
Skradzione z PInvoke.net jest ShowWindow metodą:
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 odpowiedział na to pytanie, po prostu rozszerzam go, bezpośrednio wklejając kod. Ktoś z prawami do edycji może go tam skopiować i usunąć to, co mnie interesuje;))
Jeśli chcesz użyć Win32 P / Invoke , możesz użyć metody ShowWindow (pierwszy przykład kodu robi dokładnie to, co chcesz).
To właśnie zadziałało dla mnie. Zapewnia TopMost, ale bez kradzieży ostrości.
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;
}
}
Pamiętaj, aby pominąć ustawienie TopMost w programie Visual Studio Designer lub w innym miejscu.
To jest skradzione, błędne, pożyczone, stąd (kliknij Obejście):
Wydaje się, że to hack, ale wydaje się działać:
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
Edycja: Uwaga, to po prostu podnosi już utworzony formularz bez kradzieży ostrości.
Przykładowy kod z pinvoke.net w odpowiedziach Alexa Lymana / TheSoftwareJedi sprawi, że okno będzie oknem „najwyższym”, co oznacza, że nie można go umieścić za zwykłymi oknami po tym, jak się pojawi. Biorąc pod uwagę opis Matiasa, do czego chce tego użyć, może to być to, czego chce. Ale jeśli chcesz, aby użytkownik mógł umieścić twoje okno za innymi oknami po tym, jak je wyskoczyłeś, po prostu użyj HWND_TOP (0) zamiast HWND_TOPMOST (-1) w przykładzie.
W WPF można to rozwiązać w następujący sposób:
W oknie umieść te atrybuty:
<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>
Ostatni atrybut to ten, którego potrzebujesz ShowActivated = "False".
Utwórz i uruchom formularz powiadomienia w osobnym wątku i zresetuj fokus z powrotem do formularza głównego po otwarciu formularza. Poproś formularz powiadomienia o dostarczenie zdarzenia OnFormOpened, które jest uruchamiane ze Form.Shown
zdarzenia. Coś takiego:
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
}
Możesz również zachować uchwyt do obiektu NotifcationForm, aby mógł być programowo zamknięty przez główny formularz Form (frm.Close()
).
Brakuje niektórych szczegółów, ale miejmy nadzieję, że poprowadzi Cię to we właściwym kierunku.
Możesz zastanowić się, jakiego rodzaju powiadomienie chcesz wyświetlić.
Jeśli jest absolutnie krytyczne, aby poinformować użytkownika o jakimś zdarzeniu, zaleca się użycie Messagebox.Show, ze względu na jego naturę, aby zablokować wszelkie inne zdarzenia w oknie głównym, dopóki użytkownik tego nie potwierdzi. Uważaj jednak na wyskakującą ślepotę.
Jeśli jest to mniej niż krytyczne, możesz chcieć użyć alternatywnego sposobu wyświetlania powiadomień, na przykład paska narzędzi u dołu okna. Napisałeś, że wyświetlasz powiadomienia w prawym dolnym rogu ekranu - standardowym sposobem byłoby użycie końcówki dymku z kombinacją ikony zasobnika systemowego .
To działa dobrze.
Zobacz: OpenIcon - MSDN i 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);
}
Państwo może obsługiwać go za pomocą logiki sam też, chociaż muszę przyznać, że powyższe sugestie, gdzie kończy się z metodą BringToFront bez faktycznie kradzież ostrość jest najbardziej elegancki jeden.
W każdym razie natknąłem się na to i rozwiązałem to, używając właściwości DateTime, aby nie zezwalać na dalsze wywołania BringToFront, jeśli połączenia były wykonywane już niedawno.
Załóżmy podstawową klasę „Core”, która obsługuje na przykład trzy formularze „Form1, 2 i 3”. Każdy formularz wymaga właściwości DateTime i zdarzenia Activate, które wywołuje Core w celu przeniesienia okien na wierzch:
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;
}
A następnie stwórz pracę w Core Class:
internal static void BringAllToFront(Form inForm)
{
Form1.BringToFront();
Form2.BringToFront();
Form3.BringToFront();
inForm.Focus();
}
Na marginesie, jeśli chcesz przywrócić zminimalizowane okno do jego pierwotnego stanu (nie zmaksymalizowane), użyj:
inForm.WindowState = FormWindowState.Normal;
Ponownie, wiem, że to tylko łatka bez BringToFrontWithoutFocus. Jest to sugestia, jeśli chcesz uniknąć pliku DLL.
Nie wiem, czy jest to uważane za nekro-wysyłanie, ale właśnie to zrobiłem, ponieważ nie mogę go uruchomić z metodami „ShowWindow” i „SetWindowPos” użytkownika 32. I nie, nadpisywanie „ShowWithoutActivation” nie działa w tym przypadku, ponieważ nowe okno powinno być zawsze na wierzchu. W każdym razie stworzyłem metodę pomocniczą, która przyjmuje postać jako parametr; po wywołaniu pokazuje formularz, przenosi go na wierzch i sprawia, że jest to TopMost bez kradzieży fokusu bieżącego okna (najwyraźniej tak, ale użytkownik tego nie zauważy).
[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);
}
}
Wiem, że to może brzmieć głupio, ale to zadziałało:
this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
Musiałem to zrobić z moim oknem TopMost. Zaimplementowałem powyższą metodę PInvoke, ale stwierdziłem, że moje zdarzenie Load nie jest wywoływane jak powyżej Talha. W końcu mi się udało. Może to komuś pomoże. Oto moje rozwiązanie:
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
Podczas tworzenia nowego formularza za pomocą
Form f = new Form();
f.ShowDialog();
kradnie fokus, ponieważ Twój kod nie może kontynuować wykonywania w głównym formularzu, dopóki ten formularz nie zostanie zamknięty.
Wyjątkiem jest użycie wątków do utworzenia nowego formularza, a następnie Form.Show (). Upewnij się jednak, że wątek jest widoczny globalnie, ponieważ jeśli zadeklarujesz go w funkcji, zaraz po zakończeniu funkcji wątek zakończy się, a formularz zniknie.
Zorientowaliśmy się: window.WindowState = WindowState.Minimized;
.