WinForms:最顶层窗体在隐藏从其调用的对话框时失去焦点

6rvt4ljy  于 2022-11-17  发布在  其他
关注(0)|答案(2)|浏览(174)

我有一个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中的已知问题吗?如何使主窗体在此构造中不失去焦点?

u91tlkcl

u91tlkcl1#

问题似乎是当单击主窗体时,它触发了WM_WINDOWPOSCHANGING事件。由于子对话框是打开的,因此hwndInsertAfter句柄是子对话框。但是在Dialog_Deactivate中,子对话框是隐藏的,这导致主窗体落在所有其他窗口后面,因为hwndInsertAfter句柄不再是可见窗口。
可能的解决方案是1)在调用Hide()之前将子对话框所有者设置为null,或者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();
    }
}
b1uwtaje

b1uwtaje2#

在隐藏对话框后,尝试在主窗体上调用Activate(),即:

private void Dialog_Deactivate(object sender, EventArgs e)
{
    _dialog.Hide();
    this.Activate();
}

相关问题