显示表单而不偷窃重点?
我正在使用一个窗体来显示通知(它出现在屏幕的右下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。
这是从这里偷走,错误,借用(点击解决办法):
在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;
。