I have a listview that can be filtered using a textbox:
<TextBox TextChanged="txtFilter_TextChanged" Name="FilterLv"/>
In the view code-behind I do the following:
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(this.lv.ItemsSource);
view.Filter = UserFilter;
private bool UserFilter(object item)
{
if (String.IsNullOrEmpty(FilterLv.Text))
return true;
else
{
DataModel m = (item as DataModel);
bool result = (m.Name.IndexOf(Filter.Text, StringComparison.OrdinalIgnoreCase) >= 0 ||
//m.Surname.IndexOf(Filter.Text, StringComparison.OrdinalIgnoreCase) >= 0);
return result;
}
}
private void Filter_TextChanged(object sender, TextChangedEventArgs e)
{
CollectionViewSource.GetDefaultView(this.lv.ItemsSource).Refresh();
}
Now I have placed a label in the view and I would like this label to show the number of items currently displayed in the listview.
How can I do it? I have found things like this but I don't understand at all what is RowViewModelsCollectionView. In this link it is suggested to bind as below:
<Label Content="{Binding ModelView.RowViewModelsCollectionView.Count}"/>
Could anyone explain me or provide a very little and simple example on how to do it?
FINAL UPDATE:
View model:
public class TestViewModel
{
// lv is populated later in code
public ObservableCollection<DataModel> lv = new ObservableCollection<DataModel>();
public ObservableCollection<DataModel> LV
{
get
{
return this.lv;
}
private set
{
this.lv= value;
OnPropertyChanged("LV");
}
}
private CollectionView view;
public TestViewModel()
{
this.view = (CollectionView)CollectionViewSource.GetDefaultView(this.LV);
view.Filter = UserFilter;
}
private string textFilter;
public string TextFilter
{
get
{
return this.textFilter;
}
set
{
this.textFilter= value;
OnPropertyChanged("TextFilter");
if (String.IsNullOrEmpty(value))
this.view.Filter = null;
else
this.view.Filter = UserFilter;
}
}
private bool UserFilter(object item)
{
if (String.IsNullOrEmpty(this.TextFilter))
return true;
else
{
DataModel m = (item as DataModel);
bool result = (m.Name.IndexOf(this.TextFilter, StringComparison.OrdinalIgnoreCase) >= 0 ||
//m.Surname.IndexOf(this.TextFilter, StringComparison.OrdinalIgnoreCase) >= 0);
return result;
}
}
/// <summary>
/// Número de registros en la listview.
/// </summary>
public int NumberOfRecords
{
get
{
return this.view.Count;
}
}
}
View (xaml):
<!-- search textbox - filter -->
<TextBox TextChanged="txtFilter_TextChanged"
Text="{Binding TextFilter, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<!-- label to show the number of records -->
<Label Content="{Binding NumberOfRecords}"/>
view code-behind (xaml.cs):
private void txtFilter_TextChanged(object sender, TextChangedEventArgs e)
{
CollectionViewSource.GetDefaultView((DataContext as TestViewModel).LV).Refresh();
}
It is filtering ok when I type in the search textbox and listview is updated correctly but the number of records is always 0.
What am i doing wrong?
ATTEMPT2: Below another attempt not working. If I attach my listivew to the View declared in model view then no items are shown. If I attach listview to LV in model view then items are shown, and when I filter through my search textbox it filters ok, listview is updated but the number of rows shown in the listview always remains to 0.
Notes:
- I am using NET 3.5 Visual Studio 2008.
- I need to set View as writable in model view because I do not set it in view model constructor, instead i set it in LoadData method in view model. LoadData is called from view code-behind constructor.
View Model:
namespace MyTest.Example
{
public Class TestViewModel : INotifyPropertyChanged // Implementations not here to simplify the code here.
{
private ObservableCollection<DataModel> lv;
public ObservableCollection<DataModel> LV
{
get
{
return this.lv;
}
private set
{
this.lv = value;
OnPropertyChanged("LV");
}
}
public CollectionView View { get; set; }
public TestViewModel()
{
this.LV = new ObservableCollection<DataModel>();
// this.View = (CollectionView)CollectionViewSource.GetDefaultView(this.LV);
// this.View.Filter = UserFilter;
}
private string textFilter = string.Empty;
public string TextFilter
{
get
{
return this.textFilter ;
}
set
{
this.textFilter = value;
OnPropertyChanged("TextFilter");
this.View.Refresh();
}
}
private bool UserFilter(object item)
{
if (String.IsNullOrEmpty(this.TextFilter))
return true;
else
{
DataModel m = (item as DataModel);
bool result = (m.Name.IndexOf(this.TextFilter, StringComparison.OrdinalIgnoreCase) >= 0 ||
//m.Surname.IndexOf(this.TextFilter, StringComparison.OrdinalIgnoreCase) >= 0);
return result;
}
}
public void LoadData()
{
this.LV = LoadDataFromDB();
this.View = (CollectionView)CollectionViewSource.GetDefaultView(this.LV);
this.View.Filter = UserFilter;
}
} // End Class
} // End namespace
View code-behing (xaml.cs):
namespace MyTest.Example
{
public Class TestView
{
public TestView()
{
InitializeComponent();
(DataContext as TestViewModel).LoadData();
}
}
}
View (xaml):
xmlns:vm="clr-namespace:MyTest.Example"
<!-- search textbox - filter -->
<TextBox Text="{Binding Path=TextFilter, UpdateSourceTrigger=PropertyChanged}">
<!-- label to show the number of records -->
<Label Content="{Binding Path=View.Count}" ContentStringFormat="No. Results: {0}"/>
<ListView Grid.Row="1" Grid.Column="0" ItemsSource="{Binding Path=View}" SelectionMode="Extended" AlternationCount="2">
ATTEMPT 3: Finally I have get it to work. Solution is the same as ATTEMPT2 but making below changes:
I have replaced this:
public CollectionView View { get; set; }
by this one:
private CollectionView view;
public CollectionView View {
get
{
return this.view;
}
private set
{
if (this.view == value)
{
return;
}
this.view = value;
OnPropertyChanged("View");
}
}
All the rest remains the same as in ATTEMPT2. In view View.Count and assigning View as ItemsSource to my listview now is working all perfectly.