当焦点位于文本框的自动完成框时禁用键事件 [英] disable key event when the focus is on autocompletion box of textbox

查看:12
本文介绍了当焦点位于文本框的自动完成框时禁用键事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的项目中有一个表单 mainForm,其中有两个文本框 txtUserNametxtPassword 以及一个按钮 btnLogin.

In my project there is a Form mainForm in which there are two textBoxes txtUserName and txtPassword and also a button btnLogin.

我已经给出了以下 txtUserName 属性:

I have given the following txtUserName properties:

txtUserName 属性

AutoCompleteCustomSource - Collection
                            --> Administrator
                            --> Clerk
AutoCompleteMode   - Suggest
AutoCompleteSource - CustomSource

btnLogin_Click 事件

if (txtUserName.Text.Equals("Administrator") && txtPassword.Text.Equals("123"))
{
    //function to access admin features
}
else if (txtUserName.Text.Equals("Clerk") && txtPassword.Text.Equals("123"))
{
    //function to access clerk features
}
else
{
    MessageBox.Show("Please Enter correct details", "Login Error");
}

我已将 mainForm keypreview 设置为 true 并实现了 mainForm 的 keyDown 事件的函数,如图所示在下面的代码中:

I have setted the mainForm keypreview to true and implemented function to keyDown event of mainForm which is shown in the below code:

ma​​inForm_KeyDownEvent

if (e.KeyCode.Equals(Keys.Enter))  //Invokes whenever Enter is pressed
{
    btnLogin_Click(sender,e);  //login
}

现在我的问题是,只要将焦点放在 txtUserName 上并按 A,下拉菜单就会显示选择管理员"(在集合中定义,如我在以上属性).当我在键盘上单击 Enter 时,它显示 MessageBox 而不是选择管理员".我知道这是调用 mainForm 的 keydown 事件.如何禁用 keyDown 事件,当它在文本框下拉事件上时,我可以按 enter?

Now my problem is that whenever the focus is on txtUserName and pressing A, dropdown is showing to select "Administrator" (which is defined in collections as I shown in above properties). When I click Enter on keyboard it is showing MessageBox instead of selecting "Administrator". I know that is invoking the keydown event of mainForm. How to disable the keyDown event, when it is on textbox dropdown thing so that I can press enter?

编辑:
我在 public form() 中尝试了以下代码:(不工作)

EDIT:
I tried the below code in public form() :(not working)

InitializeComponent();
if (txtUserName.AutoCompleteMode) { /* showing red scribbles */
            this.KeyDown -= mainForm_KeyDown;
        }

推荐答案

您根本不应该处理 Enter 键.您可以删除 KeyDown 处理程序,而是使用 AcceptButton 表单属性 设置按下 Enter 时被点击"的按钮.当另一个控件已经处理了 Enter 键时,这应该单击"按钮.

You should not be handling the Enter key at all. You can remove your KeyDown handler, and instead use the AcceptButton property of the form to set the button that gets "clicked" when Enter is pressed. This is already supposed to not "click" the button when another control has already handled the Enter key.

这对您的情况来说还不够,因为标准的 Windows 行为让 Enter 键按下默认按钮.例如,按 Win+R 以获取运行..."对话框,开始键入 C:Use,按向下选择 C:Users,按 Enter,然后看看会发生什么.

That isn't enough for your situation, because standard Windows behaviour is for the Enter key to press the default button. Press Win+R, for example, to get the Run... dialog, start typing C:Use, press Down to select C:Users, press Enter, and see what happens.

为了覆盖该行为,您需要让文本框告诉表单它将自己处理 Enter 键,以便表单不会将其发送到默认按钮.这可以通过创建派生类并覆盖 IsInputKey 来完成:

In order to override that behaviour, you need to make the text box tell the form that it will be handling the Enter key itself, so that the form won't send it to the default button. This can be done by creating a derived class and overriding IsInputKey:

public class MyTextBox : TextBox
{
    protected override bool IsInputKey(Keys keyData)
    {
        return base.IsInputKey(keyData) || ((keyData & ~Keys.Shift) == Keys.Enter && IsDroppedDown);
    }
}

但是,TextBox 使用 SHAutoComplete函数,自动创建IAutoComplete 对象 在幕后.无法访问该对象,因此无法创建我在 IsInputKey 中使用的 IsDroppedDown 属性.它将使用 IAutoCompleteDropDown.GetDropDownStatus 来实现,但由于对象不可访问,因此您无法(可靠地)确定下拉列表是否正在显示.

However, TextBox implements autocompletion using the SHAutoComplete function, which automatically creates an IAutoComplete object behind the scenes. That object cannot be accessed, and because of that, the IsDroppedDown property that I used in IsInputKey cannot be created. It would be implemented using IAutoCompleteDropDown.GetDropDownStatus, but since the object is inaccessible, you cannot (reliably) determine whether the dropdown list is showing.

您需要使用内置的 AutoComplete* 属性来实现自动完成,或者您需要始终抑制Enter键(去掉上面IsInputKey中的&&IsDroppedDown).

You would need to either implement the auto completion without using the built-in AutoComplete* properties, or you would need to always suppress the Enter key (remove the && IsDroppedDown in the above IsInputKey).

更新:以下是手动创建 IAutoComplete 对象的方法.字符串 Administrator 和 Clerk 是硬编码的.GetDropDownStatus 函数用于在下拉列表可见时抑制任何默认按钮对 Enter 的处理.欢迎反馈.

Update: here's how to create an IAutoComplete object manually. The strings Administrator and Clerk are hardcoded. The GetDropDownStatus function is used to suppress any default button's handling of Enter when the drop down list is visible. Feedback welcome.

IAutoComplete.cs:

IAutoComplete.cs:

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

[ComImport]
[Guid("00bb2762-6a77-11d0-a535-00c04fd7d062")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[CoClass(typeof(IAutoCompleteClass))]
interface IAutoComplete
{
    void Init(HandleRef hwndEdit, IEnumString punkACL, string pwszRegKeyPath, string pwszQuickComplete);
    void Enable(bool fEnable);
}

IAutoComplete2.cs:

IAutoComplete2.cs:

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

[Guid("EAC04BC0-3791-11d2-BB95-0060977B464C")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAutoComplete2
{
    void Init(HandleRef hwndEdit, IEnumString punkACL, string pwszRegKeyPath, string pwszQuickComplete);
    void Enable(bool fEnable);
    void SetOptions(AutoCompleteOptions dwFlag);
    AutoCompleteOptions GetOptions();
};

AutoCompleteOptions.cs:

AutoCompleteOptions.cs:

using System;

[Flags]
enum AutoCompleteOptions : int
{
    None = 0x00,
    AutoSuggest = 0x01,
    AutoAppend = 0x02,
    Search = 0x04,
    FilterPrefixes = 0x08,
    UseTab = 0x10,
    UpDownKeyDropsList = 0x20,
    RtlReading = 0x40,
    WordFilter = 0x80,
    NoPrefixFiltering = 0x100,
}

IAutoCompleteDropDown.cs:

IAutoCompleteDropDown.cs:

using System;
using System.Runtime.InteropServices;
using System.Text;

[Guid("3CD141F4-3C6A-11d2-BCAA-00C04FD929DB")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAutoCompleteDropDown
{
    void GetDropDownStatus(out AutoCompleteDropDownFlags dwFlags, out StringBuilder wszString);
    void ResetEnumerator();
}

AutoCompleteDropDownFlags.cs:

AutoCompleteDropDownFlags.cs:

using System;

[Flags]
enum AutoCompleteDropDownFlags : int
{
    None = 0x00,
    Visible = 0x01
}

IAutoCompleteClass.cs:

IAutoCompleteClass.cs:

using System;
using System.Runtime.InteropServices;

[ComImport]
[Guid("00BB2763-6A77-11D0-A535-00C04FD7D062")]
class IAutoCompleteClass
{
}

枚举字符串.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

class EnumString : IEnumString
{
    const int E_INVALIDARG = unchecked((int)0x80070057);
    const int S_OK = 0;
    const int S_FALSE = 1;

    int current;
    string[] strings;

    public EnumString(IEnumerable<string> strings)
    {
        this.current = 0;
        this.strings = strings.ToArray();
    }

    public void Clone(out IEnumString ppenum)
    {
        ppenum = new EnumString(strings);
    }

    public int Next(int celt, string[] rgelt, IntPtr pceltFetched)
    {
        if (celt < 0)
            return E_INVALIDARG;

        int num = 0;
        while (current < strings.Length && celt != 0)
        {
            rgelt[num] = strings[current];
            current++;
            num++;
            celt--;
        }

        if (pceltFetched != IntPtr.Zero)
            Marshal.WriteInt32(pceltFetched, num);

        if (celt != 0)
            return S_FALSE;

        return S_OK;
    }

    public void Reset()
    {
        current = 0;
    }

    public int Skip(int celt)
    {
        if (celt < 0)
            return E_INVALIDARG;

        if (strings.Length - current > celt)
        {
            current = strings.Length;
            return S_FALSE;
        }

        current += celt;
        return S_OK;
    }
}

MyTextBox.cs:

MyTextBox.cs:

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

public class MyTextBox : TextBox
{
    IAutoComplete2 autoComplete;
    IAutoCompleteDropDown autoCompleteDropDown;

    public bool IsDroppedDown
    {
        get
        {
            if (autoCompleteDropDown == null)
                return false;

            AutoCompleteDropDownFlags dwFlags;
            StringBuilder wszString;
            autoCompleteDropDown.GetDropDownStatus(out dwFlags, out wszString);
            return (dwFlags & AutoCompleteDropDownFlags.Visible) != AutoCompleteDropDownFlags.None;
        }
    }

    protected override void CreateHandle()
    {
        base.CreateHandle();

        autoComplete = (IAutoComplete2)new IAutoComplete();
        autoCompleteDropDown = (IAutoCompleteDropDown)autoComplete;
        autoComplete.SetOptions(AutoCompleteOptions.AutoSuggest);
        autoComplete.Init(new HandleRef(this, this.Handle), new EnumString(new string[] { "Administrator", "Clerk" }), null, null);
    }

    protected override void DestroyHandle()
    {
        ReleaseAutoComplete();
        base.DestroyHandle();
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            ReleaseAutoComplete();
        }
        base.Dispose(disposing);
    }

    protected override bool IsInputKey(Keys keyData)
    {
        return base.IsInputKey(keyData) || ((keyData & ~Keys.Shift) == Keys.Enter && IsDroppedDown);
    }

    void ReleaseAutoComplete()
    {
        if (autoComplete != null)
        {
            Marshal.ReleaseComObject(autoComplete);
            autoComplete = null;
            autoCompleteDropDown = null;
        }
    }
}

这篇关于当焦点位于文本框的自动完成框时禁用键事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆