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

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

问题描述

在我的项目中有一个表格 mainForm ,其中有两个textBoxes txtUserName txtPassword 以及一个按钮 btnLogin



我已给出以下 txtUserName 属性:



txtUserName属性

  AutoCompleteCustomSource- Collection 
- >管理员
- >职员
AutoCompleteMode - 建议
AutoCompleteSource - CustomSource

btnLogin_Click事件

  if(txtUserName.Text.Equals(Administrator)&& txtPassword.Text.Equals 123))
{
//用于访问管理员功能的函数
}
else if(txtUserName.Text.Equals(Clerk)&& txtPassword.Text。等于(123))
{
//函数访问文员特性
}
else
{
MessageBox.Show详细信息,登录错误);
}

我已经设置了 mainForm keypreview true ,并实现 mainForm



 >  if(e.KeyCode.Equals(Keys.Enter))//每当Enter被按下时调用
{
btnLogin_Click(sender,e); // login
}

现在我的问题是,每当焦点在 txtUserName ,然后按 A ,将显示下拉菜单以选择管理员(在集合中定义为我在上面的属性中显示)。当我在键盘上单击输入时,它显示MessageBox,而不是选择管理员。我知道是在调用 mainForm 的keydown事件。如何禁用keyDown事件,当它在文本框下拉框事件,以便我可以按输入



strong> EDIT :

我尝试了 public form()无效

  InitializeComponent(); 
if(txtUserName.AutoCompleteMode){/ *显示红色涂鸦* /
this.KeyDown - = mainForm_KeyDown;
}


解决方案

全部输入密钥。您可以删除 KeyDown 处理程序,而使用 AcceptButton 表单的属性设置获取点击。这已经应该不是当其他控件已经处理了Enter键时点击按钮。



这是不够的情况,因为标准Windows行为是Enter键按默认按钮。例如,按Win + R,得到Run ...对话框,开始键入C:\Use,按Down选择C:\Users,按Enter键,看看会发生什么。



为了覆盖这个行为,你需要让文本框告诉窗体它将处理Enter键本身,这样窗体不会将它发送到默认按钮。这可以通过创建一个派生类并覆盖 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 ,但由于对象无法访问,因此您无法(可靠地)确定是否显示下拉列表。



您需要使用内置的 AutoComplete * 属性来实现自动完成而不需要,否则您需要始终 em>禁止Enter键(删除上面 IsInputKey 中的&& amp; IsDroppedDown )。



更新:下面介绍如何手动创建 IAutoComplete 对象。字符串管理员和文件是硬编码的。当下拉列表可见时,GetDropDownStatus函数用于禁止任何默认按钮对Enter的处理。反馈欢迎。



IAutoComplete.cs:

  
using System.Runtime.InteropServices;
使用System.Runtime.InteropServices.ComTypes;

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

IAutoComplete2.cs:

 使用系统; 
using System.Runtime.InteropServices;
使用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:

  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:

 使用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:

 使用系统; 

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

IAutoCompleteClass.cs:

 使用系统; 
using System.Runtime.InteropServices;

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

 <$> 

c $ c> using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
使用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:

 使用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);
}

保护覆盖void DestroyHandle()
{
ReleaseAutoComplete();
base.DestroyHandle();
}

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

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

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


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

I have given the following txtUserName properties:

txtUserName Properties

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

btnLogin_Click Event

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");
}

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

mainForm_KeyDownEvent

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

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?

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

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

解决方案

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.

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.

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);
    }
}

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.

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).

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:

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:

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:

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:

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:

using System;

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

IAutoCompleteClass.cs:

using System;
using System.Runtime.InteropServices;

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

EnumString.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:

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天全站免登陆