C# WPF DataGrid 的 CollectionViewSource MVVM 实现

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12599374/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 23:51:10  来源:igfitidea点击:

CollectionViewSource MVVM Implementation for WPF DataGrid

c#wpfmvvmdatagridcollectionviewsource

提问by Lucifer

I have implemented small demo of CollectionViewSource for WPF DataGrid in MVVM. I would really appreciate any help to verify the implementation and comment on whether this is the right approach to use CollectionViewSource.

我已经在 MVVM 中为 WPF DataGrid 实现了 CollectionViewSource 的小演示。我真的很感激任何帮助来验证实现并评论这是否是使用 CollectionViewSource 的正确方法。

public class ViewModel : NotifyProperyChangedBase
{       
    private ObservableCollection<Movie> _movieList;
    public ObservableCollection<Movie> MovieList
    {
        get { return _movieList; }
        set
        {
            if (this.CheckPropertyChanged<ObservableCollection<Movie>>("MovieList", ref _movieList, ref value))
                this.DisplayNameChanged();
        }
    }

    private CollectionView _movieView;
    public CollectionView MovieView
    {
        get { return _movieView; }
        set
        {
            if (this.CheckPropertyChanged<CollectionView>("MovieView", ref _movieView, ref value))
                this.DisplayNameChanged();
        }
    }

    public ViewModel()
    {
          MovieView = GetMovieCollectionView(MovieList);
    }

    private void DisplayNameChanged()
    {
        this.FirePropertyChanged("DisplayName");
    }

    public void UpdateDataGrid(string uri)
    {            
        MovieView = GetMovieCollectionView(new ObservableCollection<Movie>(MovieList.Where(mov => uri.Contains(mov.ID.ToString())).ToList<Movie>()));
    }

    public CollectionView GetMovieCollectionView(ObservableCollection<Movie> movList)
    {
        return (CollectionView)CollectionViewSource.GetDefaultView(movList);
    }

The XAML View :

XAML 视图:

  <Window.Resources>
     <CollectionViewSource x:Key="MovieCollection" Source="{Binding MovieList}">
    </CollectionViewSource>
  </Window.Resources>
   <DataGrid Name="MyDG" 
             ItemsSource="{Binding MovieView}" 
             AutoGenerateColumns="True" />

The Code Behind :

背后的代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.Resources.Add("TagVM", new TagViewModel());
        this.DataContext = this.Resources["TagVM"];
    }

    private void Hyperlink_Click(object sender, RoutedEventArgs e)
    {
        string uri = ((Hyperlink)sender).NavigateUri.ToString();
        ((ViewModel)this.DataContext).UpdateDataGrid(uri);
    }

The Hyperlink_Click handler invokes the UpdateDataGrid method of the VM passing it comma seperated movie IDs which are then used to filter the MovieList collection using extension methods.

Hyperlink_Click 处理程序调用 VM 的 UpdateDataGrid 方法,传递给它逗号分隔的电影 ID,然后使用扩展方法过滤 MovieList 集合。

采纳答案by Per

You should not create new instances of the observable collection and the collection view. Assign a predicate to the filter property on the collecion view and call Refresh whenever you want to filter the collection.

您不应创建可观察集合和集合视图的新实例。为集合视图上的过滤器属性分配一个谓词,并在您想要过滤集合时调用 Refresh。

public class ViewModel : NotifyProperyChangedBase
{       
    string uri;

    public ObservableCollection<Movie> MovieList { get; private set; }

    public CollectionView MovieView { get; private set; }

    public ViewModel(MoveList movieList)
    {
        MovieList = movieList;
        MovieView = GetMovieCollectionView(MovieList);
        MovieView.Filter = OnFilterMovie;
    }

    public void UpdateDataGrid(string uri)
    {     
        this.uri = uri;
        MovieView.Refresh();
    }

    bool OnFilterMovie(object item)
    {
        var movie = (Movie)item;
        return uri.Contains(movie.ID.ToString());
    }

    public CollectionView GetMovieCollectionView(ObservableCollection<Movie> movList)
    {
        return (CollectionView)CollectionViewSource.GetDefaultView(movList);
    }
}

回答by HichemSeeSharp

You can skip adding resources by doing this directly : DataContext = new TagViewModel();and doing your bindings normally. but I highly recommend using Dependency Injection.

您可以通过直接执行此操作来跳过添加资源:DataContext = new TagViewModel();并正常进行绑定。但我强烈推荐使用依赖注入。

回答by BgRva

Here is an example of instantiating a CollectionViewSource in order to enable multi-filtering in a DataGrid: http://www.codeproject.com/Articles/442498/Multi-filtered-WPF-DataGrid-with-MVVM

这是实例化 CollectionViewSource 以在 DataGrid 中启用多重过滤的示例:http: //www.codeproject.com/Articles/442498/Multi-filtered-WPF-DataGrid-with-MVVM

The CollectionViewSource was instantiated in the XAML view but is bound to a collection of objects instantiated in the view model. The view model then uses the CollectionViewSource to filter the data in the DataGrid.

CollectionViewSource 在 XAML 视图中实例化,但绑定到在视图模型中实例化的对象集合。然后视图模型使用 CollectionViewSource 来过滤 DataGrid 中的数据。

As to what is the rightapproach to instantiate a CollectionViewSource - that is debatable.

至于实例化 CollectionViewSource的正确方法是什么- 这是有争议的。