Combobox di completamento automatico per WPF

Ho bisogno di una combobox di completamento automatico per WPF C #. Ho provato diversi approcci ma niente funziona. Ad esempio, ho provato una casella combinata:

 

Names è un elenco di stringhe: Peter John, John, John Doe, Cathy, Howard, John Richards e così via

Se inserisci un nome, ad es. John, la casella combinata dovrebbe espandersi e dovrei vedere

  • John
  • John Doe
  • John Richards
  • Peter John

Ma questo non funziona. Come lo posso fare?

    usa l’evento PreviewTextInput per fare filtrare e mostrare il menu a discesa in questo modo:

     private void ComboBox_TextInput_1(object sender, TextCompositionEventArgs e) { cmbperson.IsDropDownOpen = true; cmbperson.ItemsSource = DataBase.Persons.Where(p => p.Name.Contains(e.Text)).ToList(); } 

    Ti suggerisco di utilizzare un controllo creato per il completamento automatico anziché una casella combinata. Molte aziende offrono tali controlli, questo è gratuito e considerato buono.

    Dopo molte discussioni, sono riuscito a trovare una soluzione completa e funzionante. (O così sembra.)

    Passaggio 1. Modificare il markup XAML

    Devi modificare il tuo ComboBox in questo modo:

      

    vale a dire. per disabilitare la ricerca di testo predefinita e aggiungere gestori di eventi che si occuperanno dell’aggiunta, dell’eliminazione e dell’incollatura del testo da parte dell’utente.

    Passaggio 2. Aggiungi una funzione di supporto che otterrà il TextBox interno di ComboBox (perché WPF)

    Per fare in modo che PreviewTextInput_EnhanceComboSearch e Pasting_EnhanceComboSearch funzionino, è necessario accedere al caret del ComboBox. Sfortunatamente, per fare questo, devi attraversare, er, albero visivo ( hat tip per Matt Hamilton ). Puoi farlo in un metodo di estensione, ma ne ho usato uno statico nella mia class Page :

     public static T GetChildOfType(DependencyObject depObj) where T : DependencyObject { if (depObj == null) return null; for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { var child = VisualTreeHelper.GetChild(depObj, i); var result = (child as T) ?? GetChildOfType(child); if (result != null) return result; } return null; } 

    Passaggio 3. Implementare i gestori di eventi

    Si prega di notare che ho usato

     s => s.IndexOf(e.Text, StringComparison.InvariantCultureIgnoreCase) != -1 

    che è equivalente al controllo s => s.Contains(e.Text) tra maiuscole e minuscole. Ricordarsi di cambiare quella parte in base alle proprie esigenze.

    Passaggio 3.a Inizia la ricerca sull’utente digitando all’interno di ComboBox

    Quando viene eseguito un gestore di PreviewTextInput , la proprietà .Text all’interno del ComboBox contiene il testo precedente alla sua modifica. Pertanto, abbiamo bisogno di ottenere il TextBox interno di ComboBox usando il metodo GetChildOfType per ottenere il suo caret, quindi sappiamo esattamente dove è stato inserito il carattere digitato.

     private void PreviewTextInput_EnhanceComboSearch(object sender, TextCompositionEventArgs e) { ComboBox cmb = (ComboBox)sender; cmb.IsDropDownOpen = true; if (!string.IsNullOrEmpty(cmb.Text)) { string fullText = cmb.Text.Insert(GetChildOfType(cmb).CaretIndex, e.Text); cmb.ItemsSource = Names.Where(s => s.IndexOf(fullText, StringComparison.InvariantCultureIgnoreCase) != -1).ToList(); } else if (!string.IsNullOrEmpty(e.Text)) { cmb.ItemsSource = Names.Where(s => s.IndexOf(e.Text, StringComparison.InvariantCultureIgnoreCase) != -1).ToList(); } else { cmb.ItemsSource = Names; } } 

    Passaggio 3.b Attivare la ricerca sull’utente che si incolla in ComboBox

    DataObject.Pasting gestore DataObject.Pasting comporta in modo simile a PreviewTextInput PreviewTextInput, quindi è necessario PreviewTextInput con il PreviewTextInput omissione.

     private void Pasting_EnhanceComboSearch(object sender, DataObjectPastingEventArgs e) { ComboBox cmb = (ComboBox)sender; cmb.IsDropDownOpen = true; string pastedText = (string)e.DataObject.GetData(typeof(string)); string fullText = cmb.Text.Insert(GetChildOfType(cmb).CaretIndex, pastedText); if (!string.IsNullOrEmpty(fullText)) { cmb.ItemsSource = Names.Where(s => s.IndexOf(fullText, StringComparison.InvariantCultureIgnoreCase) != -1).ToList(); } else { cmb.ItemsSource = Names; } } 

    Passaggio 3.c Attivare la ricerca sull’utente eliminando il testo all’interno di ComboBox (e anche premendo Spazio, perché WPF)

    Questo si innesca quando l’utente preme Delete o Backspace.

    E anche Space, perché Space viene ignorato da PreviewTextInput , quindi sarebbe difficile filtrare “John” da “John Doe” e “John Richards” nell’esempio.

     private void PreviewKeyUp_EnhanceComboSearch(object sender, KeyEventArgs e) { if (e.Key == Key.Back || e.Key == Key.Delete) { ComboBox cmb = (ComboBox)sender; cmb.IsDropDownOpen = true; if (!string.IsNullOrEmpty(cmb.Text)) { cmb.ItemsSource = Names.Where(s => s.IndexOf(cmb.Text, StringComparison.InvariantCultureIgnoreCase) != -1).ToList(); } else { cmb.ItemsSource = Names; } } } 

    … e probabilmente dovrebbe essere sufficiente.

    Ho creato un completamento automatico per WPF che potrebbe aiutarti. Segui il link sottostante per github: https://github.com/rhpontes/AutocompleteWpf

    Spero che ti aiuti.

    In XAML devi impostare IsEditable = True e aggiungere il gestore per l’evento PreviewKeyDown:

     private void ComboBox_PreviewKeyDown(object sender, KeyEventArgs e) { var cmb = (ComboBox)sender; cmb.IsDropDownOpen = true; var textbox = cmb.Template.FindName("PART_EditableTextBox", cmb) as TextBox; cmb.ItemsSource = CurrentStorage.Organisations.Where(p => string.IsNullOrEmpty(cmb.Text) || p.Name.ToLower().Contains(textbox.Text.ToLower())).ToList(); }