用于WPF的自动完成combobox

我需要一个用于WPF C#的自动完成combobox。 我尝试了几种方法,但没有任何效果。 例如,我尝试过一个combobox:

 

Names是一个字符串列表:Peter John,John,John Doe,Cathy,Howard,John Richards等等

如果你输入一个名字,例如John,combobox应该扩展,我应该看到

  • 约翰
  • 约翰·多伊
  • 约翰理查兹
  • 彼得约翰

但这不起作用。 我怎样才能做到这一点?

使用PreviewTextInput事件进行过滤和显示下拉,如下所示:

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

我建议您使用自动完成的控件而不是combobox。 许多公司提供这样的控制, 这个控制是免费的,并被认为是好的

经过大量的摆弄,我已经设法找到了一个完整的,有效的解决方案。 (或者似乎是这样。)

步骤1.修改XAML标记

你需要像这样修改你的ComboBox:

  

即。 禁用默认文本搜索,并添加将负责用户添加,删除和粘贴文本的事件处理程序。

步骤2.添加一个辅助函数,它将获得ComboBox的内部TextBox(因为WPF)

PreviewTextInput_EnhanceComboSearchPasting_EnhanceComboSearch完全正常工作,您需要访问ComboBox的插入符号。 不幸的是,要做到这一点,你需要遍历,呃,视觉树( 帽子提示到马特汉密尔顿 )。 您可以在扩展方法中执行此操作,但我在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; } 

第3步。实现事件处理程序

请注意我用过

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

这相当于不区分大小写的s => s.Contains(e.Text)检查。 记得改变那部分以满足您的需求。

步骤3.a触发用户在ComboBox内键入的搜索

运行PreviewTextInput处理程序时,ComboBox中的.Text属性包含修改之前的文本。 因此,我们需要使用GetChildOfType方法获取ComboBox的内部TextBox以获取其插入符,因此我们知道插入的键入字符的确切位置。

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

步骤3.b触发用户粘贴到ComboBox的搜索

DataObject.Pasting处理程序的行为方式与PreviewTextInput hanlder类似,因此我们需要再次使用插入符号。

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

步骤3.c触发搜索用户删除ComboBox内的文本(并按下Space,因为WPF)

当用户按下Delete或Backspace时,将触发此操作。

还有Space,因为PreviewTextInput会忽略Space,所以在PreviewTextInput中很难从“John Doe”和“John Richards”中过滤掉“John”。

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

……这应该足够了。

我为WPF创建了一个可以帮助你的自动完成function。 请点击以下链接到github: https : //github.com/rhpontes/AutocompleteWpf

我希望它对你有所帮助。

在XAML中,您应该设置IsEditable = True并为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(); }