如何动态更改C#组合框或文本框中的自动完成条目?
我在C#中有一个组合框,我希望使用自动完成建议,但是我希望能够在用户类型中更改自动完成条目,因为可能的有效条目太多,无法在启动时填充如何动态更改C#组合框或文本框中的自动完成条目?,c#,winforms,autocomplete,combobox,textbox,C#,Winforms,Autocomplete,Combobox,Textbox,我在C#中有一个组合框,我希望使用自动完成建议,但是我希望能够在用户类型中更改自动完成条目,因为可能的有效条目太多,无法在启动时填充AutoCompleteStringCollection 例如,假设我让用户输入一个名称。我有一个可能的名字列表(“乔”、“约翰”)和一个姓氏列表(“布洛格斯”、“史密斯”),但如果我每个都有一千个,那么可能会有一百万个字符串——太多了,无法放入自动完成的条目中。因此,最初我只想将名字作为建议(“Joe”、“John”),然后,一旦用户输入了名字(“Joe”),我想
AutoCompleteStringCollection
例如,假设我让用户输入一个名称。我有一个可能的名字列表(“乔”、“约翰”)和一个姓氏列表(“布洛格斯”、“史密斯”),但如果我每个都有一千个,那么可能会有一百万个字符串——太多了,无法放入自动完成的条目中。因此,最初我只想将名字作为建议(“Joe”、“John”),然后,一旦用户输入了名字(“Joe”),我想删除现有的自动完成条目,并将其替换为一个新的集合,该集合由所选的名字和可能的姓氏(“Joe Bloggs”、“Joe Smith”)组成。为此,我尝试了以下代码:
void InitializeComboBox()
{
ComboName.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
ComboName.AutoCompleteSource = AutoCompleteSource.CustomSource;
ComboName.AutoCompleteCustomSource = new AutoCompleteStringCollection();
ComboName.TextChanged += new EventHandler( ComboName_TextChanged );
}
void ComboName_TextChanged( object sender, EventArgs e )
{
string text = this.ComboName.Text;
string[] suggestions = GetNameSuggestions( text );
this.ComboQuery.AutoCompleteCustomSource.Clear();
this.ComboQuery.AutoCompleteCustomSource.AddRange( suggestions );
}
但是,这并不能正常工作。对Clear()的调用似乎会导致自动完成机制“关闭”,直到组合框中出现下一个字符,但当然,当下一个字符出现时,上面的代码会再次调用Clear(),因此用户从未真正看到自动完成功能。它还会导致组合框的全部内容被选中,因此在每次按键之间,您必须取消选择现有文本,这使其无法使用。如果我删除了对Clear()的调用,那么自动完成就可以工作了,但是似乎AddRange()
调用没有效果,因为我添加的新建议不会出现在自动完成下拉列表中
我一直在寻找解决方案,并看到了各种建议,但我无法让它们中的任何一个工作-要么自动完成功能被禁用,要么新字符串没有出现。以下是我尝试过的事情列表:
- 在更改字符串之前调用
,然后调用BeginUpdate()
EndUpdate()
- 对所有现有字符串调用
,而不是Clear()Remove()
- 在更新字符串时清除组合框中的文本,然后再添加回来
- 更改字符串时将
自动完成模式设置为“None”,然后将其设置回“SuggestAppend”
- 挂起
或TextUpdate
事件,而不是KeyPress
TextChanged
- 每次都将现有的
替换为新的AutoCompleteCustomSource
AutoCompleteStringCollection
组合框
函数。使用反射器,我在组合框中找到了两个看起来很有前途的方法-getStringsFrautoComplete()
和SetAutoComplete()
,但它们都是私有的,所以我无法从派生类访问它们。我再也受不了了
我尝试用文本框
替换组合框
,因为自动完成界面是相同的,我发现行为略有不同。使用文本框
时,它似乎工作得更好,因为自动完成的附加部分工作正常,但建议部分工作不正常-建议框短暂闪烁,但随后立即消失
所以我想“好吧,我将不使用建议功能,而只使用Append”,但是当我将AutoCompleteMode
设置为Append时,我得到了一个访问冲突异常。Suggest也会发生同样的情况-唯一不引发异常的模式是SuggestAppend
,即使SuggestAppend部分的行为不正确
我认为在使用C#托管代码时,不可能获得访问冲突异常。建议我使用“lock”来修复此问题,但我不知道应该锁定什么-唯一具有SyncRoot成员的是AutoCompleteTestringCollection
,以及无法防止访问冲突异常的锁定。我还试着锁定组合框
或文本框
,但也没有用。据我所知,lock只阻止其他锁,所以如果底层代码没有使用lock,那么我使用它不会有任何区别
所有这一切的结果是,我目前无法使用动态自动完成的文本框
或组合框
。有人对我如何做到这一点有什么见解吗
更新:
我仍然没有让这个工作,但我发现了更多。也许这会激励其他人想出一个解决方案
我尝试用文本框
替换组合框
,因为自动完成界面是相同的,我发现行为略有不同。使用文本框
时,它似乎工作得更好,因为自动完成的附加部分工作正常,但建议部分工作不正常-建议框短暂闪烁,但随后立即消失
所以我想“好吧,我将不使用建议功能,而只使用Append。”然而,当我将AutoCompleteMode
设置为Append时,我得到了一个访问冲突异常。Suggest也会发生同样的情况-唯一不引发异常的模式是SuggestAppend
,即使SuggestAppend部分的行为不正确
我认为在使用C#托管代码时不可能获得访问冲突异常,但无论如何,结果是我目前无法使用任何类型的动态自动完成的文本框
或组合框
。有人对我如何实现目标有什么见解吗
AutoCompleteCustomSource accs_a;
AutoCompleteCustomSource accs_b;
bool accs_check = true; //true for accs_a, false for accs_b
void InitializeComboBox()
{
ComboName.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
ComboName.AutoCompleteSource = AutoCompleteSource.CustomSource;
accs_a = new AutoCompleteStringCollection();
accs_b = new AutoCompleteStringCollection();
ComboName.AutoCompleteCustomSource = accs_a;
ComboName.TextChanged += new EventHandler( ComboName_TextChanged );
}
void ComboName_TextChanged( object sender, EventArgs e )
{
string text = this.ComboName.Text;
if(accs_check)
{
accs_b.Clear();
accs_b.AddRange(GetNameSuggestions( text ));
accs_check = false;
}
else
{
accs_a.Clear();
accs_a.AddRange(GetNameSuggestions( text ));
accs_check = true;
}
this.ComboQuery.AutoCompleteCustomSource = accs_check? accs_a : accs_b;
}
private void Form1_Load(object sender, EventArgs e)
{
textBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
textBox1.TextChanged+=new EventHandler(textBox1_TextChanged);
col1.AddRange(new string[] { "avi avi", "avram avram" });
col2.AddRange(new string[] { "boria boria", "boris boris" });
textBox1.AutoCompleteCustomSource = col1;
textBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
}
AutoCompleteStringCollection col1 = new AutoCompleteStringCollection();
AutoCompleteStringCollection col2 = new AutoCompleteStringCollection();
object locker = new object();
private void textBox1_TextChanged(object sender, EventArgs e)
{
lock (locker)
{
if (textBox1.Text.StartsWith("a") && textBox1.AutoCompleteCustomSource != col1)
{
textBox1.AutoCompleteCustomSource = col1;
}
if (textBox1.Text.StartsWith("b") && textBox1.AutoCompleteCustomSource != col2)
{
textBox1.AutoCompleteCustomSource = col2;
}
}
}
if(!textBox3.AutoCompleteCustomSource.Contains(textBox3.Text))
textBox3.AutoCompleteCustomSource.Add(textBox3.Text);
PropertyInfo[] props = [object].GetType().GetProperties({flags go here});
props[0].SetValue(this, new object[] { 0 });
private void cboAuthor_KeyDown(object sender, KeyEventArgs e)
{
if (cboAuthor.Text.Length == 0)
{
// Next two lines simple load data from the database in the
// into a collection (var gateway), base on first letter in
// the combobox. This is specific to my app.
var gateway = new AuthorTableGateway();
gateway.LoadByFirstLetter(Char.ConvertFromUtf32(e.KeyValue)[0]);
// Clear current source without calling Clear()
for (int i = 0; i < authorsAutoComplete.Count; i++)
authorsAutoComplete.RemoveAt(0);
// Rebuild with new data
foreach (var author in gateway)
authorsAutoComplete.Add(author.AuthorName);
}
}
private void txtAutoComplete_KeyUp(object sender, KeyEventArgs e)
{
String text = txtAutoComplete.Text;
if (text.EndsWith(" "))
{
string[] suggestions = GetNameSuggestions( text ); //put [text + " "] at the begin of each array element
txtAutoComplete.AutoCompleteCustomSource.Clear();
txtAutoComplete.AutoCompleteCustomSource.AddRange( suggestions );
}
}
form.fileComboBox.TextChanged += (sender, e) => {
var autoComplete = new AutoCompleteStringCollection();
string[] items = CustomUtil.GetFileNames();
autoComplete.AddRange(items);
form.fileComboBox.AutoCompleteCustomSource = autoComplete;
};
private void dataGridView1_EditingControlShowing(object sender,DataGridViewEditingControlShowingEventArgs e)
{
if (e.Control is DataGridViewComboBoxEditingControl)
{
((ComboBox)e.Control).DropDownStyle = ComboBoxStyle.DropDown;
((ComboBox)e.Control).AutoCompleteSource = AutoCompleteSource.ListItems;
((ComboBox)e.Control).AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
}
}
private void comboBox1_KeyUp(object sender, KeyEventArgs e)
{
if (string.IsNullOrWhiteSpace(comboBox1.Text))
{
e.Handled = true;
return;
}
if (comboBox1.Text.Length < 3)
{
e.Handled = true;
return;
}
if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up)
{
e.Handled = true;
return;
}
else if (e.KeyCode == Keys.Back)
{
e.Handled = true;
return;
}
string text = comboBox1.Text;
if (e.KeyCode == Keys.Enter)
{
comboBox1.DroppedDown = false;
comboBox1.SelectionStart = text.Length;
e.Handled = true;
return;
}
List<string> LS = Suggestions(comboBox1.Text);
comboBox1.Items.Clear();
comboBox1.Items.AddRange(LS.ToArray());
//If you do not want to Suggest and Append
//comment the following line to only Suggest
comboBox1.Focus();
comboBox1.DroppedDown = true;
comboBox1.SelectionStart = text.Length;
//Prevent cursor from getting hidden
Cursor.Current = Cursors.Default;
e.Handled = true;
}
private void CellBox_TextChanged(object sender, EventArgs e)
{
((TextBox)sender).TextChanged -= CellBox_TextChanged;
((TextBox)dataGridView1.EditingControl).AutoCompleteMode = AutoCompleteMode.None;
((TextBox)dataGridView1.EditingControl).AutoCompleteCustomSource = null;
aCSC.Clear();
foreach (string value in Autocompletevalues())
{
aCSC.Add(value);
}
((TextBox)dataGridView1.EditingControl).AutoCompleteCustomSource = aCSC;
((TextBox)dataGridView1.EditingControl).AutoCompleteMode = AutoCompleteMode.Suggest;
((TextBox)sender).TextChanged += CellBox_TextChanged;
}