任务栏最小化c# Windows窗体问题



我有一个Windows窗体应用程序,当窗体被激活,去激活或sizechange时,窗体做一些事情。这是相当具体的。例如:

表单激活:将变量isActive设置为true,并将输入集中到一个输入框中,以便其他人也可以输入一些内容。

Form Deactivated:将变量isActive设置为false,这样应用程序中的任何焦点更改(由远程机器消息,聊天消息等引起)都不会从其他应用程序窃取焦点。

现在,我有我的webBrowser1.Focus()命令在Form Activated事件,这是不理想的,因为当你点击任务栏图标,它试图最小化,但由于它的焦点回到web浏览器,窗体然后恢复/激活再次。

我在这里做了一些搜索Stack Overflow,并找到了以下信息:

编辑以下信息:

我确实在另一篇关于Stack Overflow的文章中找到了这个信息:

protected void OnActivateApp(bool activate)
{
    Console.WriteLine("Activate {0}", activate);
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
    // Trap WM_ACTIVATEAPP
    if (m.Msg == 0x1c) OnActivateApp(m.WParam != IntPtr.Zero);
    base.WndProc(ref m);
}

但是行为类似于我在上面2个事件中看到的问题。当任务栏图标被点击时,表单会捕捉到Deactivated:

激活假

然后,它立即这样做:

激活真正的

看起来,当你最小化带有任务栏按钮的窗口时,它仍然是"聚焦"的应用程序,直到你点击另一个应用程序。

其中一个帖子确实建议我捕获表单的GotFocus,但是没有事件,我可以找到GotFocus的表单级别,因为GotFocus是从控件派生的,而不是应用程序表单。

问题:我如何允许表单与任务栏按钮最小化,然后重新显示表单时,让它做webBrowser1.Focus()命令将焦点放在应该在的地方?

我是这样解决这个问题的。以前,我在OnActivated中的ActiveElement上调用Focus()。然而,除了你注意到的任务栏最小化调用,按alt选项卡给你的表单焦点不会导致调用OnActivated。

因此,我选择查看WM_ACTIVATE消息以确定何时给予焦点。来自MSDN文档:

按钮

低序字指定窗口是被激活还是被激活停用。该参数可以是以下值之一。的高阶字指定窗口的最小状态已激活或未激活。非零值表示窗口为最小化。

[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message message)
{
    base.WndProc(ref message);
    if (message.Msg == 0x6)
    {
        int highOrderWord = (int)((message.WParam.ToInt32() & 0xFFFF0000) >> 16);
        bool minimized = highOrderWord != 0;
        bool activating = message.WParam != IntPtr.Zero;
        if (activating && !minimized)
        {
            this.FocusBrowserElement();
        }
    }
}

private void FocusBrowserElement()
{
    if (!this.webBrowser.IsDisposed && 
         this.webBrowser.Document != null &&
         this.webBrowser.Document.ActiveElement != null)
    {
        this.webBrowser.Document.ActiveElement.Focus();
    }
}

对不起,我曾认为GotFocus事件会对窗体起作用,但当窗口本身的焦点发生变化时,它似乎不会触发。

所以我冒昧地写了一些可以工作的代码。而是使用Form Resize事件。我留下事件处理程序为您的激活和停用事件,以防他们仍然需要,但我不认为他们应该。只要确保调用'Refresh',这样表单就会重新绘制,焦点也会移动。

    public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private bool isActive = false;
    private FormWindowState previousstate;
    private void Form1_Load(object sender, EventArgs e)
    {
        previousstate = this.WindowState;
        //Got Focus Anonymous Delegate handles focus on the textbox
        //if the Form currently is Activated
        this.Resize += delegate(object resizesender, EventArgs resizee)
        {
            //if (previousstate == FormWindowState.Minimized)
            // {
                txtGetFocus.Focus();
                this.Refresh();
            // }
            previousstate = this.WindowState;
        };
        this.Activated += delegate(object activatedsender, EventArgs activatede)
        {
            isActive = true;
        };
        this.Deactivate += delegate(object deactivatesender, EventArgs deactivatee)
        {
            isActive = false;
        };
    }
}

我注释掉了一个测试用例,如果你想基于某个Windowstate来抑制移动。

我不喜欢你对焦点的方法,这是一个残酷的hack,但你可以推迟焦点的改变一秒钟,像这样:

Thread t = new Thread((ThreadStart)delegate(){
  Thread.Sleep(1000);
  this.Invoke(methodChangingFocus, new object[] {});
}).Start();

这样用户就有机会按下最小化按钮

最新更新