Autocompletado dynamic de combobox de C # winforms

Mi problema es similar a este: ¿Cómo puedo cambiar dinámicamente las entradas de autocompletar en un cuadro combinado de C # o en un cuadro de texto? Pero todavía no encuentro la solución.

El problema brevemente:

Tengo un ComboBox y una gran cantidad de registros para mostrar. Cuando el usuario comienza a escribir, quiero cargar los registros que comienzan con el texto de entrada y ofrecerle al usuario la función de autocompletar. Como se describe en el tema anterior, no puedo cargarlos en сomboBox_TextChanged porque siempre sobrescribo los resultados anteriores y nunca los veo.

¿Puedo implementar esto usando solo ComboBox ? (no TextBox o ListBox )

Yo uso esta configuración:

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

También me encontré con este tipo de requisitos recientemente. Establecí las siguientes propiedades sin escribir el código que funciona. Mira si esto te ayuda.

enter image description here

Aquí está mi solución final. Funciona bien con una gran cantidad de datos. Uso Timer para asegurarme de que el usuario quiera encontrar el valor actual. Parece complejo pero no es así. Gracias a Max Lambertini por la idea.

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

Esta solución no es muy buena. Entonces, si alguien tiene otra solución, por favor, compártala conmigo.

Sí, seguramente puedes … pero necesita un poco de trabajo para que funcione sin problemas. Este es un código que se me ocurrió. Tenga en cuenta que no usa las funciones de autocompletar de combobox, y puede ser bastante lento si lo usa para examinar muchos elementos …

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

Escribí algo como esto …

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

Eso es todo (Y)

He encontrado la respuesta de Max Lambertini muy útil, pero he modificado su método HandleTextChanged como tal:

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

Este código se escribe en la carga de tu formulario. Muestra todo el recorrido en la base de datos cuando el usuario escribe la letra en el cuadro combinado. Este código sugiere y anexa automáticamente la opción correcta según lo desee el usuario.

  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 list = new List(); foreach (DataRow row in dt.Rows) { list.Add(row.Field("Tour")); } this.combo_search2.Items.AddRange(list.ToArray()); combo_search2.AutoCompleteMode = AutoCompleteMode.SuggestAppend; combo_search2.AutoCompleteSource = AutoCompleteSource.ListItems; con.Close(); 

En las respuestas anteriores hay inconvenientes. Ofrece su propia versión con la selección en la lista desplegable del elemento deseado:

  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; } } } 
  using (var client = new UserServicesClient()) { var list = new AutoCompleteStringCollection(); list.AddRange(client.ListNames(query).ToArray()); comboBoxName.AutoCompleteCustomSource = list; }