c# - 在文本框自動補全框中,C# 在焦點處於焦點時禁用鍵事件

  显示原文与译文双语对照的内容
133 2

在我的項目中有一個窗體 mainForm,它的中有兩個文本框 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");
}

我已經將 mainFormkeypreview 設置為 true,並將函數實現為 mainForm 事件,如下面的代碼所示:

mainForm_KeyDownEvent

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

現在我的問題是,每當焦點位於 txtUserName 並按下 A 時,就會顯示選擇"管理員"( 如我在上面的屬性中所示的集合中所定義。當我在鍵盤上單擊 Enter 時,它顯示的是MessageBox而不是選擇"管理員"。我知道這是調用 mainForm的keydown事件。當keyDown事件位於textbox下拉列表中時,如何禁用該事件,以便可以按 Enter 鍵?

編輯:
我嘗試了 public form() 中的下面代碼:( 不工作)

InitializeComponent();
if (txtUserName.AutoCompleteMode) {/* showing red scribbles */
 this.KeyDown -= mainForm_KeyDown;
 }
时间:原作者:0个回答

94 3

你根本不應該處理輸入鍵。可以刪除 KeyDown 處理程序,而使用表單的 AcceptButton 屬性來設置在按下Enter鍵時獲取"單擊"的按鈕。當另一個控制項已經處理輸入鍵時,這個按鈕已經被關閉了,而不是這個按鈕。

這對於你的情況是不夠的,因為標準的Windows 行為 is輸入鍵按默認按鈕。按Win+R鍵,以獲取運行。對話框,開始鍵入 C:Use, 按下鍵選擇 C:Users, 按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* 屬性,則需要實現自動完成插件,或者你將需要使用內置的屬性,否則你將需要取消輸入密鑰( 移除上 IsInputKey 中的&& IsDroppedDown ) 。

更新: 手動創建 IAutoComplete 對象的方法如下。字元串管理員和管理員被硬編碼。GetDropDownStatus函數用於抑制當下降 List 可以見時輸入按鈕的任何默認處理。反饋歡迎。

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;
 }
 }
}
原作者:
147 4

你需要重寫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....
 }
原作者:
99 5

嘗試這個。希望在你的焦點在txtUsername或者它的他位置時,它不會導致任何問題。

如果在 txtUserName 中寫入 a 並按回車,則使用 regular expressionautocompletecustomsource 選擇 Admministrator 選項,並且焦點將轉到 txtPassword我的正則表達式非常靈活,可以以從頭到尾嚴格地限制 MATCH,也可以以刪除忽略案例。

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();
//}
 }
原作者:
146 0

實際上你有兩個問題。

如果用戶鍵入第一個字母,將AutoCompleteMode屬性設置為,而不是簡單地使用"推薦。",那麼正確的條目將自動添加到 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");
 }
}

上面的關鍵事件處理代碼測試,以查看密碼文本框是否具有焦點( 意思是,用戶已經輸入了用戶 NAME,以及密碼,並且準備提交數據) 。如果是這樣,則調用btnLogin_Click事件。否則,將( 意思是txtUserName可能有焦點) 控制項傳遞給txtPassword以繼續數據輸入。

更新:你的評論:

就像這樣殺死鍵向下事件處理程序中的邏輯:

修改的事件處理代碼:

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

注意,另一個次要改進是使用組合框來選擇用戶名,然後將自動完成源設置為( 考慮到代碼的總體結構) 。這要求用戶從預先定義的List 中進行選擇。這仍然有類似於前面的scaleability問題,但是如果輸入用戶 NAME 數據,則消除了不必要的步驟。

記住用戶喜歡彈出郵件時不喜歡的中斷。允許他們從下拉列表中選擇適當的"用戶名",輸入正確的密碼,然後繼續。

有一些更好的方法來完成這一切,但這應該調整你的工作順序。

最後一個注意,讓我觀察一下最終你可以能想要找到一種更加健壯的方式來執行這種驗證。你需要添加用戶( 在你的代碼中,它似乎被定義為"組時,需要添加到條件事件處理樹。

你可以在加密的文件或者資料庫中檢查持久名和密碼,然後將它們載入到字典或者運行時。然後對用戶/密碼執行鍵/值查找。

或者什麼。

總之希望能幫助你。

更新 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");
 }
 }
 }
}
原作者:
...