使用ICollectionView过滤ObservableCollection的WPF

5

我有一个ObservableCollection、一个ICollectionView、一个筛选器和两个文本框。

如果我只为一个TextBox使用筛选器,它可以正常工作。但是,如果我添加另一个TextBox并将筛选器绑定到第二个TB上,则筛选会出现问题。

我已尝试使用两个筛选器(不同名称-相同功能),但这也没有起作用。

我认为可能与ObservableCollection有关..

这是我的筛选器:

this.AllUsers.Filter = i =>
{
      if (string.IsNullOrEmpty(this.SearchUsername)) return true;

      User u = i as User;
      return u.Name.StartsWith(this.SearchUsername);
};

我的ICollectionView包含ObservableCollection中的数据:

public ICollectionView AllUsers
{
    get
    {
       return CollectionViewSource.GetDefaultView(UserSource);
    }
}

我的ObservableCollection:

public ObservableCollection<User> UserSource
{
    get
    {
        return _UserSource;
    }
    set
    {
        _UserSource = value; OnPropertyChanged();
    }

}

我正在使用AllUsers.Refresh();在我的字符串属性SearchUsername中更新视图。
ObservableCollection被绑定到一个ListBox,字符串属性被绑定到TextBox。
第二个TextBox也是同样的情况。同一个ObservableCollection被绑定到另一个不同的ListBox,字符串属性(UserName)被绑定到第二个TextBox。
那么有没有简单的方法来解决这个问题呢?

我建议的第一件事是从你的可观察集合中摆脱 set,你想要设置集合中的项目而不是整个集合。 - MikeT
@MikeT 像这样:get{ return _UserSource?? (_UserSource = new ObservableCollection<User>());} - Purger86
如果您使用的是C#6,则使用以下代码:public ObservableCollection<User> UserSource {get;} = new ObservableCollection<User>();。如果您不使用C#6,则使用以下代码:private _UserSource = new ObservableCollection<User>(); public ObservableCollection<User> UserSource {get { return _UserSource ;}} - MikeT
你是否尝试通过两个不同的文本字段的值来筛选集合? - MikeT
@MikeT 是的,完全正确。 - Purger86
2个回答

2
这是一个使用集合视图源的双重过滤器示例。
视图。
<Window x:Class="WpfApplication1.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:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel x:Name="vm" />
    </Window.DataContext>

    <DockPanel >
        <TextBox DockPanel.Dock="Top" Text="{Binding Search1}"/>
        <TextBox DockPanel.Dock="Top" Text="{Binding Search2}"/>
        <ListView ItemsSource="{Binding View}">
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding Property1}" Header="Prop1"/>
                    <GridViewColumn DisplayMemberBinding="{Binding Property2}" Header="Prop1"/>
                </GridView>
            </ListView.View>
        </ListView>
    </DockPanel>
</Window>

模型:

public class DataModel
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
}

视图模型(使用 Prism 和 c#6)

public class ViewModel:BindableBase
{
    public ViewModel()
    {
        for (int i = 0; i < 200; i++)
        {
            Items.Add(new DataModel()
            {
                Property1 = $"{200 - i}:Prop1",
                Property2 = $"{i}:Prop2"
            });
        }
        //add filter
        CollectionViewSource.Filter += (s, e) =>
        {
            var d = e.Item as DataModel;
            if (d != null)
            {
                e.Accepted = (string.IsNullOrEmpty(Search1) || d.Property1.StartsWith(Search1))//search property 1
                            && (string.IsNullOrEmpty(Search2) || d.Property2.StartsWith(Search2));//search property 2
            }
            else
                e.Accepted = false;
        };
        CollectionViewSource.Source = Items;
    }

    public CollectionViewSource CollectionViewSource { get; } = new CollectionViewSource();
    public ICollectionView View => CollectionViewSource.View;



    private string _Search1;

    public string Search1
    {
        get { return _Search1; }
        set
        {
            if (SetProperty(ref _Search1, value))
                View.Refresh();
        }
    }

    private string _Search2;

    public string Search2
    {
        get { return _Search2; }
        set
        {
            //SetProperty defined as if value is different update, raise PropertyChanged and return true, else return false;
            if (SetProperty(ref _Search2, value))
                View.Refresh();
        }
    }

    public ObservableCollection<DataModel> Items { get; } = new ObservableCollection<DataModel>();
}

0
ObservableCollection绑定到ListBox,字符串属性绑定到TextBox...
你应该将ListBox(es)的ItemsSource绑定到ICollectionView属性而不是ObservableCollection属性。实际上,你正在过滤前者。
此外,你应该在视图模型中仅创建一个ObservableCollection和ICollectionView实例,例如在构造函数中,然后从这个单一的ObservableCollection实例添加/删除项目:
public class ViewModel
{
    public ViewModel()
    {
        AllUsers = new ObservableCollection<User>();
        AllUsers = CollectionViewSource.GetDefaultView(UserSource);
        //...
    }

    public ObservableCollection<User> UserSource
    {
        { get; private set; }
    }

    public ICollectionView AllUsers
    {
        { get; private set; }
    }
}

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