使用 MVVM 在 WPF 中进行 COMBOBOX 过滤

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21554569/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:43:11  来源:igfitidea点击:

COMBOBOX filtering in WPF with MVVM

wpfmvvmcomboboxitemssource

提问by rednerus

I am developing an application using WPF mvvm approach. I have a requirement where I have to show a list of items in a combo box for selection. Based on some flag I need to filter out few items from the combo box for selection.

我正在使用 WPF mvvm 方法开发应用程序。我有一个要求,我必须在组合框中显示项目列表以供选择。基于某些标志,我需要从组合框中过滤掉一些项目以供选择。

I tried to use two different items sources one with full list and another with filtered list and based on the flag I wanted to change the items source. This does not seem to be working well. Is there any easy way to apply filters on the existing list based on some flag ?

我尝试使用两个不同的项目源,一个是完整列表,另一个是过滤列表,并根据我想更改项目源的标志。这似乎效果不佳。有没有什么简单的方法可以根据某个标志在现有列表上应用过滤器?

回答by Mark Green

There are lots of different ways to do this but my personal preference is to use a ListCollectionViewas the ItemsSource of the control displaying the filtered list, to set a filter predicate on ListCollectionView.Filterand to call ListCollectionView.Refreshwhen the filter parameters change.

有很多不同的方法可以做到这一点,但我个人的偏好是使用 aListCollectionView作为显示过滤列表的控件的 ItemsSource,设置过滤谓词ListCollectionView.FilterListCollectionView.Refresh在过滤参数更改时调用。

The example below will filter a list of countries based on their continent.

下面的示例将根据大洲过滤国家/地区列表。

Code

代码

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

public class FilteringViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Country> _countries;
    private ContinentViewModel _selectedContinent;

    public ListCollectionView CountryView { get; set; }
    public event PropertyChangedEventHandler PropertyChanged;
    public ObservableCollection<ContinentViewModel> Continents { get; set; } 

    public FilteringViewModel()
    {
        _countries =
            new ObservableCollection<Country>(
                new[]
                    {
                        new Country() { Continent = Continent.Africa, DisplayName = "Zimbabwe" },
                        new Country() { Continent = Continent.Africa, DisplayName = "Egypt" },
                        new Country() { Continent = Continent.Europe, DisplayName = "United Kingdom" }
                    });
        CountryView = new ListCollectionView(_countries);
        CountryView.Filter = o => _selectedContinent == null || ((Country)o).Continent == _selectedContinent.Model;

        Continents = new ObservableCollection<ContinentViewModel>(Enum.GetValues(typeof(Continent)).Cast<Continent>().Select(c => new ContinentViewModel { Model = c}));
    }

    public ContinentViewModel SelectedContinent
    {
        get
        {
            return _selectedContinent;
        }
        set
        {
            _selectedContinent = value;
            OnContinentChanged();
            this.OnPropertyChanged("SelectedContinent");
        }
    }

    private void OnContinentChanged()
    {
        CountryView.Refresh();
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class Country
{
    public string DisplayName { get; set; }
    public Continent Continent { get; set; }
}

public enum Continent
{
    [Description("Africa")]
    Africa,
    Asia,
    Europe,
    America
}

public class ContinentViewModel
{
    public Continent Model { get; set; }
    public string DisplayName
    {
        get
        {
            return Enum.GetName(typeof(Continent), Model);
        }
    }
}

XAML

XAML

<StackPanel Orientation="Vertical">
    <ComboBox ItemsSource="{Binding Continents}" SelectedItem="{Binding SelectedContinent}" DisplayMemberPath="DisplayName" />
    <ListBox ItemsSource="{Binding CountryView}" DisplayMemberPath="DisplayName" />
</StackPanel>

回答by Mukesh Rawat

Is there any easy way to apply filters on the existing list based on some flag ?

有没有什么简单的方法可以根据某个标志在现有列表上应用过滤器?

Although your question is not clear, but I think you don't need to maintain two list just to get the filter data. You can use simple LINQ to do the filtering. Suppose if you have a ViewModel Property like

虽然你的问题不清楚,但我认为你不需要维护两个列表来获取过滤器数据。您可以使用简单的 LINQ 进行过滤。假设你有一个 ViewModel 属性,比如

public IEnumerable<ComboBoxItem> Data
    {
        get ;
        set ;
    }

And you want to filter that based on some bool values then you can write something like

并且您想根据一些 bool 值对其进行过滤,然后您可以编写类似的内容

ViewModel.Data.ToList().Where(item => item.Status).ToList()

Status can be the bool based on that you want to filter your data and you can add this bool inside your ComboBoxItem class.

Status 可以是基于您要过滤数据的 bool,您可以在 ComboBoxItem 类中添加此 bool。