在其他一切背后展示一张表格,而不是偷不懂焦点?

时间:2012-02-17 20:30:49

标签: c# .net winforms

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

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

这很好用。

现在我想更进一步。我想要一个表格一个表格(即让它可见),但它是后面的其他表格。

可能在.net?

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

Bonus Chatter

调用SendToBack()不起作用:

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

3 个答案:

答案 0 :(得分:6)

使用SetWindowPos function

的一点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);
}

答案 1 :(得分:0)

这应该可以解决问题:

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

答案 2 :(得分:0)

要添加到the viable solution Lars provided,您还可以阻止用户完全更改窗口的Z顺序。

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

因此,在这种情况下,您需要设置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没有在进行函数调用时到处应该正确插入。按照编译器的要求修复它......