Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# MVVM添加排序描述_C#_Wpf_Sorting_Mvvm - Fatal编程技术网

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>