Не создавайте CollectionViewSource
в вашем представлении. Вместо этого создайте свойство типа ICollectionView
в своей модели представления и привяжите к нему ListView.ItemsSource
.
Как только вы это сделаете, вы можете поместить логику в установщик свойства FilterText
, который вызывает Refresh()
на ICollectionView
всякий раз, когда пользователь его изменяет.
Вы обнаружите, что это также упрощает проблему сортировки: вы можете встроить логику сортировки в модель представления, а затем предоставить команды, которые представление может использовать.
ИЗМЕНИТЬ
Вот довольно простая демонстрация динамической сортировки и фильтрации представления коллекции с использованием MVVM. Эта демонстрация не реализует FilterText
, но как только вы поймете, как все это работает, у вас не должно возникнуть проблем с реализацией свойства FilterText
и предиката, который использует это свойство вместо жестко запрограммированного фильтра, который он использует сейчас.
(Обратите внимание также, что классы модели представления здесь не реализуют уведомление об изменении свойства. Это просто для упрощения кода: поскольку ничто в этой демонстрации на самом деле не изменяет значения свойств, оно не требует уведомления об изменении свойства.)
Сначала класс для ваших предметов:
public class ItemViewModel
{
public string Name { get; set; }
public int Age { get; set; }
}
Теперь модель представления для приложения. Здесь происходят три вещи: во-первых, он создает и заполняет свой собственный ICollectionView
; во-вторых, он предоставляет ApplicationCommand
(см. ниже), который представление будет использовать для выполнения команд сортировки и фильтрации, и, наконец, он реализует метод Execute
, который сортирует или фильтрует представление:
public class ApplicationViewModel
{
public ApplicationViewModel()
{
Items.Add(new ItemViewModel { Name = "John", Age = 18} );
Items.Add(new ItemViewModel { Name = "Mary", Age = 30} );
Items.Add(new ItemViewModel { Name = "Richard", Age = 28 } );
Items.Add(new ItemViewModel { Name = "Elizabeth", Age = 45 });
Items.Add(new ItemViewModel { Name = "Patrick", Age = 6 });
Items.Add(new ItemViewModel { Name = "Philip", Age = 11 });
ItemsView = CollectionViewSource.GetDefaultView(Items);
}
public ApplicationCommand ApplicationCommand
{
get { return new ApplicationCommand(this); }
}
private ObservableCollection<ItemViewModel> Items =
new ObservableCollection<ItemViewModel>();
public ICollectionView ItemsView { get; set; }
public void ExecuteCommand(string command)
{
ListCollectionView list = (ListCollectionView) ItemsView;
switch (command)
{
case "SortByName":
list.CustomSort = new ItemSorter("Name") ;
return;
case "SortByAge":
list.CustomSort = new ItemSorter("Age");
return;
case "ApplyFilter":
list.Filter = new Predicate<object>(x =>
((ItemViewModel)x).Age > 21);
return;
case "RemoveFilter":
list.Filter = null;
return;
default:
return;
}
}
}
Сортировка - отстой; вам необходимо реализовать IComparer
:
public class ItemSorter : IComparer
{
private string PropertyName { get; set; }
public ItemSorter(string propertyName)
{
PropertyName = propertyName;
}
public int Compare(object x, object y)
{
ItemViewModel ix = (ItemViewModel) x;
ItemViewModel iy = (ItemViewModel) y;
switch(PropertyName)
{
case "Name":
return string.Compare(ix.Name, iy.Name);
case "Age":
if (ix.Age > iy.Age) return 1;
if (iy.Age > ix.Age) return -1;
return 0;
default:
throw new InvalidOperationException("Cannot sort by " +
PropertyName);
}
}
}
Для запуска метода Execute
в модели представления используется класс ApplicationCommand
, который представляет собой простую реализацию ICommand
, которая направляет CommandParameter
on кнопки в представлении методу Execute
модели представления. Я реализовал это таким образом, потому что я не хотел создавать кучу RelayCommand
свойств в модели представления приложения, и я хотел сохранить всю сортировку / фильтрацию в одном методе, чтобы было легко увидеть, как это делается.
public class ApplicationCommand : ICommand
{
private ApplicationViewModel _ApplicationViewModel;
public ApplicationCommand(ApplicationViewModel avm)
{
_ApplicationViewModel = avm;
}
public void Execute(object parameter)
{
_ApplicationViewModel.ExecuteCommand(parameter.ToString());
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
}
Наконец, вот MainWindow
для приложения:
<Window x:Class="CollectionViewDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:CollectionViewDemo="clr-namespace:CollectionViewDemo"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<CollectionViewDemo:ApplicationViewModel />
</Window.DataContext>
<DockPanel>
<ListView ItemsSource="{Binding ItemsView}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}"
Header="Name" />
<GridViewColumn DisplayMemberBinding="{Binding Age}"
Header="Age"/>
</GridView>
</ListView.View>
</ListView>
<StackPanel DockPanel.Dock="Right">
<Button Command="{Binding ApplicationCommand}"
CommandParameter="SortByName">Sort by name</Button>
<Button Command="{Binding ApplicationCommand}"
CommandParameter="SortByAge">Sort by age</Button>
<Button Command="{Binding ApplicationCommand}"
CommandParameter="ApplyFilter">Apply filter</Button>
<Button Command="{Binding ApplicationCommand}"
CommandParameter="RemoveFilter">Remove filter</Button>
</StackPanel>
</DockPanel>
</Window>
person
Robert Rossney
schedule
24.06.2011
bool Include(object o)
) в моей модели ViewModel напрямую, поэтому мне не нужно иметь обработчик событий в фоновом коде? - person Pieter Müller   schedule 24.06.2011