C# 根据事件设置活动表单,闪烁表单并发送到后台 - 怎么了?

C# set active form based on event, flashes form and sends to background - whats wrong?

我正在编写一个 windows 表单 (C#.NET) 项目,它将 运行 在 thinkpad 平板电脑上。我已经编写了一个自定义文本框,它可以触发设备上的 tabtip 键盘以帮助进行屏幕输入,但这很烦人,因为用户必须不断地在不同模式(数字、文本)和其他一些我希望通过提供自定义表单(键盘) 模拟屏幕键盘。

我的愿景: 在 Mainform 上,用户通过单击选择一个文本框,我的键盘表单显示,是活动表单并获得焦点。用户可以使用键盘表单将 numbers/text 发送到主表单上先前选择的文本框中。如果他将焦点切换回主窗体,它将把它带到前面和键盘(到后面)。

我是怎么解决的: 我的键盘表单是一个单例,它包含一个注册文本框的方法,该方法应该触发前面提到的行为。该表单包含一个变量,该变量将保存当前(或最后一个)选定的文本框,为此我注册了文本框的 OnFocus 事件并根据需要设置变量。

//part of the full solution
public TextBox CurrentControlInFocus
    {
        get { return _inFocusControl; }
        set
        {

            if (_inFocusControl != null && _inFocusControl != value)
            {
               //a new control is being selected 
               //so we should reset the color on the previous one 
               //to indicate to the user 
               //that it is not more the active control
                _inFocusControl.BackColor = DefaultColor;
            }
            // do nothing
            if (value == _inFocusControl) return;

            _inFocusControl = value;

            if (_inFocusControl != null)
            {
                //highlight the control to indicate 
               //to the user that this is the current 
               //active control
                _inFocusControl.BackColor = FocusColor;

                // activate the keyboard form.
                Application.OpenForms[Name].Activate();
            }
        }
    }

我的问题: 键盘已经显示并位于主窗体后面,我预计

Application.OpenForms[Name].Activate();

将把它带到前面,并使它成为焦点中的活动表单,但发生的是表单闪烁,来到前面,然后 returns 回到他以前的 z -主窗体后面的顺序。

当前不需要解决方法: 如果我将键盘表单上的 TopMost 属性 更改为 yes,代码将按预期工作,但这不符合我的标准,即如果主窗体再次检索焦点,键盘应按 z 顺序向后移动。

目前我不知道我还能尝试什么或者我缺少什么。

[可选] 因为主窗体上的文本框不在焦点上(因为键盘窗体是)插入符号不显示和动画,有没有比创建更简单的解决方案具有覆盖绘制事件并在该特定场景中手动绘制插入符号的自定义文本框?

尝试使用

    Application.OpenForms[Name].BringToFront()

编辑:

我猜你不能在控件的 OnFocus 事件中给另一个表单焦点。这将是一件容易测试的事情,我会这样做,但我现在没有 C# env。

编辑2:

来自 MSDN

Do not attempt to set focus from within the Enter, GotFocus, Leave, LostFocus, Validating, or Validated event handlers.

您可以尝试使用 BeginInvoke 来设置焦点,我认为它看起来像

    BeginInvoke((MethodInvoker)new delegate()
                 { Application.OpenForms[Name].Activate(); });

根据@BoldAsLove的建议 我找到了适合我的解决方案。

正如他提到的 MSDN 文章,我试图将焦点从文本框中的 GotFocus 事件中切换出来,但它没有按预期工作。

然而,通过 .BeginIvoke,我能够完成从 FormA 到 FormB 的焦点切换。

 public TextBox CurrentControlInFocus
    {
        get { return _inFocusControl; }
        set
        {

            if (_inFocusControl != null && _inFocusControl != value)
            {
                _inFocusControl.BackColor = DefaultColor;

            }

            if (value == _inFocusControl) return;

            _inFocusControl = value;

            if (_inFocusControl != null)
            {
                _inFocusControl.BackColor = FocusColor;

                #region Important block
                var f = Application.OpenForms[Name] ?? Singleton;
                // just making sure both handles are created before using an invoke
                if (Handle != IntPtr.Zero && _inFocusControl.Handle != IntPtr.Zero)
                    //call the invoke on the textbox control
                    _inFocusControl.BeginInvoke((MethodInvoker) (() => { 
                          f.Show(); //show the form 
                          // bring it to front
                          // it also should raise the event Activated 
                          f.Activate(); 
                    }));
                #endregion

            }
        }
    }

这是一种非常丑陋的方式。我很确定通常 Button 会触发这样的场景,我遇到了异常/边缘情况。我需要在 GotFocus 事件上将焦点更改为另一种形式。