【问题标题】:Is there a way to detect whether the Winform TextBox's Leave event was triggered by Tab or Shift-Tab or other event?有没有办法检测 Winform TextBox 的 Leave 事件是否由 Tab 或 Shift-Tab 或其他事件触发?
【发布时间】:2012-08-07 23:27:08
【问题描述】:

我现在将跳过我的代码;应该更容易用文字来描述。

到目前为止,我的逻辑如下:

  1. 我有一个输入文本框,当用户输入错误的文本时,我会显示一条错误消息并将焦点返回到文本框。
  2. 当用户不输入任何内容或删除其中的内容并离开文本框时,它会进行一些处理,但在其他方面的行为与它一样 - 按 Tab 顺序跳转到下一个控件。
  3. 如果我关闭 Tab 键,如果我按下 Shift-Tab 或专注于我用鼠标单击的任何内容,则跳转到上一个控件。
  4. 如果我为某些可以自动完成的文本输入唯一前缀,例如可以自动完成为“artichoke”的“articho”,则代码会自动填充旁边的另一个只读文本框并跳到只读文本框的下一个邻居。 注意:如果我 Shift-Tab 使用相同的输入,那么它的作用相同,但在这种情况下我想执行不同的逻辑。
  5. 就像 4。但是如果我通过单击鼠标离开,那么代码会自动填充文本框 - 很好,但它也会选择我想要的控件。

现在坏掉的是4的秃头部分。;如果我尝试使用 Shift-Tab 向后循环所有交互式(而不是标签或禁用的)控件,我不能 - 我的自定义逻辑每 4. 启动并将焦点向前发送。仅当我在手头的文本框中填写了一些内容时,这才是一个问题,但我仍然想修复这种边缘情况。

有什么想法吗?有问题吗?

附:我不知道如何回答“你试过什么?”除了说我使用 WinForms 几个月而且我不知道如何在这里继续之外的其他类型的问题。谢谢。

【问题讨论】:

  • 反对者,请详细说明。

标签: c# winforms .net-4.0 customization


【解决方案1】:

您可能想尝试文本框的 PreviewKeyDown 事件,您可以在其中识别被按下的组合键,如果是 Shift + Tab 键则执行不同的逻辑。

【讨论】:

  • 谢谢。正如所写,我不会认为这是一个完整的答案。既然我还有一个单独的 Leave 事件,那我该如何让两者沟通呢?由于KeyPreview 将在Leave 事件之前发生,某种共享时间很快就会过期?更复杂的是,我已经在整个表单上拦截了一个KeyPreview 事件,并在 Page Up / Page Down 上做一些事情。当它们的键既不是 Page Down / Page Up 时退出该方法不应该花费太长时间,但我仍然不确定如何最好地选择时间间隔。另外,关于 Timer 类使用的任何建议
【解决方案2】:

这就是我的做法。

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace LeaveTest {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e) {
            base.OnLoad(e);
            textBox2.LostFocus += new EventHandler(textBox2_LostFocus);
        }

        void textBox2_LostFocus(object sender, EventArgs e) {
            Control newControl = GetCurrentControl();
            Control prevControl = GetPrevControl(textBox2);
            Control nextControl = GetNextControl(textBox2);

            if (newControl.Handle == prevControl.Handle) {
                MessageBox.Show("Case 4");
            }
        }

        [DllImport("user32.dll")]
        static extern IntPtr GetFocus();

        [DllImport("user32.dll")]
        static extern IntPtr GetNextDlgTabItem(IntPtr hDlg, IntPtr hCtl,
           bool bPrevious);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);

        enum GetWindow_Cmd : uint {
            GW_HWNDFIRST = 0,
            GW_HWNDLAST = 1,
            GW_HWNDNEXT = 2,
            GW_HWNDPREV = 3,
            GW_OWNER = 4,
            GW_CHILD = 5,
            GW_ENABLEDPOPUP = 6
        }


        private Control GetCurrentControl() {
            IntPtr hWnd = GetFocus();
            Control control = Control.FromHandle(hWnd);
            return control;
        }

        private Control GetNextControl(Control ctrl) {
            // I know the last parameter looks wierd, but it works
            IntPtr hWnd = GetNextDlgTabItem(ctrl.Parent.Handle, ctrl.Handle, true);

            Control control = Control.FromHandle(hWnd);
            return control;
        }

        private Control GetPrevControl(Control ctrl) {
            // I know the last parameter looks wierd, but it works
            IntPtr hWnd = GetNextDlgTabItem(ctrl.Parent.Handle, ctrl.Handle, false);
            Control control = Control.FromHandle(hWnd);
            return control;
        }
    }
}

【讨论】:

  • 谢谢,我会试一试。我试图尽量减少对user32.dll 的依赖,所以如果有技术上不需要去那里的方法,我想避免直接进行本机调用。例如,getCurrentControl() 可以只是 form.ActiveControl;要获取下一个和上一个选项卡项目,我可以执行 container.Controls 后跟 Linq 查询 - 更昂贵,但有效。所以,我很好奇 - 我绝对需要 user32.dll 的哪些功能来实现这一点?谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-29
  • 2011-09-19
  • 1970-01-01
相关资源
最近更新 更多