我有一個 WinForms 專案,其中有一個主要的最頂層表單,從中顯示了一個非模態對話框。如果它失去輸入焦點,我需要隱藏(而不是關閉)對話框 - 無論是什么原因(用戶單擊主表單,切換到另一個應用程式等)。專案源代碼的以下裸露部分顯示了正在發生的事情:
public partial class MainForm : Form
{
Form _dialog = new Form();
public MainForm()
{
InitializeComponent();
this.TopMost = true;
this.Text = "Main Form";
_dialog.Text = "Dialog";
_dialog.Owner = this;
_dialog.TopMost = true;
_dialog.Deactivate = Dialog_Deactivate;
_dialog.FormClosing = Dialog_FormClosing;
}
private void Dialog_Deactivate(object sender, EventArgs e)
{
_dialog.Hide();
}
private void Dialog_FormClosing(object sender, FormClosingEventArgs e)
{
_dialog.Hide();
e.Cancel = true;
}
private void ButtonShowDialog_Click(object sender, EventArgs e)
{
_dialog.Show();
}
}
我要解決的主要問題如下。如果用戶打開對話框并單擊主表單,如下圖所示

,對話框按預期隱藏,但主表單失去焦點,并且之前處于活動狀態的另一個應用程式在后臺變為活動狀態 - 下一個螢屏截圖中的 Windows 資源管理器:

這是 Windows 或 WinForms 中的已知問題嗎?在這個構建中,如何使主體形式不失重點?
uj5u.com熱心網友回復:
問題似乎是當單擊主表單時,它會觸發一個WM_WINDOWPOSCHANGING事件。由于子對話框是打開的,hwndInsertAfter句柄就是子對話框。但隨后在Dialog_Deactivate子對話框中被隱藏,導致主表單落后于所有其他視窗,因為hwndInsertAfter句柄不再是可見視窗。
可能的解決方案是 1)在呼叫之前將子對話框所有者設定為 nullHide()或 2)使用不同的事件,例如LostFocus,即:
public class MainForm3 : Form {
Form _dialog = null;
public MainForm3() {
this.Text = "Main Formmmmmmmm";
Button btn = new Button { Text = "Show" };
btn.Click = ButtonShowDialog_Click;
this.Controls.Add(btn);
}
bool b = false;
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
if (_dialog != null && _dialog.Visible)
b = true;
if (b)
Debug.WriteLine(m);
int WM_WINDOWPOSCHANGING = 0x46;
if (b && m.Msg == WM_WINDOWPOSCHANGING) {
var wp = Marshal.PtrToStructure<WINDOWPOS>(m.LParam);
Debug.WriteLine("hwnd: " wp.hwnd " " GetWindowText(wp.hwnd));
Debug.WriteLine("hwndInsertAfter: " wp.hwndInsertAfter " " GetWindowText(wp.hwndInsertAfter));
Debug.WriteLine("flags: " wp.flags);
}
}
private void Dialog_Deactivate(object sender, EventArgs e) {
_dialog.Owner = null; // solution 1
_dialog.Hide();
}
private void _dialog_LostFocus(object sender, EventArgs e) { // solution 2
_dialog.Hide();
}
private void Dialog_FormClosing(object sender, FormClosingEventArgs e) {
if (_dialog.Visible) {
_dialog.Hide();
e.Cancel = true;
}
}
private void ButtonShowDialog_Click(object sender, EventArgs e) {
if (_dialog == null) {
_dialog = new Form();
_dialog.Text = "Dialoggggggg";
//_dialog.Deactivate = Dialog_Deactivate;
_dialog.LostFocus = _dialog_LostFocus; // solution 2, use LostFocus instead
_dialog.FormClosing = Dialog_FormClosing;
}
_dialog.Owner = this;
_dialog.Show();
}
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS {
public IntPtr hwnd, hwndInsertAfter;
public int x, y, cx, cy;
public SWP flags;
}
[Flags]
public enum SWP : uint {
SWP_ASYNCWINDOWPOS = 0x4000,
SWP_DEFERERASE = 0x2000,
SWP_DRAWFRAME = 0x0020,
SWP_FRAMECHANGED = 0x0020,
SWP_HIDEWINDOW = 0x0080,
SWP_NOACTIVATE = 0x0010,
SWP_NOCOPYBITS = 0x0100,
SWP_NOMOVE = 0x0002,
SWP_NOOWNERZORDER = 0x0200,
SWP_NOREDRAW = 0x0008,
SWP_NOREPOSITION = 0x0200,
SWP_NOSENDCHANGING = 0x0400,
SWP_NOSIZE = 0x0001,
SWP_NOZORDER = 0x0004,
SWP_SHOWWINDOW = 0x0040
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private static String GetWindowText(IntPtr hWnd) {
StringBuilder sb = new StringBuilder(256);
GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
}
uj5u.com熱心網友回復:
隱藏對話框后嘗試在主表單上呼叫 Activate(),即:
private void Dialog_Deactivate(object sender, EventArgs e)
{
_dialog.Hide();
this.Activate();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/509992.html
標籤:形式表格重点所有者最顶层
下一篇:dataGridView.Sort錯誤System.InvalidOperationException:“DataGridView控制元件必須系結到要排序的IBindingList物件。”
