自动完成组合框用于WPF

Str*_*uct 6 .net c# wpf combobox autocomplete

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

<ComboBox  Width="200"
      IsEditable="True"
      ItemsSource="{Binding Names}"
      IsTextSearchEnabled="True"
      HorizontalAlignment="Left"/>
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

小智 6

使用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();
    }
Run Code Online (Sandbox Code Playgroud)


Dra*_*mok 6

经过反复的摆弄,我设法找到了一个完整的,可行的解决方案。(或者如此。)

步骤1.修改XAML标记

您需要像这样修改ComboBox:

<ComboBox
    ...
    IsTextSearchEnabled="False"
    ...
    PreviewTextInput="PreviewTextInput_EnhanceComboSearch"
    PreviewKeyUp="PreviewKeyUp_EnhanceComboSearch"
    DataObject.Pasting="Pasting_EnhanceComboSearch" />
Run Code Online (Sandbox Code Playgroud)

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

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

为了PreviewTextInput_EnhanceComboSearchPasting_EnhanceComboSearch在所有的工作,你将需要访问你的组合框的插入符号。不幸的是,要做到这一点,您需要遍历,看得见树(Matt Hamilton的帽子提示)。您可以在扩展方法中执行此操作,但是我在Page类中使用了静态方法:

public static T GetChildOfType<T>(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<T>(child);
        if (result != null) return result;
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

步骤3.实现事件处理程序

请注意我用过

s => s.IndexOf(e.Text, StringComparison.InvariantCultureIgnoreCase) != -1 
Run Code Online (Sandbox Code Playgroud)

这等效于不区分大小写的s => s.Contains(e.Text)检查。切记更改该部分以适合您的需求。

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

PreviewTextInput运行处理程序,该.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<TextBox>(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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

DataObject.Pasting处理程序的行为与PreviewTextInputhanlder 相似,因此我们再次需要插入符号。

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<TextBox>(cmb).CaretIndex, pastedText);

    if (!string.IsNullOrEmpty(fullText))
    {
        cmb.ItemsSource = Names.Where(s => s.IndexOf(fullText, StringComparison.InvariantCultureIgnoreCase) != -1).ToList();
    }
    else
    {
        cmb.ItemsSource = Names;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

还有Space,因为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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

...这应该足够了。

  • 另见 /sf/ask/262028861/ (2认同)

Mot*_*Azu 3

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