在其他所有内容后面显示一个表格,而不会窃取焦点?

StackOverflow上存在一个关于如何在不窃取焦点的情况下显示表单的问题。 答案是覆盖ShowWithoutActivation并返回true:

 protected override bool ShowWithoutActivation { get { return true; } } 

这很好用。

现在我想更进一步。 我希望展示一个表格(即使其可见),但让它落后于z顺序中的其他表格。

可能在.net?

如果没有,可以使用P / Invoke吗?

奖金Chatter

调用SendToBack()不起作用:

  RunnerForm frm = new RunnerForm(); // frm.Show(); frm.Visible = true; frm.SendToBack(); 

使用SetWindowPos函数的一点PInvoke

 public static class HWND { public static readonly IntPtr NOTOPMOST = new IntPtr(-2), BROADCAST = new IntPtr(0xffff), TOPMOST = new IntPtr(-1), TOP = new IntPtr(0), BOTTOM = new IntPtr(1); } public static class SWP { public static readonly int NOSIZE = 0x0001, NOMOVE = 0x0002, NOZORDER = 0x0004, NOREDRAW = 0x0008, NOACTIVATE = 0x0010, DRAWFRAME = 0x0020, FRAMECHANGED = 0x0020, SHOWWINDOW = 0x0040, HIDEWINDOW = 0x0080, NOCOPYBITS = 0x0100, NOOWNERZORDER = 0x0200, NOREPOSITION = 0x0200, NOSENDCHANGING = 0x0400, DEFERERASE = 0x2000, ASYNCWINDOWPOS = 0x4000; } [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags); private void button1_Click(object sender, EventArgs e) { RunnerForm frm = new RunnerForm(); SetWindowPos(frm.Handle, HWND.BOTTOM, 0, 0, 0, 0, SWP.SHOWWINDOW | SWP.NOMOVE | SWP.NOOWNERZORDER | SWP.NOSIZE | SWP.NOACTIVATE); } 

这应该是诀窍:

 RunnerForm frm = new RunnerForm(); myMainForm.Owner = frm; 

要添加Lars提供的可行解决方案 ,您还可以防止用户完全更改窗口的Z顺序。

为此,您将覆盖窗体的WndProc方法,并捕获在其大小,位置或Z顺序位置即将更改时发送到窗口的WM_WINDOWPOSCHANGING消息 。 关于这条消息的超酷事 – 我认为这是我的最爱之一 – 它实际上允许你改变或修改即将发生的变化的参数。

因此,在这种情况下,您需要设置SWP_NOZORDER标志以防止更改窗口的Z顺序。

关于这种方法的值得注意的是,它始终会在您离开它的最后位置保持Z顺序的窗口。 用户将无法将其带到前面,这可能是也可能不是好事,具体取决于UI的设计方式。 除了表单之外,它还可以正常使用控件。

从我的一个库中提取示例代码:

 internal class NativeMethods { public const int WM_WINDOWPOSCHANGING = 0x46; public const int WM_WINDOWPOSCHANGED = 0x47; [Flags()] public enum SetWindowPosFlags { SWP_NOSIZE = 0x1, SWP_NOMOVE = 0x2, SWP_NOZORDER = 0x4, SWP_NOREDRAW = 0x8, SWP_NOACTIVATE = 0x10, SWP_FRAMECHANGED = 0x20, SWP_DRAWFRAME = SWP_FRAMECHANGED, SWP_SHOWWINDOW = 0x40, SWP_HIDEWINDOW = 0x80, SWP_NOCOPYBITS = 0x100, SWP_NOOWNERZORDER = 0x200, SWP_NOREPOSITION = SWP_NOOWNERZORDER, SWP_NOSENDCHANGING = 0x400, SWP_DEFERERASE = 0x2000, SWP_ASYNCWINDOWPOS = 0x4000, } public enum WindowZOrder { HWND_TOP = 0, HWND_BOTTOM = 1, HWND_TOPMOST = -1, HWND_NOTOPMOST = -2, } [StructLayout(LayoutKind.Sequential)] public struct WINDOWPOS { public IntPtr hWnd; public IntPtr hwndInsertAfter; public int x; public int y; public int cx; public int cy; public SetWindowPosFlags flags; // Returns the WINDOWPOS structure pointed to by the lParam parameter // of a WM_WINDOWPOSCHANGING or WM_WINDOWPOSCHANGED message. public static WINDOWPOS FromMessage(Message msg) { // Marshal the lParam parameter to an WINDOWPOS structure, // and return the new structure return (WINDOWPOS)Marshal.PtrToStructure(msg.LParam, typeof(WINDOWPOS)); } // Replaces the original WINDOWPOS structure pointed to by the lParam // parameter of a WM_WINDOWPOSCHANGING or WM_WINDOWPSCHANGING message // with this one, so that the native window will be able to see any // changes that we have made to its values. public void UpdateMessage(Message msg) { // Marshal this updated structure back to lParam so the native // window can respond to our changes. // The old structure that it points to should be deleted, too. Marshal.StructureToPtr(this, msg.LParam, true); } } } 

然后我有一个光滑的小子类表单,它引发对应于这些消息的.NET事件,并允许事件处理程序修改值或取消事件(如果需要)。 我不处理SWP_NOZORDER ,但你可以知道它是如何工作的。

 public class FormEx : System.Windows.Forms.Form { // ...snip constructors and such protected override void WndProc(ref Message m) { switch (m.Msg) { case NativeMethods.WM_WINDOWPOSCHANGING: this.WmWindowPosChanging(m); return; // ...snip } base.WndProc(m); } private void WmWindowPosChanging(ref Message m) { // Extract the WINDOWPOS structure corresponding to this message NativeMethods.WINDOWPOS wndPos = NativeMethods.WINDOWPOS.FromMessage(m); // Determine if the size is changing (absence of SWP_NOSIZE flag) if (!((wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOSIZE) == NativeMethods.SetWindowPosFlags.SWP_NOSIZE)) { // Raise the LowLevelSizeChanging event SizeChangingEventArgs e = new SizeChangingEventArgs(this.Size, new Size(wndPos.cx, wndPos.cy)); this.OnLowLevelSizeChanging(e); // Determine if the user canceled the size changing event if (e.Cancel) { // If so, add the SWP_NOSIZE flag wndPos.flags = wndPos.flags | NativeMethods.SetWindowPosFlags.SWP_NOSIZE; wndPos.UpdateMessage(m); } } // Determine if the position is changing (absence of SWP_NOMOVE flag) if (!((wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOMOVE) == NativeMethods.SetWindowPosFlags.SWP_NOMOVE)) { // Raise the LowLevelPositionChanging event PositionChangingEventArgs e = new PositionChangingEventArgs(this.Location, new Point(wndPos.x, wndPos.y)); this.OnLowLevelPositionChanging(e); // Determine if the user canceled the position changing event if (e.Cancel) { // If so, add the SWP_NOMOVE flag wndPos.flags = wndPos.flags | NativeMethods.SetWindowPosFlags.SWP_NOMOVE; wndPos.UpdateMessage(m); } } base.WndProc(m); } // ...snip event infrastructure } 

编辑:嗯,这段代码最初是用VB.NET编写的,我是通过自动翻译器运行的。 在进行函数调用时,看起来ref没有正确地插入它们应该是的任何地方。 按照编译器的要求修复它…