【问题标题】:Detecting when my form has focus检测我的表单何时具有焦点
【发布时间】:2013-06-22 17:40:35
【问题描述】:

我在一个包含多个表单的大型应用程序中使用 C# 和 WinForms。

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

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

如果有人知道更好的方法(我不致力于 EventHandler 方法)或 EventHandler 方法的工作代码,它将解决我的问题。

编辑

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

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

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

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

【问题讨论】:

  • 使用两个 UI 线程是解决各种问题的秘诀。不要那样做。
  • 不幸的是,我将在项目结束时帮助结束它。双 UI 线程现在已在系统中根深蒂固。把它拿出来会比它的价值更麻烦。
  • 你试过Form.Activate方法和Form.Activated事件吗?
  • 我现在正在调查。这似乎可行。
  • 简单的方法是将表单的 Enable 属性设置为 false,这样就无法激活它。检查this answer,了解在多个线程上显示 UI 可能会遇到的麻烦。

标签: c# winforms events focus


【解决方案1】:

我尝试了一些方法,发现这确实可以按您的意愿工作,整个想法是在显示进度表单时从您的主 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();
        }
    }

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

【讨论】:

    猜你喜欢
    • 2015-01-01
    • 2010-09-26
    • 1970-01-01
    • 2016-07-08
    • 2013-09-13
    • 2020-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多