Changing CollectionViewSource in the MVVM World

Edited: I created a new VS2010 WPF application with three files MainWindow.xaml, MainWindow.xaml.cs and MainWindowViewModel.cs ( in the list below ). If someone feels really helpful, you can recreate the problem in seconds (copy / paste). When you start the application, the DataGrid will display the "OldCollection" line, which is incorrect. If you change the binding of ItemsSource to MyCollection, it will display "NewCollection", which is true.

Full Description: First I had a DataGrid with its ItemsSource associated with MyCollection. I need an UpdateCollection method that assigns a new ObservableCollection <> to MyCollection. With the addition of NotifyPropertyChange to MyCollection UI updates.

Then it became necessary to introduce a CollectionViewSource to enable grouping. When the user interface is bound to MyCollectionView, calls to UpdateCollection no longer work. The debugger confirms that MyCollectionView always contains the original MyCollection. How can I get my NewCollection to be reflected in the view? I tried View.Refresh (), Binding CollectionViewSource and many other strategies.

Note. First of all, others relate to changes in the elements of the collection that do not update the view (grouping / sorting) without calling Refresh. My problem is that I am assigning a new collection to CollectionViewSource and the view / user interface never changes.

// MainWindow.xaml
<Window x:Class="CollectionView.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid Name="grid" ItemsSource="{Binding MyCollectionView}" />
    </Grid>
</Window>

//MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;

namespace CollectionView
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel();
        }
    }
}

//MainWindowViewModel.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.ComponentModel;

namespace CollectionView
{
    class MainWindowViewModel : INotifyPropertyChanged
    {
        public MainWindowViewModel()
        {
            MyCollection = new ObservableCollection<MyObject>() { new MyObject() { TestString = "OldCollection" } };

            MyCollectionViewSource = new CollectionViewSource();

            // Bind CollectionViewSource.Source to MyCollection
            Binding MyBind = new Binding() { Source = MyCollection };
            BindingOperations.SetBinding(MyCollectionViewSource, CollectionViewSource.SourceProperty, MyBind);

            // The DataGrid is bound to this ICollectionView
            MyCollectionView = MyCollectionViewSource.View;

            // This assignment here to demonstrate that View/UI does not update to show "NewCollection"
            MyCollection = new ObservableCollection<MyObject>() { new MyObject() { TestString = "NewCollection" } };
        }

        // Collection Property
        // NotifyPropertyChanged added specifically to notify of MyCollection re-assignment
        ObservableCollection<MyObject> _MyCollection;
        public ObservableCollection<MyObject> MyCollection
        {
            get { return _MyCollection; }
            set
            {
                if (value != _MyCollection)
                {
                    _MyCollection = value;
                    NotifyPropertyChanged("MyCollection");
                }
            }
        }

        public CollectionViewSource MyCollectionViewSource { get; private set; }
        public ICollectionView MyCollectionView { get; private set; }

        // Method updates MyCollection itself (Called via ICommand from another ViewModel)
        public void UpdateCollection(ObservableCollection<MyObject> NewCollection)
        {
            MyCollection = NewCollection;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }

    class MyObject
    {
        public string TestString { get; set; }
    }
}

Thank,

+5
source share
3 answers

I would choose one of the following two solutions.

First you can take ObservableCollectionand create ICollectionView(group, sort) once. Instead of replacing, ObservableCollectionyou can use .Clear()and add items from the new collection. This has an added bonus so as not to break your grouping and sorting.

: , ObservableCollection, ICollectionView .

 this._view = (ICollectionView)CollectionViewSource.GetDefaultView(this.MyCollection);

, DefaultView

 <DataGrid Name="grid" ItemsSource="{Binding MyCollection}" />

CollectionViewSource.

+4

, , , MyCollection, , .

- :

MyCollectionViewSource = new CollectionViewSource();
Binding binding = new Binding();
binding.Source = MyCollection;
BindingOperations.SetBinding( MyCollectionViewSource , 
                              CollectionViewSource.SourceProperty, 
                              binding );

, - , xaml, .

<CollectionViewSource Source="{Binding MyCollection}" />

. : CollectionView.Source?

0

, , . Xceed DataGridCollectionViewSource, , , Xceed .

, DataGridCollectionViewSource , , , myDataGrid.Source, DataGridCollectionViewSource. , , , :

void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    //Xceed DataGridCollectionView are terrible and do not update when the bound table changes, so we need to replace them each change.
   if (e.PropertyName == "MyCollection")
   {
       DataGridCollectionView GridView = new DataGridCollectionView(MyViewModel.MyCollection.DefaultView);
       GridView.SortDescriptions.Add(new SortDescription("DataSetID", ListSortDirection.Ascending));
       uiMyCollectionGrid.ItemsSource = GridView;
   }
}

, ? , , .

0

All Articles