Reputation: 2965
I'm getting stuck into MVVM in WPF and I have setup an ObservableCollection
and an ICollectionView
. The ICollectionView
is set as the ItemsSource of a DataGrid
, and the model is a type of Job
.
I've setup getters and setter for both of the collections however when I am setting a Filter
on the ICollectionView
instead of the Job
being filtered by the SearchString
they're just replicated over and over again, leading me to believe that they way I have the collections setup is totally wrong.
Here is how the two collections are get/set:
public ObservableCollection<Job> AllJobs
{
get
{
foreach (var job in _allJobsList)
_allJobs.Add(job);
return _allJobs;
}
set
{
if (_allJobs == value) return;
OnPropertyChanged("AllJobs");
}
}
public ICollectionView AllJobsView
{
get
{
_allJobsView = CollectionViewSource.GetDefaultView(AllJobs);
return _allJobsView;
}
set
{
if (_allJobsView == value)
{
return;
}
_allJobsView = value;
OnPropertyChanged("AllJobsView");
}
}
Now I have a stringcalled SearchString
that is bound to a TextBox.Text
. When the text changes I do the following:
public string SearchString
{
get => _searchString;
set
{
if (_searchString == value) return;
_searchString = value;
FilterJobs();
OnPropertyChanged("SearchString");
}
}
private void FilterJobs()
{
AllJobsView.Filter = x =>
{
var viewJob = x as Job;
return viewJob != null && viewJob.Number.Contains(_searchString);
};
}
Now when the page first loads, there are the correct Jobs
loaded into the DataGrid
. However, as soon as the user types the Jobs
are duplicated if the Job.Number
does contain the SearchString
. How am I able to setup the collections so that I can appropriately set a filter?
Upvotes: 0
Views: 301
Reputation: 703
The problem is in the getter of your ObservableCollection. Every time you "get" the collection, you are adding every item to the collection all over again.
Your code:
get
{
foreach (var job in _allJobsList)
_allJobs.Add(job);
return _allJobs;
}
Instead, it should be:
get
{
return _allJobs;
}
The setter of your ObservableCollection is also missing the "setter" (private field = value) code:
set
{
if (value != _allJobs)
{
_allJobs = value;
OnPropertyChanged("AllJobs");
}
}
Your Property AllJobs would then be:
private ObservableCollection<Job> _allJobs;
public ObservableCollection<Job> AllJobs
{
get
{
return _allJobs;
}
set
{
if (value != _allJobs)
{
_allJobs = value;
OnPropertyChanged("AllJobs");
}
}
}
The initialization of your collection should be someplace else (and not in the getter of your property), like in the constructor of the ViewModel or/and in a method that a command calls after the user asks for a refresh of the collection.
For example, if your VieModel is called MyViewModel
and your List<Job>
is called _allJobsList, you can initialize your collection like so:
public MyViewModel()
{
//fill the _allJobsList first, getting from a database for example: _allJobsList = GetJobs();
//and then create an observable collection from that list
AllJobs = new ObservableCollection<Job>(_allJobsList);
}
Upvotes: 1