当焦点位于文本框的自动完成框时,禁用键事件

在我的项目中有一个Form mainForm ,其中有两个textBoxes txtUserNametxtPassword以及一个按钮btnLogin

我给出了以下txtUserName属性:

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事件,如下面的代码所示:

mainForm_KeyDownEvent

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

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

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

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

您根本不应该处理Enter键。 您可以删除KeyDown处理程序,而是使用表单的AcceptButton属性来设置按下Enter时“单击”的按钮。 当另一个控件已经处理了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*属性的情况下实现自动完成,或者您需要始终禁止Enter键(删除上述&& IsDroppedDown中的&& IsDroppedDown IsInputKey )。

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

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

您需要覆盖keydown事件处理程序。

  protected override void OnKeyDown(KeyEventArgs e) { //call original event handler. Remove it if you don't need it at all. base.OnKeyDown(e); //Insert your code here.... } 

试试这个。 希望在焦点位于txtUsername或其他位置时按Enter键不会造成任何问题

如果您在txtUserName写入并按Enter键, Admministrator使用regular expression从您的autocompletecustomsource选择您的Admministrator选项,焦点将转到txtPassword 。 我的正则表达式非常灵活你可以将它限制为跟随严格匹配从开始,也可以删除忽略大小写

Regex rg = new Regex("^" + txtUserName.Text);

  private void mainForm_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode.Equals(Keys.Enter))// && !txtUserName.Focus())// && intFlag.Equals(0)) { if (txtUserName.Text.Length > 0) { if (txtUserName.Focused) { Regex rg = new Regex(txtUserName.Text, RegexOptions.IgnoreCase); for (int i = 0; i < txtUserName.AutoCompleteCustomSource.Count; i++) { if (rg.IsMatch(txtUserName.AutoCompleteCustomSource[i])) { txtUserName.Text = txtUserName.AutoCompleteCustomSource[i]; txtPassword.Focus(); return; } } } if (txtPassword.Text.Length > 0) { btnLogin_Click(null, null); //login } else { //MessageBox.Show("Please Give a Password"); txtPassword.Focus(); } } else { //MessageBox.Show("Please Give a username"); txtUserName.Focus(); } } //if (txtPassword.ContainsFocus) //{ // btnLogin_Click(sender, e); //login //} //else //{ // this.txtPassword.Focus(); //} } 

实际上,你有两个问题。

首先,将txtUserName的AutoCompleteMode属性设置为“SuggestAppend”,而不是简单地“建议”。 这样,如果用户键入第一个字母或两个字母,则正确的条目将自动附加到txtUSerName.Text。

接下来,修改您的表单代码如下:

 void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode.Equals(Keys.Enter)) //Invokes whenever Enter is pressed { if (txtPassword.ContainsFocus) { btnLogin_Click(sender, e); //login } else { this.txtPassword.Focus(); } } } private void btnLogin_Click(object sender, EventArgs e) { if (txtUserName.Text.Equals("Administrator") && txtPassword.Text.Equals("123")) { MessageBox.Show("Administrator"); } else if (txtUserName.Text.Equals("Clerk") && txtPassword.Text.Equals("123")) { MessageBox.Show("Clerk"); } else { MessageBox.Show("Please Enter correct details", "Login Error"); } } 

在上面,Key Down事件处理代码测试以查看密码文本框是否具有焦点(意味着,用户已经设定了用户名和密码,并准备提交数据)。 如果是,则调用btnLogin_Click事件。 否则,(意思是,txtUserName可能具有焦点)控制被传递给txtPassword以继续数据输入。

更新:重新 – 你的评论:

简单地杀掉Key Down Event处理程序中的逻辑,如下所示:

修订的事件处理代码:

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

注意,另一个小的改进(考虑到代码的整体结构)将使用combobox来选择UserName,并将自动完成源设置为“ListItems”,然后输入与文本框相同的选项。 这要求用户从预定义列表中进行选择。 这仍然具有与之前类似的可扩展性问题,但如果用户在输入用户名数据时只是输入拼写错误,则会为用户消除不必要的步骤。

请记住,用户倾向于不喜欢弹出消息不必要的中断。 允许他们从下拉列表中选择适当的“用户名”,输入正确的密码,然后继续。

有一些更好的方法来完成所有这些,但这应该调整你的工作顺序。

最后,请注意,最终您可能希望找到一种更强大的方法来执行此类validation。 任何时候您需要添加用户(在您的代码中,似乎更多地定义为“组”,您将需要添加到条件事件处理树。

您可以检查加密文件或数据库中的持久用户名和密码,并在运行时将它们加载到字典或其他内容中。 然后在user / Password上执行键/值查找。

或者其他的东西。

无论如何,希望有所帮助。

更新2:完整的代码一次性完成。 这应该按照你要求的方式行事:

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); this.KeyDown +=new KeyEventHandler(Form1_KeyDown); } void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode.Equals(Keys.Enter)) //Invokes whenever Enter is pressed { btnLogin_Click(sender, e); //login } } private void btnLogin_Click(object sender, EventArgs e) { if (txtUserName.Text.Equals("Administrator") && txtPassword.Text.Equals("123")) { MessageBox.Show("Administrator"); } else if (txtUserName.Text.Equals("Clerk") && txtPassword.Text.Equals("123")) { MessageBox.Show("Clerk"); } else { MessageBox.Show("Please Enter correct details", "Login Error"); } } } }