2012-04-10 29 views
5

Editado: he creado una nueva appilication VS2010 WPF con sólo 3 archivos MainWindow.xaml, MainWindow.xaml.cs, y MainWindowViewModel.cs (se indican a continuación). Si alguien se siente realmente útil, puede recrear el problema en segundos (copiar/pegar). Cuando ejecutas la aplicación, DataGrid mostrará la cadena "OldCollection", que es incorrecta. Si cambia el enlace ItemsSource a MyCollection, muestra "NewCollection" que es correcto.Cambio CollectionViewSource Fuente en un mundo MVVM

Descripción completa: Al principio tenía un DataGrid con su ItemsSource vinculado a MyCollection. Tengo/necesito un método UpdateCollection que asigna un nuevo ObservableCollection <> a MyCollection. Con la adición de NotifyPropertyChange a MyCollection las actualizaciones de la interfaz de usuario.

A continuación, se hizo necesario introducir un CollectionViewSource para habilitar la agrupación. Con la interfaz de usuario vinculada a MyCollectionView, las llamadas a UpdateCollection ahora no tienen ningún efecto. El depurador confirma que MyCollectionView siempre contiene la MyCollection inicial. ¿Cómo puedo hacer que mi NewCollection se refleje en la Vista? He intentado View.Refresh(), binding CollectionViewSource, y un sinnúmero de otras estrategias.

Nota: Principalmente, otros se preocupan por los cambios en los elementos de la Colección que no actualizan la vista (agrupación/clasificación) sin llamar a Refresh. Mi problema es que estoy asignando una nueva colección a CollectionViewSource y la vista/UI nunca cambia.

// 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; } 
    } 
} 

Gracias,

Respuesta

4

Elegiría una de las dos soluciones siguientes.

Primero, puede tomar su ObservableCollection y crear un ICollectionView (agrupamiento, clasificación) una vez.En lugar de reemplazar el ObservableCollection, puede usar .Clear() y agregar los elementos de la nueva Colección. Esto tiene la ventaja adicional de no romper su agrupación y clasificación.

Segundo enfoque: cada vez que reemplace su ObservableCollection, debe crear un nuevo ICollectionView para ordenar y agrupar.

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

puede simplemente unirse a su colección si se toma el DefaultView

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

y se puede tirar a la basura su código CollectionViewSource material de unión.

0

El problema es, sin duda el hecho de que no son vinculantes para la fuente de su propiedad MiColeccion, estás asignando una vez y nunca se actualiza de nuevo.

Usted debe hacer algo como lo siguiente:

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

Me disculpo si lo anterior no funciona de inmediato sin pellizcar - esto es por lo general el tipo de cosa que creó en XAML, porque es mucho más fácil allí.

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

Ver también: How do I change the binding of a CollectionView.Source?

+0

Este problema es tan frustrante que edité la pregunta (Consulte la sección Editado) para que cualquiera pueda reproducir el problema en segundos. Según su sugerencia, agregué el enlace CollectionViewSource al código anterior, pero no tuvo ningún efecto. – aidesigner

0

El hecho de que la unión no está funcionando es increíblemente raro. Encontré exactamente el mismo problema con Xceed DataGridCollectionViewSource, pero supuse que era porque Xceed estaba equivocado.

Mi solución fue crear realmente una DataGridCollectionViewSource completamente nueva cada vez que se reemplazó la colección subyacente y volver a configurarla programáticamente, y luego actualizar la propiedad myDataGrid.Source para apuntar a la nueva DataGridCollectionViewSource. Esa solución, sin duda va a funcionar, pero que vence por completo el propósito de fijaciones, que debería estar trabajando:

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; 
    } 
} 

Tal vez esta solución fuerza bruta puede resolver su problema? Lo entiendo si ni siquiera quieres considerar esto todavía, ya que es muy sucio.

+0

Gracias por intentarlo, pero prefiero otra cosa por las razones que usted indicó. Además, no puedo acceder a la x: clave uiMyCollectionGrid de mi ViewModel con el patrón MVVM. Curiosamente, el documento CollectionViewSource http://msdn.microsoft.com/en-us/library/system.windows.data.collectionviewsource.aspx dice "los cambios generados por el evento CollectionChanged se propagan a las vistas". Tal vez está comiendo el PropertyChange, que es el que realmente se activa cuando la propiedad MyCollection asigna un nuevo valor. – aidesigner

Cuestiones relacionadas