当焦点在文本框的自动完成框上时禁用键事件 [英] disable key event when the focus is on autocompletion box of textbox
问题描述
在我的项目中有一个表格 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 $ c $
> 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屋!