C# 禁用IsTextSearchable的组合框过滤可清除文本

C# 禁用IsTextSearchable的组合框过滤可清除文本,c#,wpf,filter,combobox,C#,Wpf,Filter,Combobox,我在WPF表单中使用了一个组合框,它似乎显示出奇怪的行为,在选择一个下拉项后,文本立即从组合框中清除,然后在组合框中键入文本 首先,对于一些背景信息,我的ComboBox包含ComboBoxItems列表,其内容属性设置为各种字符串值(在我的示例应用程序中,我使用的是水果名称)。组合框本身的所有属性都设置为默认值,但IsEditable属性(设置为true)和IsTextSearchEnabled属性(设置为false)除外 当我从下拉列表中选择一个项目,单击组合框以删除突出显示并将焦点放在单词

我在WPF表单中使用了一个组合框,它似乎显示出奇怪的行为,在选择一个下拉项后,文本立即从组合框中清除,然后在组合框中键入文本

首先,对于一些背景信息,我的ComboBox包含ComboBoxItems列表,其内容属性设置为各种字符串值(在我的示例应用程序中,我使用的是水果名称)。组合框本身的所有属性都设置为默认值,但IsEditable属性(设置为true)和IsTextSearchEnabled属性(设置为false)除外

当我从下拉列表中选择一个项目,单击组合框以删除突出显示并将焦点放在单词末尾,然后键入时,就会出现问题。只要我输入一个字母,文本就会立即删除,我输入的任何新文本都会重新启动过滤器。我希望新文本只是附加到组合框中的现有文本中,但这里的情况并非如此

有趣的是,我可以通过两种方式解决这个问题:

a) 重新启用“IsTextSearchEnabled”。但是,由于各种原因,我不希望启用此属性,主要原因是行为与客户端期望控件的行为不一致

b) 修改过滤器以使用静态值

如果我将过滤器修改为:

if (((ComboBoxItem)o).Content.ToString().StartsWith(combobox.Text, true, null))
致:

然后清除文本行为不再发生。但是,这显然对我没有帮助,因为我想使用组合框的文本作为列表的过滤器


在这种情况下,如何防止文本从控件中删除,同时仍保持过滤和常规控件行为?

我真的不明白为什么不能使用内置搜索功能。对于发布的示例,
IsTextSearchEnabled=“True”
StaysOpenOnEdit=“True”
应获得所需的结果。但我想你有你的理由,可能不想分享你的确切代码

当您第一次聚焦组合框并开始键入nothing时,将选中该选项,您只需过滤项目列表。因此,在组合框失去焦点或实际提交所选值之前,一切都会正常工作。
每当您选择一个项目时,ComboBox都会使用
SelectedItem
属性并将其绑定到选定的ComboBox项目。如果文本随后被更改,并且不再与当前所选项目匹配,则组合框将删除所选项目,实际上将其设置为“无”,从而清除文本。这可以通过将
SelectedValue
声明为组合框的实际文本属性来避免。要使下拉列表仍然正确影响文本,还必须定义
SelectedValuePath
属性

<ComboBox x:Name="comboBox" HorizontalAlignment="Left" SelectedValuePath="Content" SelectedValue="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Text}" VerticalAlignment="Top" Width="120" Margin="121,100,0,0"  IsEditable="True" KeyUp="comboBox_KeyUp" IsTextSearchEnabled="False">
    <ComboBoxItem Content="apple"/>
    <ComboBoxItem Content="banana"/>
    <ComboBoxItem Content="grape"/>
    <ComboBoxItem Content="lemon"/>
    <ComboBoxItem Content="strawberry"/>
</ComboBox>
希望这能帮助您解决当前的问题,我想补充一点,对于类似的问题,有更好的解决方案。它确实涉及到实际的模型绑定,如果您还没有这样做的话,您肯定应该研究这一点

下面是一个WPF自定义过滤组合框的示例,它的可重用性比您当前所做的要多得多


更新:我忘了检查Ctrl、Shift或Alt等修改键


筛选
集合会带来麻烦<代码>组合框尝试将所选项目与
文本
属性同步。当你过滤
使其实际上为空时,组合框显然会想,“哦,没有可能的选择,因此我当前的选择不可能是有效的。我将继续并清除它,以及我的文本。”
组合框
可能不是用于此场景的最佳控件。我建议您寻找一个第三方文本控件,该控件具有自动完成功能,您可以使用它。我可以问一下为什么不使用任何绑定吗?WPF是最常用的,它也可以解决许多类似的问题。这是一个很好的答案,它确实解决了这个问题。但是,导致光标被修改的行为会阻止我使用快捷键(如“Ctrl+A”)选择文本,并立即取消选择文本。正如一些人所问,我之所以使用过滤器,是因为我希望在用户输入框时,无效的下拉项消失,而应用过滤器似乎是最好的方法。我没有想到这一点,很好。我现在没有时间来测试这个,但是你可以检查修改键并以这种方式转义事件。也许您最好使用
KeyDownEvent
我必须将修饰符条件更改为以下条件,并检查修饰符键是否是被按下的键:
if(ctb==null | | |(Keyboard.modifiers.HasFlag(ModifierKeys.Shift)| | Keyboard.modifiers.HasFlag(ModifierKeys.Control)| | Keyboard.modifiers.HasFlag(ModifierKeys.Alt);(e.Key==Key.LeftShift | | e.Key==Key.RightShift | | e.Key==Key.LeftCtrl | | e.Key==Key.LeftAlt | e.Key==Key.righalt){return}
但这样做之后,它看起来就像我需要的那样工作!
if (((ComboBoxItem)o).Content.ToString().StartsWith(combobox.Text, true, null))
if (((ComboBoxItem)o).Content.ToString().StartsWith("ba", true, null))
<ComboBox x:Name="comboBox" HorizontalAlignment="Left" SelectedValuePath="Content" SelectedValue="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Text}" VerticalAlignment="Top" Width="120" Margin="121,100,0,0"  IsEditable="True" KeyUp="comboBox_KeyUp" IsTextSearchEnabled="False">
    <ComboBoxItem Content="apple"/>
    <ComboBoxItem Content="banana"/>
    <ComboBoxItem Content="grape"/>
    <ComboBoxItem Content="lemon"/>
    <ComboBoxItem Content="strawberry"/>
</ComboBox>
private void comboBox_KeyUp(object sender, KeyEventArgs e)
{
    var combobox = (ComboBox)sender;
    var ctb = combobox.Template.FindName("PART_EditableTextBox", combobox) as TextBox;
    if (ctb == null) return;
    var caretPos = ctb.CaretIndex;
    combobox.IsDropDownOpen = true;

    CollectionView itemsViewOriginal = (CollectionView)CollectionViewSource.GetDefaultView(combobox.Items);
    itemsViewOriginal.Filter = ((o) =>
    {
        if (String.IsNullOrEmpty(combobox.Text))
        {
            return true;
        }
        else
        {
            if (((ComboBoxItem)o).Content.ToString().StartsWith(combobox.Text, true, null))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    });

    itemsViewOriginal.Refresh();
    ctb.CaretIndex = caretPos;
}
private void comboBox_KeyUp(object sender, KeyEventArgs e)
{
    var combobox = (ComboBox)sender;
    var ctb = combobox.Template.FindName("PART_EditableTextBox", combobox) as TextBox;
    if (ctb == null) return;
    if (Keyboard.Modifiers.HasFlag(ModifierKeys.Shift) || Keyboard.Modifiers.HasFlag(ModifierKeys.Control) || Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
    return;
    var caretPos = ctb.CaretIndex;
    combobox.IsDropDownOpen = true;

    CollectionView itemsViewOriginal = (CollectionView)CollectionViewSource.GetDefaultView(combobox.Items);
    itemsViewOriginal.Filter = ((o) =>
    {
        if (String.IsNullOrEmpty(combobox.Text))
        {
            return true;
        }
        else
        {
            if (((ComboBoxItem)o).Content.ToString().StartsWith(combobox.Text, true, null))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    });

    itemsViewOriginal.Refresh();
    ctb.CaretIndex = caretPos;
}