CollectionViewSource MVVM Implementation for WPF DataGrid
Asked Answered
T

3

12

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.

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 :

  <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.

Therefrom answered 26/9, 2012 at 10:11 Comment(2)
Your code is a little bit misleading, please verify class names. ViewModel, TagViewModel.. so we can better understand.Bunco
Oh sorry @HichemC, actually had renamed the class name while posting the question. Forgot to change it in the code behind. Good observation though. Thanks for drawing my attention.Therefrom
B
23

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.

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);
    }
}
Blend answered 26/9, 2012 at 10:27 Comment(1)
github.com/Fazzani/Solutions/blob/master/Tools/…Icelandic
J
2

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

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.

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

Jefferson answered 28/9, 2012 at 14:10 Comment(0)
B
0

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

Bunco answered 26/9, 2012 at 10:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.