[英]Show a Form behind everything else, and without stealing focus?
StackOverflow上存在一個關於如何在不竊取焦點的情況下顯示表單的問題。 答案是覆蓋ShowWithoutActivation
並返回true:
protected override bool ShowWithoutActivation
{
get { return true; }
}
這很好用。
現在我想更進一步。 我希望展示一個表格(即使其可見),但讓它在z順序中的其他表格后面 。
可能在.net?
如果沒有,可以使用P / Invoke嗎?
調用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
。 按照編譯器的要求修復它...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.