首页 > 解决方案 > 尝试根据另一个 ComboBox 值将绑定的 ObservableCollection 过滤到组合框不起作用

问题描述

我看到了其他几篇关于此的帖子,但我似乎无法确切了解如何使其正常工作以供我使用。

简而言之,这就是我所拥有的。

我有两个组合框——角色和位置。

我将这两个绑定到一个 ObservableCollection,它在实例化时将枚举值转换为加载到其中的字符串。

<ComboBox  x:Name="empRoleCB" ItemsSource="{Binding Role}" SelectedItem="{Binding RoleStr}"/>
<ComboBox  x:Name="empPositionCB" ItemsSource="{Binding Pos}" SelectedItem="{Binding PosStr}"/>

在我的视图模型中:

public abstract class EmployeeMenuVMBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
    {
        if(!EqualityComparer<T>.Default.Equals(field, newValue))
        {
            field = newValue;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            return true;
        }
        return false;
    }
}

class EmployeeMenuVM : EmployeeMenuVMBase
{
    private ObservableCollection<string> _pos = new ObservableCollection<string>(Enum.GetNames(typeof(Global.Positions)));
    private ObservableCollection<string> _role = new ObservableCollection<string>(Enum.GetNames(typeof(Global.Roles)));
    public ObservableCollection<string> Pos { get => _pos; }
    public ObservableCollection<string> Role { get => _role; }
    public string RoleStr
    {
        get => _roleStr;
        set => SetProperty(ref _roleStr, value);
    }
    public string PosStr
    {
        get => _posStr;
        set => SetProperty(ref _posStr, value);
    }
}

What I want to happen is when a Role is selected, based on that selection, only certain Positions should be shown. 例如,如果我选择“客户服务”作为角色,那么职位应该只包含“经理”、“CSS”和“无”。如果 Role 是“Admin”,那么 Position 应该只包含“None”,依此类推。

我的斗争是如何正确过滤这个。我看到了使用 CollectionViewSource 的一些东西,但我不确定如何让它与我的示例一起使用。
我有 5 个角色,每个角色都有不同的需要显示的职位列表。

使用 MINIMAL 额外代码或 XAML 进行这项工作的最佳方法是什么?

我真正不喜欢 WPF 的一件事是看似简单的事情需要大量代码才能使它们多次正常工作。

标签: c#wpfobservablecollectioncollectionviewsource

解决方案


首先,如果您认为 WPF 很复杂。所以,你用错了。

我建议你使用CollectionViewSource过滤器作为流:

<ComboBox  x:Name="empPositionCB" ItemsSource="{Binding MyPositionFilter}" SelectionChanged="RoleComboBox_SelectionChanged" ....../>


public ICollectionView MyPositionFilter { get; set; }

//ctor
public MyUserControlOrWindow()
{
    //Before InitComponent()
    this.MyPositionFilter = new CollectionViewSource { Source = MyPosObservableCollection }.View;


    InitComponent();
}

public void RoleComboBox_SelectionChanged(object sender,EventArgs e)
{
    //Get the selected Role (the ? is to prevent NullException (VS 2015 >))
    Role r = empRoleCB.SelectedItem as Role;

    //Apply the filter
    this.MyPositionFilter.Filter = item =>
    {
        //Make you sure to convert correcteley your Enumeration, I used it here like a class
        Position p = item as Position;

        //Put your condition here. For example:
        return r.ToLowers().Contains(p.ToLower());

        //Or

        return (r != null && r.Length >= p.Length);
    };
}

过滤器不会更改您的集合,所有隐藏的项目都保留在您的 ObservableCollection 中。


推荐阅读