如何根据输入文本过滤组合框项目? [英] How to filter combobox items based on the input text?

查看:48
本文介绍了如何根据输入文本过滤组合框项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想显示一个组合框,其项目由视图模型提供.组合框应该是可编辑的.根据用户当前输入的文本,应过滤组合框项目.

I would like to display a combo box whose items are supplied by the view model. The combo box should be editable. Based on the text currently input by the user, the combo box items should be filtered.

我正在尝试使用以下解决方案,该解决方案是在该主题的各种资源中指出的(例如,该问题该问题该问题,

I am trying to apply the following solution pointed out in various resources on the topic (such as that question, that question, that article, that question, that blogpost, that tutorial, etc.):

  • 我的视图模型提供了有关项目的集合视图.
  • 我在视图模型中将组合框的 Text 属性双向绑定到 CustomText 属性.
  • 集合视图上的 Filter 谓词设置为根据项目的显示名称是否包含 CustomText 来检查项目.
  • 更改 CustomText 后,将在项目集合视图上调用 Refresh 方法.
  • My view model provides a collection view around the items.
  • I have two-way bound the Text property of the combo box to a CustomText property in my view model.
  • The Filter predicate on the collection view is set to check items based on whether their display name contains the CustomText.
  • When CustomText is changed, the Refresh method on the items collection view is invoked.

我希望每当我修改文本时,它都会更新组合框下拉列表中的项目列表.不幸的是,列表保持不变.

I'd expect this to update the list of items in the combo box dropdown list whenever I modify the text. Unfortunately, the list remains the same.

如果在我的 Filter 谓词中放置一个断点,它将被命中,但是不知何故,并非每个项目都如此.

If I place a breakpoint in my Filter predicate, it gets hit, but somehow, not always for each item.

以下是一个最小的示例:

窗口的Xaml:

<Window x:Class="ComboBoxFilterTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ComboBoxFilterTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ComboBox
            VerticalAlignment="Center"
            ItemsSource="{Binding Items}"
            DisplayMemberPath="Name"
            IsEditable="True"
            Text="{Binding CustomText}"
            IsTextSearchEnabled="False"/>
    </Grid>
</Window>

该窗口的代码背后:

using System.Windows;

namespace ComboBoxFilterTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new MainViewModel();
        }
    }
}

和视图模型(此处为 Item 数据类,通常位于其他位置):

And the view model (here with the Item data class, which would normally reside elsewhere):

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;

namespace ComboBoxFilterTest
{
    public class MainViewModel : INotifyPropertyChanged
    {
        private sealed class Item
        {
            public int Id { get; set; }

            public string Name { get; set; }
        }

        public MainViewModel()
        {
            Items = new CollectionView(items)
            {
                Filter = item =>
                {
                    if (string.IsNullOrEmpty(customText))
                    {
                        return true;
                    }

                    if (item is Item typedItem)
                    {
                        return typedItem.Name.ToLowerInvariant().Contains(customText.ToLowerInvariant());
                    }
                    return false;
                }
            };
        }

        private readonly ObservableCollection<Item> items = new ObservableCollection<Item>
        {
            new Item{ Id = 1, Name = "ABC" },
            new Item{ Id = 2, Name = "ABCD" },
            new Item{ Id = 3, Name = "XYZ" }
        };

        public ICollectionView Items { get; }

        private string customText = "";

        public event PropertyChangedEventHandler PropertyChanged;

        public string CustomText
        {
            get => customText;
            set
            {
                if (customText != value)
                {
                    customText = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CustomText)));

                    Items.Refresh();
                }
            }
        }
    }
}


基本上,我认为我的做法与在另一个问题中所述的 ,但显然,仍然有些不同,因为在我的情况下它不起作用.


Basically, I think I'm doing the same as what is described in another question, but apparently, something is still different as it doesn't work in my case.

请注意,有一点细微的区别是我没有使用 CollectionViewSource.GetDefaultView ,因为我想在同一个集合中拥有多个经过不同过滤的视图,而不是获取默认的 视图.

Note that one slight difference is that I am not using CollectionViewSource.GetDefaultView, as I want to have several differently filtered views on the same collection rather than obtaining the default view.

请注意,作为解决方法,我当然可以自己返回经过适当过滤的可枚举项目,并在每次过滤器更改时为此类可枚举属性触发一个属性更改事件.但是,我知道依赖集合视图是正确的WPF方法,所以我宁愿正确"地进行操作.

Note that as a workaround, I could of course just return the appropriately filtered enumerable of items myself and fire a property changed event for such an enumerable property each time the filter changes. However, I understand relying on collection views is the proper WPF way, so I would prefer to do it "correctly".

推荐答案

为避免出现类似问题,建议的模式是使用 CollectionViewSource 作为绑定源.

The recommended pattern to avoid any problems like the one you are experiencing is to use CollectionViewSource as binding source.

正如文档中也提到的那样,您永远不要手动创建 CollectionView 的实例.您必须根据源集合的实际类型使用特殊的子类型:

As also mentioned in the docs, you should never create instances of CollectionView manually. You have to use a specialized sub-type according to the actual type of the source collection:

"您不应在代码中创建此类[ CollectionView ]的对象.要为仅实现IEnumerable的集合创建集合视图,请创建CollectionViewSource对象,将集合添加到Source属性,然后从View属性获取集合视图. Microsoft Docs:CollectionView

"You should not create objects of this class [CollectionView] in your code. To create a collection view for a collection that only implements IEnumerable, create a CollectionViewSource object, add your collection to the Source property, and get the collection view from the View property." Microsoft Docs: CollectionView

CollectionViewSource 在内部为您进行类型检查,并创建正确初始化的 ICollectionView 实现,该实现适用于实际的源集合.如果默认视图不足,则推荐使用XAML或C#创建的 CollectionViewSource ,它是获取 ICollectionView 实例的一种方法:

CollectionViewSource internally does the type checking for you and creates a properly initialized ICollectionView implementation, that is appropriate for the actual source collection. CollectionViewSource, whether created in XAML or C#, is the recommended way to obtain an instance of ICollectionView, if the default view is not sufficient:

public ICollectionView Items { get; }
public CollectionViewSource ItemsViewSource { get; }

public ctor()
{      
  ObservableCollection<object> items = CreateObservableItems();
  this.ItemsViewSource = new CollectionViewSource() {Source = items};
  this.Items = this.ItemsViewSource.View;
}

这篇关于如何根据输入文本过滤组合框项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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