显示表单而不偷窃重点?

我正在使用一个窗体来显示通知(它出现在屏幕的右下angular),但是当我显示这个窗体时,它从主窗体中窃取了焦点。 有没有一种方法来显示这个“通知”forms而不偷窃?

嗯,是不是简单地重写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; } } 

从PInvoke.net的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); } 

(Alex Lyman回答说,我只是直接粘贴代码来扩展它,具有编辑权限的人可以在那里复制它,并删除所有我关心的内容)

如果您愿意使用Win32 P / Invoke ,那么您可以使用ShowWindow方法(第一个代码示例完全按照您的需要)。

这样做似乎是一个黑客,但似乎工作:

 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 

编辑:请注意,这只是提出一个已经创build的forms,没有偷窃的重点。

在Alex Lyman / TheSoftwareJedi的答案中,来自pinvoke.net的示例代码将使窗口成为“最顶层”窗口,这意味着在popup窗口后不能将其放在正常窗口后面。 鉴于马蒂亚斯的描述,他想用这个,这可能是他想要的。 但是如果你希望用户能够在popup窗口之后把你的窗口放在其他窗口之后,只需要使用HWND_TOP(0)而不是HWND_TOPMOST(-1)。

这是为我工作。 它提供了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; } } 

请记住省略在Visual Studiodevise器或其他地方设置TopMost。

这是从这里偷走,错误,借用(点击解决办法):

https://connect.microsoft.com/VisualStudio/feedback/details/401311/showwithoutactivation-is-not-supported-with-topmost

在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”。

在单独的线程中创build并启动通知窗体,并在窗体打开后将焦点重置回主窗体。 让通知窗体提供从Form.Shown事件触发的OnFormOpened事件。 像这样的东西:

 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() )以编程方式closures。

一些细节不见了,但希望这会让你朝着正确的方向前进。

您可能想要考虑要显示的通知types。

如果让用户知道某个事件是非常重要的,那么使用Messagebox.Show将是推荐的方法,因为它的本质是阻止任何其他事件到主窗口,直到用户确认它为止。 不过,要注意popup式失明。

如果它不是关键性的,可能需要使用另一种方式来显示通知,例如窗口底部的工具栏。 你写道,你在屏幕的右下angular显示通知 – 标准的做法是使用气球提示和系统托盘图标的组合。

我有类似的东西,我只是显示通知表单,然后做

 this.Focus(); 

把重点放在主要forms上。

这很好:

 [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. } 

也可以单独使用逻辑处理它,尽pipe我不得不承认,上面提到的BringToFront方法没有实际偷取焦点的build议是最优雅的。

无论如何,我遇到了这个问题,并通过使用DateTime属性来解决它,如果最近已经进行了调用,则不允许进一步的BringToFront调用。

假设一个核心类,“核心”,它处理例如三种forms,“Form1,2和3”。 每个表单都需要一个DateTime属性和一个调用Core的Activate事件来将窗口放在前面:

 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类中创build工作:

 internal static void BringAllToFront(Form inForm) { Form1.BringToFront(); Form2.BringToFront(); Form3.BringToFront(); inForm.Focus(); } 

在附注中,如果您想要将最小化窗口恢复到原始状态(未最大化),请使用:

 inForm.WindowState = FormWindowState.Normal; 

再次,我知道这只是缺lessBringToFrontWithoutFocus的补丁解决scheme。 这意味着如果你想避免DLL文件的build议。

我不知道这是否被认为是necro-posting,但这是我做了什么,因为我没有得到它与user32的“ShowWindow”和“SetWindowPos”方法的工作。 不,重写“ShowWithoutActivation”在这种情况下不起作用,因为新窗口应该始终在最上面。 无论如何,我创build了一个帮助器方法,以表单作为参数; 当被调用时,它显示窗体,把它带到前面,并使其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那样被调用。 我终于成功了。 也许这会帮助别人。 这是我的解决scheme:

  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 

如果第一个表单失去焦点的时间less于1秒无关紧要,你可以试试这个。

 private void Form2_Load(object sender, EventArgs e) { Form1 f1 = new Form1(); f1.focus(); } 

所以当form2显示时,它将立即关注form1。

当您使用创build一个新的表单

 Form f = new Form(); f.ShowDialog(); 

它窃取焦点,因为直到这个表单被closures,你的代码才能继续在主窗体上执行。

例外是通过使用线程来创build一个新的窗体,然后Form.Show()。 确保线程是全局可见的,因为如果你在一个函数中声明它,只要你的函数退出,你的线程就会结束,窗体就会消失。

想通了: window.WindowState = WindowState.Minimized;