经过大量的摆弄,我终于找到了一个完整的、可行的解决方案。 (或者看起来是这样。)
步骤 1. 修改 XAML 标记
你需要像这样修改你的 ComboBox:
<ComboBox
...
IsTextSearchEnabled="False"
...
PreviewTextInput="PreviewTextInput_EnhanceComboSearch"
PreviewKeyUp="PreviewKeyUp_EnhanceComboSearch"
DataObject.Pasting="Pasting_EnhanceComboSearch" />
即。 禁用默认文本搜索,并添加将负责用户添加、删除和粘贴文本的事件处理程序。
步骤 2. 添加一个辅助函数,该函数将获取 ComboBox 的内部 TextBox(因为 WPF)
为了让PreviewTextInput_EnhanceComboSearch 和Pasting_EnhanceComboSearch 正常工作,您需要访问您的组合框的插入符号。不幸的是,要做到这一点,您需要遍历,呃,视觉树(hat tip to 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;
}
步骤 3. 实现事件处理程序
请注意我用过
s => s.IndexOf(e.Text, StringComparison.InvariantCultureIgnoreCase) != -1
相当于不区分大小写的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;
}
}
步骤 3.b 在用户粘贴到 ComboBox 时触发搜索
DataObject.Pasting 处理程序的行为方式与PreviewTextInput 处理程序类似,因此我们再次需要插入符号。
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 时触发。
还有空格,因为空格被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;
}
}
}
...应该够了。