2012-08-02 50 views
12

Mi problema es similar a este: How can I dynamically change auto complete entries in a C# combobox or textbox? Pero todavía no encuentro la solución.C# winforms combobox dynamic autocomplete

El problema brevemente:

tengo una ComboBox y un gran número de registros que se muestran en ella. 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 esta utilizando sólo ComboBox? (No TextBox o ListBox)

Yo uso esta configuración:

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

Puede hacerlo a través de jQuery o Ajax.crea un método que toma una cadena y devuelve una lista de resultados que coinciden con esa cadena, luego conecta el jquery/ajax en la vista para escuchar las teclas y luego del número de teclas x (usualmente 3), haz que jquery llame al método y rellene la lista con los resultados. – Brian

+6

hmm ... Está en winform – algreat

+0

lo siento, me enfoco en la web pero el concepto es el mismo. tener un evento que escucha las teclas y llama a un método que toma la cadena y devuelve el conjunto de resultados. – Brian

Respuesta

13

Aquí está mi solución final. Funciona bien con una gran cantidad de datos. Uso Timer para asegurarme de que el usuario quiere 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<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; 
      } 
     } 

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

+4

Si, como yo, encuentra que al usar "combobox1.DroppedDown = true" hace que el cursor del mouse desaparezca, agregue "Cursor.Current = Cursors.Default" después de él. – Andy

+0

El nombre 'Buscar' no existe en el contexto actual \t. que me estoy perdiendo aqui? –

+1

La búsqueda es una función definida por el usuario para obtener la fuente de datos –

7

Sí, seguramente se puede ... pero necesita algo de trabajo para que funcione a la perfección. Este es un código que se me ocurrió. Hay que tener en cuenta que no hace características de auto-completado el uso del cuadro combinado, y podría ser bastante lento si lo usa para tamizar a través de una gran cantidad de artículos ...

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

Esta es una buena solución. Funciona mejor que la autocompleta predeterminada. Pero aún no es suficiente para una gran cantidad de datos. Intentaré mejorar tu solución. – algreat

+1

Puede desencadenar autocompletar iniciando consultas en datos solo cuando, por ejemplo, la longitud del texto es más de tres, cuatro caracteres ... –

+0

Usar tiempos de espera Creo que es una buena opción, cuando el usuario deja de escribir después de un tiempo predefinido, comienza a realizar la consulta. – Joseph

2

Este código se escribe en su carga de 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<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

Generalmente, las respuestas son mucho más útiles si incluyen una explicación de lo que el código pretende hacer, y por qué eso resuelve el problema sin introducir otras. (Esta publicación fue marcada por al menos un usuario, presumiblemente porque pensaron que una respuesta sin explicación debería eliminarse). –

2

en respuestas anteriores son inconvenientes. Ofrece su propia versión con la selección en la lista desplegable la opción deseada:

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

que he encontrado la respuesta de Max Lambertini muy útiles, pero han 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; 
     } 
    } 
1

I escribió 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)

12

que también vienen ac ross este tipo de requisitos recientemente. Establecí las propiedades a continuación sin escribir el código que funciona. mira si esto te ayuda.

enter image description here