Reputation: 87
my app shows a ListView which uses Data Binding to show a list of several items. Some variables use TwoWay binding and thus changes are saved in the viewmodel instance which is the datacontext. This is my "main" instance of the viewmodel as it contains all items.
Now I want to filter this list (which contains all items) and only show a portion of the items. 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.
This worked fine, but when I changed Data it would only save to the newly created instance and not to the main instance. Thus, when I changed the filter the items would again be loaded from the main instance without any changes made in between.
Is there any way to filter my main instance of the view model? I would like to work on the main instance so that changes are saved automatically.
The ViewModel contains an ObservableCollection of my own class, I would like to only show some of the items for binding according to a filter.
Upvotes: 2
Views: 1654
Reputation: 895
Normally it's done like this:
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();
This technique does filtering manipulation on ListView, not on ItemSource and it's convinient: You just use datasource as usual (add-remove elements) and ListView shows current View filtered.
Upvotes: 1
Reputation: 16652
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.
I think it is not necessary to create a new instance, you can directly manipulate your ObservableCollection
for the source of ListView
.
Just for example, I created a List
which contains all the data, and add data to ObservableCollection
from this List
:
<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>
code behind in the 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);
}
}
}
In the data model of class Person
, there are only three properties: Name, Company and Age.
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));
}
}
}
As you can see, I remove the item from ObservableCollection
when filter, this will make the filtering based on the last filter result. If you want to filter based on all the items, you can for example code like this:
public void Company_Filter(object sender, RoutedEventArgs e)
{
peopleCollection.Clear();
foreach (var person in peopleList)
{
if (person.Company == "AA")
peopleCollection.Add(person);
}
}
Upvotes: 2