WPF中使用MVVM对COMBOBOX进行筛选

3

我正在使用WPF MVVM方法开发一个应用程序。 我有一个要求,需要在组合框中显示一系列项目以供选择。 根据某些标志,我需要过滤掉一些选择项。

我尝试使用两个不同的项目源,一个是完整列表,另一个是过滤列表,并根据标志来改变项目源。 这似乎效果不佳。是否有任何简单的方法可以基于某些标志对现有列表应用过滤器?


什么出了问题?你需要添加更多细节和代码,以确定哪些部分不起作用。 - Rohit Vats
2个回答

7

有很多不同的方法可以实现这个目标,但我个人偏好使用ListCollectionView作为显示已过滤列表的控件的ItemsSource,在ListCollectionView.Filter 上设置一个过滤器谓词,并在过滤参数更改时调用ListCollectionView.Refresh

以下示例将根据其所属的大陆过滤国家列表。

代码:

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

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

谢谢。这种方法对我很有效。非常感谢您节省了我几个小时的时间。非常感激。 - rednerus

2
有没有一种简单的方法,可以根据某个标志在现有列表上应用过滤器?
虽然您的问题不是很清楚,但我认为您不需要维护两个列表来获取筛选数据。您可以使用简单的LINQ进行筛选。假设您有一个ViewModel属性,例如:
public IEnumerable<ComboBoxItem> Data
    {
        get ;
        set ;
    }

如果您想根据一些布尔值进行过滤,那么可以编写类似以下的代码:
ViewModel.Data.ToList().Where(item => item.Status).ToList()

状态可以是布尔值,基于此您可以筛选数据,并将此布尔值添加到您的ComboBoxItem类中。


但是你如何将结果与组合框的“ItemSource”关联起来呢? - Andrew Truckle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接