Не создавайте CollectionViewSource
в вашем представлении. Вместо этого создайте свойство типа ICollectionView
в вашей модели представления и привяжите ListView.ItemsSource
к нему.
Как только вы это сделаете, вы можете поместить логику в установщик свойства FilterText
, который вызывает Refresh()
для ICollectionView
всякий раз, когда пользователь меняет его.
Вы обнаружите, что это также упрощает проблему сортировки: вы можете встроить логику сортировки в модель представления, а затем представить команды, которые представление может использовать.
EDIT
Вот довольно простая демонстрация динамической сортировки и фильтрации представления коллекции с использованием 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
на представлении в 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>