Reputation: 115
I have an ObservableCollection, an ICollectionView, one filter and two TextBoxes. If I'm using the filter just for one TextBox it works fine. If I add another Textbox and bind the filter to the second TB the filtering is struggling.
I've tried it with two filters(different names - same function) this didn't work either.
I think it could be something with the ObservableCollection..
Here is my Filter:
this.AllUsers.Filter = i =>
{
if (string.IsNullOrEmpty(this.SearchUsername)) return true;
User u = i as User;
return u.Name.StartsWith(this.SearchUsername);
};
My ICollectionView which contains data from ObservableCollection:
public ICollectionView AllUsers
{
get
{
return CollectionViewSource.GetDefaultView(UserSource);
}
}
And my ObservableCollection:
public ObservableCollection<User> UserSource
{
get
{
return _UserSource;
}
set
{
_UserSource = value; OnPropertyChanged();
}
}
I'm updating the view with AllUsers.Refresh();
in my string property SearchUsername.
the ObservableCollection is bound to a ListBox and the string Property to the TextBox.
the same for the second TextBox. The same ObservableCollection is bound to a different ListBox and the string property(UserName) is bound to the second TextBox.
So is there an easy way to solve this?
Upvotes: 5
Views: 4968
Reputation: 169200
the ObservableCollection is bound to a ListBox and the string Property to the TextBox...
You should bind the ItemsSource of the ListBox(es) to the ICollectionView property and not to the ObservableCollection property. It is the former that you are actually filtering.
Also, you should create only one instance of the ObservableCollection and the ICollectionView in your view model, for example in the constructor, and then add/remove items from this single instance of the 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; }
}
}
Upvotes: 0
Reputation: 5500
here is an example of a duel filter, using a Collection View Source
View
<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>
Model:
public class DataModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
View Model:(using Prism and 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>();
}
Upvotes: 2