从绑定源过滤 ListView 项

Filter ListView Items from Binding Source

我的应用显示了一个 ListView,它使用数据绑定来显示包含多个项目的列表。一些变量使用双向绑定,因此更改保存在作为数据上下文的视图模型实例中。这是我的 "main" 视图模型实例,因为它包含所有项目。

现在我想过滤这个列表(包含所有项目)并且只显示部分项目。过去,我在后面的代码中创建了一个新的 viewmodel 实例,并将我想要显示的所有项目从我的主实例复制到新创建的 viewmodel 实例,然后将这个新的 viewmodel 设置为 DataContext。

这工作正常,但是当我更改数据时,它只会保存到新创建的实例而不是主实例。因此,当我更改过滤器时,项目将再次从主实例加载而不会在两者之间进行任何更改。

有什么方法可以过滤视图模型的主要实例吗?我想在主实例上工作,以便自动保存更改。

ViewModel 包含一个我自己的 ObservableCollection class,我只想根据过滤器显示一些要绑定的项目。

In the past, I created a new instance of the viewmodel in the code behind and copied all the items I wanted to show to from my main instance to the newly created instance of the viewmodel and then set this new viewmodel as the DataContext.

我觉得没必要新建一个实例,你可以直接操作你的ObservableCollection获取ListView的来源。

举个例子,我创建了一个包含所有数据的List,并从这个List:

添加数据到ObservableCollection
<Page.DataContext>
    <local:MainPageViewModel x:Name="VM" />
</Page.DataContext>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="4*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <ListView ItemsSource="{x:Bind VM.peopleCollection}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBox Text="{Binding Name, Mode=TwoWay}" />
                    <TextBox Text="{Binding Company, Mode=TwoWay}" />
                    <TextBox Text="{Binding Age, Mode=TwoWay}" />
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    <StackPanel Grid.Row="1">
        <Button Content="Age From 20-29" Click="{x:Bind VM.Age_Filter}" />
        <Button Content="Company AA" Click="{x:Bind VM.Company_Filter}" Margin="0,10" />
        <Button Content="Name Peter" Click="{x:Bind VM.Name_Filter}" />
    </StackPanel>
    <Button Content="Show All" Click="{x:Bind VM.Show_All}" Grid.Row="2" />
</Grid>

代码在MainPageViewModel后面:

public class MainPageViewModel
{
    public MainPageViewModel()
    {
        peopleList.Add(new Person { Name = "Jay", Company = "AA", Age = 25 });
        peopleList.Add(new Person { Name = "Peter", Company = "BB", Age = 35 });
        peopleList.Add(new Person { Name = "Jayden", Company = "AA", Age = 27 });
        peopleList.Add(new Person { Name = "John", Company = "AAC", Age = 26 });
        peopleList.Add(new Person { Name = "Alan", Company = "BB", Age = 45 });
        peopleList.Add(new Person { Name = "Frank", Company = "BB", Age = 29 });
        peopleList.Add(new Person { Name = "Ami", Company = "AA", Age = 24 });
        peopleList.Add(new Person { Name = "Elvis", Company = "AA", Age = 30 });
        peopleCollection.Clear();
        foreach (var person in peopleList)
        {
            peopleCollection.Add(person);
        }
    }

    private static List<Person> peopleList = new List<Person>();

    public ObservableCollection<Person> peopleCollection = new ObservableCollection<Person>();

    public void Age_Filter(object sender, RoutedEventArgs e)
    {
        foreach (var person in peopleList)
        {
            if (person.Age > 29 || person.Age < 20)
                peopleCollection.Remove(person);
        }
    }

    public void Company_Filter(object sender, RoutedEventArgs e)
    {
        foreach (var person in peopleList)
        {
            if (person.Company != "AA")
                peopleCollection.Remove(person);
        }
    }

    public void Name_Filter(object sender, RoutedEventArgs e)
    {
        foreach (var person in peopleList)
        {
            if (person.Name != "Peter")
                peopleCollection.Remove(person);
        }
    }

    public void Show_All(object sender, RoutedEventArgs e)
    {
        peopleCollection.Clear();
        foreach (var person in peopleList)
        {
            peopleCollection.Add(person);
        }
    }
}

classPerson的数据模型中只有三个属性:姓名、公司和年龄。

public class Person : INotifyPropertyChanged
{
    private string _Name;

    public string Name
    {
        get { return _Name; }
        set
        {
            if (value != _Name)
            {
                _Name = value;
                OnPropertyChanged();
            }
        }
    }

    private string _Company;

    public string Company
    {
        get { return _Company; }
        set
        {
            if (value != _Company)
            {
                _Company = value;
                OnPropertyChanged();
            }
        }
    }

    private int _Age;

    public int Age
    {
        get { return _Age; }
        set
        {
            if (value != _Age)
            {
                _Age = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged([CallerMemberName]string propertyName = "")
    {
        if (this.PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

如您所见,我在筛选时从 ObservableCollection 中删除了项目,这将根据上次筛选结果进行筛选。如果你想根据所有项目进行过滤,你可以像这样的代码:

public void Company_Filter(object sender, RoutedEventArgs e)
{
    peopleCollection.Clear();
    foreach (var person in peopleList)
    {
        if (person.Company == "AA")
            peopleCollection.Add(person);
    }
}

通常是这样的:

ICollectionView dataView =
              CollectionViewSource.GetDefaultView(IncList.ItemsSource);
dataView.Filter = o =>
                {
                    EventData t = o as EventData;
                    return t.action == evGroup.action && t.objid == evGroup.objid;
                };
dataView.Refresh();

这种技术在 ListView 上进行过滤操作,而不是在 ItemSource 上进行过滤操作,而且它很方便:您只需像往常一样使用数据源(添加-删除元素),ListView 显示当前视图已过滤。