Jawaban:
Hmmm, bukankah hanya mengungguli Form.ShowWithoutActivation cukup?
protected override bool ShowWithoutActivation
{
get { return true; }
}
Dan jika Anda tidak ingin pengguna mengklik jendela pemberitahuan ini juga, Anda dapat mengesampingkan 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
untuk mencegah kontrol dalam mencuri fokus
WS_EX_NOACTIVATE
dan WS_EX_TOOLWINDOW
adalah 0x08000000
dan 0x00000080
masing - masing.
Dicuri dari PInvoke.net 's ShowWindow metode:
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 menjawab ini, saya hanya mengembangkannya dengan langsung menempelkan kode. Seseorang dengan hak edit dapat menyalinnya di sana dan menghapus ini untuk semua yang saya pedulikan;))
Jika Anda ingin menggunakan Win32 P / Invoke , maka Anda dapat menggunakan metode ShowWindow (sampel kode pertama melakukan apa yang Anda inginkan).
Inilah yang bekerja untuk saya. Ini memberikan TopMost tetapi tanpa mencuri fokus.
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;
}
}
Ingatlah untuk menghilangkan pengaturan TopMost di perancang Visual Studio, atau di tempat lain.
Ini dicuri, salah, dipinjam, dari sini (klik Workarounds):
Melakukan ini tampaknya seperti peretasan, tetapi tampaknya berhasil:
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
Sunting: Catatan, ini hanya memunculkan formulir yang sudah dibuat tanpa mencuri fokus.
Kode sampel dari pinvoke.net pada jawaban Alex Lyman / TheSoftwareJedi akan menjadikan jendela tersebut sebagai jendela "paling atas", artinya Anda tidak dapat meletakkannya di belakang jendela normal setelah muncul. Mengingat deskripsi Matias tentang apa yang dia ingin gunakan untuk ini, itu bisa menjadi apa yang dia inginkan. Tetapi jika Anda ingin pengguna dapat menempatkan jendela Anda di belakang jendela lain setelah Anda muncul, cukup gunakan HWND_TOP (0) alih-alih HWND_TOPMOST (-1) dalam sampel.
Di WPF Anda dapat menyelesaikannya seperti ini:
Di jendela letakkan atribut ini:
<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>
Atribut yang terakhir adalah yang Anda butuhkan ShowActivated = "False".
Buat dan mulai Formulir pemberitahuan di utas terpisah dan setel ulang fokus kembali ke formulir utama Anda setelah Formulir dibuka. Minta Formulir pemberitahuan menyediakan acara OnFormOpened yang dipecat dari Form.Shown
acara tersebut. Sesuatu seperti ini:
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
}
Anda juga bisa menjaga pegangan ke objek NotifcationForm Anda di sekitar sehingga bisa ditutup secara terprogram oleh Formulir utama ( frm.Close()
).
Beberapa detail hilang, tetapi mudah-mudahan ini akan membuat Anda pergi ke arah yang benar.
Anda mungkin ingin mempertimbangkan jenis pemberitahuan apa yang ingin Anda tampilkan.
Jika benar-benar penting untuk memberi tahu pengguna tentang suatu peristiwa, menggunakan Messagebox. Pertunjukan akan menjadi cara yang disarankan, karena sifatnya untuk memblokir acara lain ke jendela utama, hingga pengguna mengonfirmasinya. Waspadai kebutaan pop-up.
Jika kurang dari kritis, Anda mungkin ingin menggunakan cara alternatif untuk menampilkan pemberitahuan, seperti bilah alat di bagian bawah jendela. Anda menulis, bahwa Anda menampilkan pemberitahuan di kanan bawah layar - cara standar untuk melakukan ini adalah menggunakan ujung balon dengan kombinasi ikon baki sistem .
Ini bekerja dengan baik.
Lihat: OpenIcon - MSDN dan 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);
}
Anda dapat mengatasinya hanya dengan logika saja, walaupun saya harus mengakui bahwa saran di atas di mana Anda berakhir dengan metode BringToFront tanpa benar-benar mencuri fokus adalah yang paling elegan.
Bagaimanapun, saya mengalami ini dan menyelesaikannya dengan menggunakan properti DateTime untuk tidak memungkinkan panggilan BringToFront lebih lanjut jika panggilan sudah dilakukan baru-baru ini.
Asumsikan kelas inti, 'Inti', yang menangani misalnya tiga bentuk, 'Form1, 2, dan 3'. Setiap formulir membutuhkan properti DateTime dan acara Activate yang memanggil Core untuk membawa windows ke depan:
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;
}
Dan kemudian buat karya di Kelas Inti:
internal static void BringAllToFront(Form inForm)
{
Form1.BringToFront();
Form2.BringToFront();
Form3.BringToFront();
inForm.Focus();
}
Sebagai catatan, jika Anda ingin mengembalikan jendela yang diperkecil ke keadaan semula (tidak dimaksimalkan), gunakan:
inForm.WindowState = FormWindowState.Normal;
Sekali lagi, saya tahu ini hanyalah solusi patch karena kurangnya BringToFrontWithoutFocus. Ini dimaksudkan sebagai saran jika Anda ingin menghindari file DLL.
Saya tidak tahu apakah ini dianggap sebagai posting necro, tapi ini yang saya lakukan karena saya tidak bisa menggunakannya dengan metode "ShowWindow" dan "SetWindowPos" user32. Dan tidak, mengganti "ShowWithoutActivation" tidak berfungsi dalam kasus ini karena jendela baru harus selalu di atas. Lagi pula, saya membuat metode pembantu yang mengambil formulir sebagai parameter; ketika dipanggil, ia menunjukkan formulir, membawanya ke depan dan membuatnya TopMost tanpa mencuri fokus jendela saat ini (tampaknya memang demikian, tetapi pengguna tidak akan memperhatikan).
[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);
}
}
Saya tahu ini terdengar bodoh, tetapi ini berhasil:
this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
Saya perlu melakukan ini dengan jendela saya TopMost. Saya menerapkan metode PInvoke di atas tetapi menemukan bahwa acara Load saya tidak dipanggil seperti Talha di atas. Saya akhirnya berhasil. Mungkin ini akan membantu seseorang. Ini solusinya:
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
Saat Anda membuat formulir baru menggunakan
Form f = new Form();
f.ShowDialog();
itu mencuri fokus karena kode Anda tidak dapat melanjutkan mengeksekusi pada formulir utama sampai formulir ini ditutup.
Pengecualian adalah dengan menggunakan threading untuk membuat formulir baru lalu Form.Show (). Pastikan utas tersebut terlihat secara global, karena jika Anda mendeklarasikannya dalam suatu fungsi, segera setelah fungsi Anda keluar, utas Anda akan berakhir dan formulir itu akan hilang.
Figured it out: window.WindowState = WindowState.Minimized;
.