2012-08-02 217 views
12

我的问题类似于这个:How can I dynamically change auto complete entries in a C# combobox or textbox? 但我仍然没有找到解决方案。C#winforms combobox动态自动完成

的简单问题:

我有一个ComboBox和大量的记录在它显示。当用户开始输入时,我想加载以输入文本开头的记录并为用户提供自动完成功能。 正如上述主题中所述,我无法在сomboBox_TextChanged上加载它们,因为我总是覆盖以前的结果并且从不会看到它们。

我可以仅使用ComboBox执行此操作吗? (不TextBoxListBox

我使用这个设置:

сomboBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend; 
сomboBox.AutoCompleteSource = AutoCompleteSource.CustomSource; 
+1

你可以通过jquery或ajax来做到这一点。创建一个方法,该方法接受一个字符串并返回匹配该字符串的结果列表,然后挂接视图中的jquery/ajax来监听击键和x次击键(通常为3次)后,让jquery调用方法并用结果填充列表。 – Brian 2012-08-02 15:30:34

+6

嗯......这是在winform – algreat 2012-08-02 15:39:16

+0

对不起,我开始专注于网络,但概念是相同的。有一个事件可以侦听键击并调用一个接收该字符串并返回结果集的方法。 – Brian 2012-08-02 15:56:23

回答

13

这是我的最终解决方案。它适用于大量的数据。我使用Timer来确保用户想要查找当前值。它看起来很复杂,但它不。 感谢Max Lambertini的想法。

 private bool _canUpdate = true; 

     private bool _needUpdate = false;  

     //If text has been changed then start timer 
     //If the user doesn't change text while the timer runs then start search 
     private void combobox1_TextChanged(object sender, EventArgs e) 
     { 
      if (_needUpdate) 
      { 
       if (_canUpdate) 
       { 
        _canUpdate = false; 
        UpdateData();     
       } 
       else 
       { 
        RestartTimer(); 
       } 
      } 
     } 

     private void UpdateData() 
     { 
      if (combobox1.Text.Length > 1) 
      { 
       List<string> searchData = Search.GetData(combobox1.Text); 
       HandleTextChanged(searchData); 
      } 
     }  

     //If an item was selected don't start new search 
     private void combobox1_SelectedIndexChanged(object sender, EventArgs e) 
     { 
      _needUpdate = false; 
     } 

     //Update data only when the user (not program) change something 
     private void combobox1_TextUpdate(object sender, EventArgs e) 
     { 
      _needUpdate = true; 
     } 

     //While timer is running don't start search 
     //timer1.Interval = 1500; 
     private void RestartTimer() 
     { 
      timer1.Stop(); 
      _canUpdate = false; 
      timer1.Start(); 
     } 

     //Update data when timer stops 
     private void timer1_Tick(object sender, EventArgs e) 
     { 
      _canUpdate = true; 
      timer1.Stop(); 
      UpdateData(); 
     } 

     //Update combobox with new data 
     private void HandleTextChanged(List<string> dataSource) 
     { 
      var text = combobox1.Text; 

      if (dataSource.Count() > 0) 
      { 
       combobox1.DataSource = dataSource; 

       var sText = combobox1.Items[0].ToString(); 
       combobox1.SelectionStart = text.Length; 
       combobox1.SelectionLength = sText.Length - text.Length; 
       combobox1.DroppedDown = true; 


       return; 
      } 
      else 
      { 
       combobox1.DroppedDown = false; 
       combobox1.SelectionStart = text.Length; 
      } 
     } 

此解决方案不是很酷。所以如果有人有另一种解决方案,请与我分享。

+4

如果 - 像我一样 - 您发现使用“combobox1.DroppedDown = true”导致鼠标光标消失,在它后面添加“Cursor.Current = Cursors.Default”。 – Andy 2014-03-13 16:04:59

+0

名称'搜索'在当前上下文\t中不存在。我在这里错过了什么? – 2016-12-02 22:09:17

+1

搜索是用户定义的函数来获取数据源 – 2017-03-03 12:09:33

7

是的,你一定可以的...但它需要一些工作,使之无缝工作。这是我想出的一些代码。请记住,它使用组合框的自动完成功能,如果你用它来筛选直通很多项目可能是相当缓慢......

string[] data = new string[] { 
    "Absecon","Abstracta","Abundantia","Academia","Acadiau","Acamas", 
    "Ackerman","Ackley","Ackworth","Acomita","Aconcagua","Acton","Acushnet", 
    "Acworth","Ada","Ada","Adair","Adairs","Adair","Adak","Adalberta","Adamkrafft", 
    "Adams" 

}; 
public Form1() 
{ 
    InitializeComponent(); 
} 

private void comboBox1_TextChanged(object sender, EventArgs e) 
{ 
    HandleTextChanged(); 
} 

private void HandleTextChanged() 
{ 
    var txt = comboBox1.Text; 
    var list = from d in data 
       where d.ToUpper().StartsWith(comboBox1.Text.ToUpper()) 
       select d; 
    if (list.Count() > 0) 
    { 
     comboBox1.DataSource = list.ToList(); 
     //comboBox1.SelectedIndex = 0; 
     var sText = comboBox1.Items[0].ToString(); 
     comboBox1.SelectionStart = txt.Length; 
     comboBox1.SelectionLength = sText.Length - txt.Length; 
     comboBox1.DroppedDown = true; 
     return; 
    } 
    else 
    { 
     comboBox1.DroppedDown = false; 
     comboBox1.SelectionStart = txt.Length; 
    } 
} 

private void comboBox1_KeyUp(object sender, KeyEventArgs e) 
{ 
    if (e.KeyCode == Keys.Back) 
    { 
     int sStart = comboBox1.SelectionStart; 
     if (sStart > 0) 
     { 
      sStart--; 
      if (sStart == 0) 
      { 
       comboBox1.Text = ""; 
      } 
      else 
      { 
       comboBox1.Text = comboBox1.Text.Substring(0, sStart); 
      } 
     } 
     e.Handled = true; 
    } 
} 
+0

这是很好的解决方案。它比默认的自动完成功能更好。但对大量数据来说还不够。所以我会尽力改善你的解决方案。 – algreat 2012-08-10 07:17:24

+1

只有当文本长度超过三个字符时,才能触发自动完成,例如文本长度超过三个字符...... – 2012-08-11 18:37:24

+0

使用超时我认为这是一个不错的选择,当用户在预定义时间后停止键入时,执行查询。 – Joseph 2016-06-23 15:57:21

2

此代码写在您的表单加载。当用户在组合框中输入字母时,它显示数据库中的所有巡视。此代码自动建议并根据用户需要附加正确的选项。

  con.Open(); 
      cmd = new SqlCommand("SELECT DISTINCT Tour FROM DetailsTB", con); 
      SqlDataReader sdr = cmd.ExecuteReader(); 
      DataTable dt = new DataTable(); 
      dt.Load(sdr); 
      combo_search2.DisplayMember = "Tour"; 
      combo_search2.DroppedDown = true; 

      List<string> list = new List<string>(); 
      foreach (DataRow row in dt.Rows) 
      { 
       list.Add(row.Field<string>("Tour")); 
      } 
      this.combo_search2.Items.AddRange(list.ToArray<string>()); 
      combo_search2.AutoCompleteMode = AutoCompleteMode.SuggestAppend; 
      combo_search2.AutoCompleteSource = AutoCompleteSource.ListItems; 
      con.Close(); 
0
using (var client = new UserServicesClient()) 
{ 
    var list = new AutoCompleteStringCollection(); 
    list.AddRange(client.ListNames(query).ToArray()); 
    comboBoxName.AutoCompleteCustomSource = list; 
} 
+1

通常,如果答案包含对代码的打算要做什么的解释,以及为什么解决问题而不介绍其他问题,则答案会更有帮助。 (这篇文章被至少一个用户标记,大概是因为他们认为没有解释的答案应该被删除。) – 2015-05-13 00:54:26

2

在以前的答复是缺点。提供自己版本的选择在下拉列表中选择所需项目:

private ConnectSqlForm() 
    { 
     InitializeComponent(); 
     cmbDatabases.TextChanged += UpdateAutoCompleteComboBox; 
     cmbDatabases.KeyDown += AutoCompleteComboBoxKeyPress; 
    } 

    private void UpdateAutoCompleteComboBox(object sender, EventArgs e) 
    { 
     var comboBox = sender as ComboBox; 
     if(comboBox == null) 
     return; 
     string txt = comboBox.Text; 
     string foundItem = String.Empty; 
     foreach(string item in comboBox.Items) 
      if (!String.IsNullOrEmpty(txt) && item.ToLower().StartsWith(txt.ToLower())) 
      { 
       foundItem = item; 
       break; 
      } 

     if (!String.IsNullOrEmpty(foundItem)) 
     { 
      if (String.IsNullOrEmpty(txt) || !txt.Equals(foundItem)) 
      { 
       comboBox.TextChanged -= UpdateAutoCompleteComboBox; 
       comboBox.Text = foundItem; 
       comboBox.DroppedDown = true; 
       Cursor.Current = Cursors.Default; 
       comboBox.TextChanged += UpdateAutoCompleteComboBox; 
      } 

      comboBox.SelectionStart = txt.Length; 
      comboBox.SelectionLength = foundItem.Length - txt.Length; 
     } 
     else 
      comboBox.DroppedDown = false; 
    } 

    private void AutoCompleteComboBoxKeyPress(object sender, KeyEventArgs e) 
    { 
     var comboBox = sender as ComboBox; 
     if (comboBox != null && comboBox.DroppedDown) 
     { 
      switch (e.KeyCode) 
      { 
       case Keys.Back: 
        int sStart = comboBox.SelectionStart; 
        if (sStart > 0) 
        { 
         sStart--; 
         comboBox.Text = sStart == 0 ? "" : comboBox.Text.Substring(0, sStart); 
        } 
        e.SuppressKeyPress = true; 
        break; 
      } 

     } 
    } 
2

我发现最大Lambertini的回答非常有帮助的,但修改了他的HandleTextChanged方法,例如:

//I like min length set to 3, to not give too many options 
    //after the first character or two the user types 
    public Int32 AutoCompleteMinLength {get; set;} 

    private void HandleTextChanged() { 
     var txt = comboBox.Text; 
     if (txt.Length < AutoCompleteMinLength) 
      return; 

     //The GetMatches method can be whatever you need to filter 
     //table rows or some other data source based on the typed text. 
     var matches = GetMatches(comboBox.Text.ToUpper()); 

     if (matches.Count() > 0) { 
      //The inside of this if block has been changed to allow 
      //users to continue typing after the auto-complete results 
      //are found. 
      comboBox.Items.Clear(); 
      comboBox.Items.AddRange(matches); 
      comboBox.DroppedDown = true; 
      Cursor.Current = Cursors.Default; 
      comboBox.Select(txt.Length, 0); 
      return; 
     } 
     else { 
      comboBox.DroppedDown = false; 
      comboBox.SelectionStart = txt.Length; 
     } 
    } 
1

我写这样的事情....

private void frmMain_Load(object sender, EventArgs e) 
{ 
    cboFromCurrency.Items.Clear(); 
    cboComboBox1.AutoCompleteMode = AutoCompleteMode.Suggest; 
    cboComboBox1.AutoCompleteSource = AutoCompleteSource.ListItems; 
    // Load data in comboBox => cboComboBox1.DataSource = ..... 
    // Other things 
} 

private void cboComboBox1_KeyPress(object sender, KeyPressEventArgs e) 
{ 
    cboComboBox1.DroppedDown = false; 
} 

这一切(Y)

12

我也来交流ross最近这些类型的要求。我设置下面的属性,而不写出它的工作代码,看看这是否对你有帮助。

enter image description here