检测我的表单何时有焦点

时间:2013-06-25 19:10:41

标签: c# winforms events focus

我正在使用WinForms在具有多种形式的大型应用程序中使用C#。

在几个点上,我有另一个表格作为进度屏幕。因为我无法冻结我的UI线程,所以我必须在新线程中启动新表单。我正在使用progressform.ShowDialog()来启动表单,但由于它位于新主题中,因此可以单击或Alt + Tab返回主表单。我想禁用它。

我的想法是,我可以在mainForm.GotFocus事件上放置一个EventHandler,并将焦点重定向到progressForm(如果显示)。但是,当您切换应用程序或在GotFocusprogressForm之间移动时,不会触发mainForm事件。我猜这是因为mainForm中的某些元素具有焦点,而不是形式本身。

如果有人知道更好的方法(我没有采用EventHandler方法)或者使用EventHandler方法的代码,那么它将解决我的问题。

修改

根据评论,我尝试使用Activated事件。

// in InitializeForm()
this.Activated += FocusHandler;

// outside of InitializeForm()
void FocusHandler(object sender, EventArgs e)
{
    if (ProgressForm != null)
    {
        ProgressForm.Focus();
    }
}

但它仍然允许我点击返回主窗体并单击按钮。

1 个答案:

答案 0 :(得分:0)

我尝试了一些方法,发现这可以按照您的意愿运行,整个想法是在显示进度表时从主UI中过滤一些消息:

public partial class Form1 : Form
{
    [DllImport("user32")]
    private static extern int SetForegroundWindow(IntPtr hwnd);        
    public Form1()
    {
        InitializeComponent();            
    }
    ChildUI child = new ChildUI();
    bool progressShown;
    IntPtr childHandle;
    //I suppose clicking on the button1 on the main ui form will show a progress form.
    private void button1_Click(object sender, EventArgs e)
    {
        if(!progressShown)
           new Thread(() => { progressShown = true; childHandle = child.Handle; child.ShowDialog(); progressShown = false; }).Start();
    }
    protected override void WndProc(ref Message m)
    {
        if (progressShown&&(m.Msg == 0x84||m.Msg == 0xA1||m.Msg == 0xA4||m.Msg == 0xA3||m.Msg == 0x6))  
        //0x84:  WM_NCHITTEST
        //0xA1:  WM_NCLBUTTONDOWN
        //0xA4:  WM_NCRBUTTONDOWN 
        //0xA3   WM_NCLBUTTONDBLCLK   //suppress maximizing ...
        //0x6:   WM_ACTIVATE         //suppress focusing by tab...
        {
            SetForegroundWindow(childHandle);//Bring your progress form to the front
            return;//filter out the messages
        }
        base.WndProc(ref m);
    }
}

如果你想正常显示你的进度表(不是对话框),使用Application.Run(),正常显示表单(使用Show())而不处理某些while循环将在显示后几乎立即终止表单:

private void button1_Click(object sender, EventArgs e)
    {
        //progressShown = true;
        //child.Show();
        if (!progressShown)
        {                
            new Thread(() => {
                progressShown = true;
                if (child == null) child = new ChildUI();
                childHandle = child.Handle;
                Application.Run(child);
                child = null;
                progressShown = false;
            }).Start();
        }
    }

我已经过测试,它就像一个魅力。