WPF的自动完成组合框 [英] Autocomplete combobox for WPF

查看:113
本文介绍了WPF的自动完成组合框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need an autocomplete combobox for WPF C#. I've tried several approaches but nothing works. For example I've tried a combobox:

<ComboBox  Width="200"
      IsEditable="True"
      ItemsSource="{Binding Names}"
      IsTextSearchEnabled="True"
      HorizontalAlignment="Left"/>

名称是字符串列表:Peter约翰,约翰,约翰·杜伊,凯茜,霍华德,约翰·理查兹等

Names is a List of Strings: Peter John, John, John Doe, Cathy, Howard, John Richards and so on

如果您输入名称,例如John组合框应该扩大,我应该看到

If you type in a name e.g. John the combobox should expand and I should see


  • John

  • John Doe

  • John Richards

  • Peter John

  • John
  • John Doe
  • John Richards
  • Peter John

但这不起作用。我该怎么办?

But that doesn't work. How can I do that?

推荐答案

经过多番摆弄,我设法找到了一个完整的,可行的解决方案。 (或者看起来是这样。)

After a lot of fiddling, I have managed to arrive at a complete, working solution. (Or so it seems.)

您需要像修改ComboBox一样因此:

You need to modify your ComboBox like so:

<ComboBox
    ...
    IsTextSearchEnabled="False"
    ...
    PreviewTextInput="PreviewTextInput_EnhanceComboSearch"
    PreviewKeyUp="PreviewKeyUp_EnhanceComboSearch"
    DataObject.Pasting="Pasting_EnhanceComboSearch" />

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

ie. to disable default text search, and add events handlers that will take care of user adding, deleting and pasting text.

为了 PreviewTextInput_EnhanceComboSearch Pasting_EnhanceComboSearch 都可以使用,则需要访问ComboBox的插入符号。不幸的是,要做到这一点,您需要遍历所有视觉树( Matt Hamilton的帽子提示)。您可以使用扩展方法来做到这一点,但是我在 Page 类中使用了静态方法:

In order for PreviewTextInput_EnhanceComboSearch and Pasting_EnhanceComboSearch to work at all, you will need to access your ComboBox's caret. Unfortunately, to do this, you need to traverse, er, visual tree (hat tip to Matt Hamilton). You can do that in an extension method, but I used a static one in my Page class:

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



步骤3。实施事件处理程序



请注意我用过

Step 3. Implement event handlers

Please note I used

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

-不敏感 s => s.Contains(e.Text)检查。

当运行 PreviewTextInput 处理程序时,组合框内的 .Text 属性包含之前的文本已被修改。因此,我们需要使用 GetChildOfType 方法获取ComboBox的内部TextBox以获得其插入符,以便我们确切知道在何处插入了键入字符。

When a PreviewTextInput handler is run, the .Text property inside the ComboBox contains the text from before it was modified. Therefore, we need to get ComboBox's internal TextBox using GetChildOfType method in order to obtain its caret, so we know where exactly was the typed character inserted.

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



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



DataObject.Pasting 处理程序的行为与 PreviewTextInput hanlder,所以我们再次需要插入符号。

Step 3.b Trigger search on user pasting into ComboBox

DataObject.Pasting handler behaves in a similar fashion to PreviewTextInput hanlder, so we need the caret again.

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



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



这将在用户按下Delete键或Backspace键时触发。

Step 3.c Trigger search on user deleting text inside ComboBox (and also pressing Space, because WPF)

This will trigger when the user depresses either Delete or Backspace.

还有空格,因为 PreviewTextInput 忽略了空格,所以在示例中很难从 John Doe和 John Richards中滤除 John

And also Space, because Space is ignored by PreviewTextInput, so it would be difficult to filter out "John" from "John Doe" and "John Richards" in the example.

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






...这应该足够了。


...and that should probably be enough.

这篇关于WPF的自动完成组合框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆