Answers:
嗯,仅仅覆盖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;
}
}
form1.Enabled = false
防止偷焦点内对照
WS_EX_NOACTIVATE
和WS_EX_TOOLWINDOW
是0x08000000
和0x00000080
分别。
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方法(第一个代码示例正是您想要的)。
这对我有用。它提供了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 Studio设计器或其他地方省略设置TopMost。
这是从这里偷来的,错误的,借来的(单击替代方法):
这样做似乎很简单,但似乎可行:
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
编辑:请注意,这只是引发了一个已经创建的表单而没有失去焦点。
在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”的属性。
在单独的线程中创建并启动通知表单,并在表单打开后将焦点重设回您的主表单。让通知表单提供一个从该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对象的句柄,以便可以通过主Form(frm.Close()
)以编程方式将其关闭。
缺少一些细节,但是希望这可以使您朝正确的方向前进。
这很好。
请参阅:OpenIcon-MSDN 和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);
}
您也可以单独通过逻辑来处理它,尽管我必须承认,上面的建议在您最终使用BringToFront方法而没有真正失去焦点的情况下才是最优雅的建议。
无论如何,我遇到了这个问题,并通过使用DateTime属性解决了该问题,如果最近才进行了调用,则不允许进一步的BringToFront调用。
假定一个核心类'Core',它处理例如三种形式'Form1、2和3'。每个表单都需要一个DateTime属性和一个Activate事件,该事件调用Core将窗口置于最前面:
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”不起作用,因为新窗口应始终位于顶部。无论如何,我创建了一个以表格为参数的辅助方法。调用时,它将显示表单,将其放到最前面并使其成为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那样被调用。我终于成功了。也许这会帮助某人。这是我的解决方案:
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