C# MVVM添加排序描述
我想在我已经实现的两个C# MVVM添加排序描述,c#,wpf,sorting,mvvm,C#,Wpf,Sorting,Mvvm,我想在我已经实现的两个过滤器之上添加排序功能 这就是我的代码目前的样子 XAML <Grid Grid.Row="1"> <StackPanel Orientation="Horizontal"> <Border BorderThickness="1" BorderBrush="Red"> <ComboBox Name="SortComboBox"
过滤器
之上添加排序
功能
这就是我的代码目前的样子
XAML
<Grid Grid.Row="1">
<StackPanel Orientation="Horizontal">
<Border BorderThickness="1" BorderBrush="Red">
<ComboBox
Name="SortComboBox"
SelectionChanged="View_SelectionChanged"
ItemsSource="{Binding sortOptions, Mode=OneWay}"
SelectedValue="{Binding selectedSortOption}"
/>
</Border>
<ComboBox
Name="GenreComboBox"
SelectionChanged="View_SelectionChanged"
ItemsSource="{Binding genreOptions, Mode=OneWay}"
SelectedValue="{Binding selectedGenreOption}"
/>
<TextBox Name="SearchTextBox" Width="154" TextChanged="Search_SelectionChanged" Text="{Binding Path=searchTerm, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Grid>
ViewModel
public MoviePanelViewModel()
{
...
...
this.DisplayMovies = new CollectionViewSource();
this.DisplayMovies.Source = this.Movies;
this.DisplayMovies.Filter += GenreFilter;
this.DisplayMovies.Filter += SearchFilter;
}
private void GenreFilter(object sender, FilterEventArgs e)
{
MediaDetail media = e.Item as MediaDetail;
if (selectedGenreOption != "All" && !media.genre.Contains(selectedGenreOption))
e.Accepted = false;
}
private void SearchFilter(object sender, FilterEventArgs e)
{
MediaDetail media = e.Item as MediaDetail;
if (!media.title.ToLower().Contains(searchTerm.ToLower()))
e.Accepted = false;
}
public void SortMovies()
{
DisplayMovies.SortDescriptions.Clear();
switch (SelectedSortOption)
{
case "A-Z":
DisplayMovies.SortDescriptions.Add(new SortDescription("title", ListSortDirection.Ascending)); break;
case "Z-A":
DisplayMovies.SortDescriptions.Add(new SortDescription("title", ListSortDirection.Descending)); break;
case "Release Date":
DisplayMovies.SortDescriptions.Add(new SortDescription("year", ListSortDirection.Descending)); break;
case "Rating":
DisplayMovies.SortDescriptions.Add(new SortDescription("rating", ListSortDirection.Descending)); break;
}
}
SortComboBox
可能有一个选择值a-Z
,在这种情况下,我将以一种特定的方式进行排序。或者它的值可能是Z-a
,在这种情况下,我将以另一种方式对它进行排序
我的问题是,我应该在哪里添加SortDescriptions
,以及控制应该进行何种排序的逻辑,以确保维护MVVM模式
更新
代码隐藏
private void Sort_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
_moviePanelVM.SortMovies();
}
将我的XAML
更改为:
<ComboBox
Name="SortComboBox"
SelectionChanged="Sort_SelectionChanged"
ItemsSource="{Binding sortOptions, Mode=OneWay}"
SelectedValue="{Binding selectedSortOption}"
/>
这是可行的,但我想知道我是否应该这样做?由于过滤器
只是刷新视图
,但是使用排序
我正在调用视图模型中的一个函数
,我认为您不清楚MVVM设计模式的一些原则。理想情况下,您根本不希望视图上有任何代码隐藏,这包括事件
您需要用命令替换事件
在下面的示例中,我没有在视图上使用任何事件,而是使用命令绑定排序的更改以过滤电影
以下是我正在使用的模型:
public class PropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Movie : PropertyChangedBase
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
OnPropertyChanged("Name");
}
}
}
命令如下:
public class SortChangedCommand : ICommand
{
MoviesViewModel _viewModel;
public SortChangedCommand(MoviesViewModel viewModel)
{
_viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_viewModel.Sort(parameter as string);
}
}
请注意,该命令包含对视图模型的引用,在执行该命令时,它只调用Sort方法
以下是视图模型:
public class MoviesViewModel : PropertyChangedBase
{
public ObservableCollection<Movie> Movies { get; set; }
private ObservableCollection<Movie> _FilteredMovies;
public ObservableCollection<Movie> FilteredMovies
{
get { return _FilteredMovies; }
set
{
_FilteredMovies = value;
//Have to implement property changed because in the sort method
//I am instantiating a new observable collection.
OnPropertyChanged("FilteredMovies");
}
}
public SortChangedCommand SortChangedCommand { get; set; }
public MoviesViewModel()
{
this.Movies = new ObservableCollection<Movie>();
#region Test Data
this.Movies.Add(new Movie()
{
Name = "Movie 1"
});
this.Movies.Add(new Movie()
{
Name = "Movie 2"
});
this.Movies.Add(new Movie()
{
Name = "Movie 3"
});
#endregion
//Copy the movies list to the filtered movies list (this list is displayed on the UI)
this.FilteredMovies = new ObservableCollection<Movie>(this.Movies);
this.SortChangedCommand = new SortChangedCommand(this);
}
public void Sort(string sortOption)
{
switch (sortOption)
{
case "A-Z": this.FilteredMovies = new ObservableCollection<Movie>(this.Movies.OrderBy(x => x.Name)); break;
case "Z-A": this.FilteredMovies = new ObservableCollection<Movie>(this.Movies.OrderByDescending(x => x.Name)); break;
}
}
}
公共类MoviesViewModel:PropertyChangedBase
{
公共可观测收集电影{get;set;}
私人可观测收集过滤视频;
公众可观察收集过滤视频
{
获取{return\u FilteredMovies;}
设置
{
_FilteredMovies=值;
//必须实现属性更改,因为在排序方法中
//我正在实例化一个新的可观察集合。
不动产变更(“FilteredMovies”);
}
}
公共排序更改命令和排序更改命令{get;set;}
公共电影视图模型()
{
this.Movies=新的可观察集合();
#区域测试数据
this.Movies.Add(新电影()
{
Name=“电影1”
});
this.Movies.Add(新电影()
{
Name=“电影2”
});
this.Movies.Add(新电影()
{
Name=“电影3”
});
#端区
//将电影列表复制到过滤后的电影列表(此列表显示在UI上)
this.FilteredMovies=新的ObservableCollection(this.Movies);
this.SortChangedCommand=新的SortChangedCommand(this);
}
公共无效排序(字符串排序)
{
开关(分类)
{
案例“A-Z”:this.FilteredMovies=newobserveCollection(this.Movies.OrderBy(x=>x.Name));break;
案例“Z-A”:this.FilteredMovies=newobserveCollection(this.Movies.OrderByDescending(x=>x.Name));break;
}
}
}
视图模型包含两个列表,一个用于保存所有电影,另一个用于保存已过滤电影的列表。过滤后的电影将显示在UI上
以下是视图:
<Window x:Class="BorderCommandExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:BorderCommandExample"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ViewModels:MoviesViewModel x:Key="ViewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource ViewModel}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Command="{Binding SortChangedCommand}" CommandParameter="A-Z"
Content="A-Z"/>
<Button Command="{Binding SortChangedCommand}" CommandParameter="Z-A"
Content="Z-A"
Grid.Row="1"/>
<ListBox ItemsSource="{Binding FilteredMovies}"
DisplayMemberPath="Name"
Grid.Row="2"/>
</Grid>
注意:我没有使用ComboBox,因为ComboBox控件没有命令的属性,但是您可以轻松地
当您单击任何按钮时,该命令将执行并调用sort方法。然后UI将使用过滤后的电影进行更新
用户界面本身可能不是您想要的,但是使用命令来实现这一点是您需要的。我不确定是否理解。您已经使用了CollectionViewSource
并绑定到selectedSortOption
属性,因此当属性更改时,请清除并为displaymoves
@dkozl创建新的SortDescription
,我已经用当前的方式更新了问题。我只是想知道这样做是否正确。谢谢。假设SortMovies
是MoviePanelViewModel
的一部分,例如,将其移动到selectedSortOption
的setter,而不是从ui调用它。首先,如果您想在问题中保留mvvm标记,我会将其更改为\u moviePanelVM.DisplayMovies.View.Refresh()代码>到实际上是MvvM的东西。其次,是的,这是正确的,因为在xaml
中没有这样做的方法。hth现在我已经通读了您的问题,您的ViewModel
似乎是视图的实际代码?如果是这样的话,除了错误的命名之外,你应该对你所拥有的一切感到满意。但为了将来参考,请看一下本文。这太棒了。谢谢你的例子!我会检查的。太好了,如果你有任何问题,请告诉我。
<Window x:Class="BorderCommandExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:BorderCommandExample"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ViewModels:MoviesViewModel x:Key="ViewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource ViewModel}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Command="{Binding SortChangedCommand}" CommandParameter="A-Z"
Content="A-Z"/>
<Button Command="{Binding SortChangedCommand}" CommandParameter="Z-A"
Content="Z-A"
Grid.Row="1"/>
<ListBox ItemsSource="{Binding FilteredMovies}"
DisplayMemberPath="Name"
Grid.Row="2"/>
</Grid>