2012-04-10 13 views
5

Editiert: habe ich eine neue VS2010 WPF appilication mit nur 3 Dateien MainWindow.xaml, MainWindow.xaml.cs und MainWindowViewModel.cs (nachfolgend aufgeführt). Wenn sich jemand wirklich hilfreich fühlt, können Sie das Problem in Sekundenschnelle neu erstellen (Kopieren/Einfügen). Wenn Sie die App ausführen, zeigt das DataGrid die Zeichenfolge "OldCollection" an, die falsch ist. Wenn Sie die ItemsSource-Bindung in MyCollection ändern, wird "NewCollection" angezeigt, was korrekt ist.Ändern Collection Quelle in einer MVVM Welt

Volle Beschreibung: Zuerst hatte ich ein DataGrid mit ItemsSource an MyCollection gebunden. Ich habe/brauche eine Methode UpdateCollection, die eine neue ObservableCollection <> MyCollection zuweist. Mit dem Hinzufügen von NotifyPropertyChange zu MyCollection wird die Benutzeroberfläche aktualisiert.

Als nächstes wurde es notwendig, eine CollectionViewSource einzuführen, um die Gruppierung zu ermöglichen. Wenn die Benutzeroberfläche an MyCollectionView gebunden ist, haben Aufrufe von UpdateCollection jetzt keine Auswirkungen mehr. Der Debugger bestätigt, dass MyCollectionView immer die ursprüngliche MyCollection enthält. Wie kann ich meine NewCollection in der Ansicht anzeigen lassen? Ich habe View.Refresh(), Binding CollectionViewSource und unzählige andere Strategien versucht.

Hinweis: In erster Linie betreffen andere die Änderungen an Sammelelementen, die die Ansicht (Gruppierung/Sortierung) nicht aktualisieren, ohne Refresh aufzurufen. Mein Problem ist, dass ich CollectionViewSource eine brandneue Sammlung zuweise und die Ansicht/Benutzeroberfläche sich nie ändert.

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

Danke,

Antwort

4

Ich würde eine der beiden folgenden Lösungen wählen.

Zuerst können Sie Ihre ObservableCollection und erstellen Sie eine ICollectionView (Gruppierung, Sortierung) einmal.Anstelle des ObservableCollection können Sie .Clear() verwenden und die Elemente aus der neuen Collection hinzufügen. Dies hat den zusätzlichen Vorteil, dass Sie Ihre Gruppierung und Sortierung nicht unterbrechen.

Zweiter Ansatz: Wenn Sie Ihre ObservableCollection ersetzen, müssen Sie eine neue ICollectionView zum Sortieren und Gruppieren erstellen.

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

Sie können einfach auf Ihre Sammlung binden, wenn Sie die Standardansicht nehmen

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

und Sie können Ihre Collection Code verbindlich Sachen wegzuwerfen.

0

Das Problem ist auf jeden Fall die Tatsache, dass Sie nicht bindend, die Quelle zu Ihrem MyCollection Eigentum sind, sind Sie es einmal zuweisen und es wird nie wieder aktualisiert.

Sie sollen folgend etwas wie das tun:

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

ich entschuldige mich, wenn die oben nicht sofort ohne Zwicken funktionieren - dies in der Regel ist die Art der Sache, die ich in XAML eingerichtet, weil es viel ist einfacher dort.

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

Siehe auch: How do I change the binding of a CollectionView.Source?

+0

Dieses Problem ist so frustrierend Ich habe die Frage bearbeitet (siehe bearbeiteten Abschnitt), so dass jeder das Problem in Sekunden reproduzieren kann. Gemäß Ihrem Vorschlag habe ich die CollectionViewSource-Bindung zu dem obigen Code hinzugefügt, aber es hatte keine Auswirkungen. – aidesigner

0

Die Tatsache, dass die Bindung nicht funktioniert unglaublich komisch. Ich habe genau das selbe Problem mit der Xceed DataGridCollectionViewSource gefunden - aber ich habe einfach angenommen, dass Xceed fehlerhaft war.

Meine Lösung bestand darin, eine neue DataGridCollectionViewSource jedes Mal zu erstellen, wenn die zugrunde liegende Auflistung ersetzt und programmgesteuert neu konfiguriert wurde, und anschließend die Eigenschaft myDataGrid.Source so zu aktualisieren, dass sie auf die neue DataGridCollectionViewSource verweist. Das Problemumgehung wird sicherlich funktionieren, aber das besiegt völlig den Zweck der Bindungen, die arbeiten sollen:

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

Vielleicht Brute-Force-Lösung Ihr Problem lösen kann? Ich verstehe, wenn du das noch nicht einmal in Betracht ziehen willst, weil es so dreckig ist.

+0

Danke für den Versuch, aber ich bevorzuge etwas anderes für die Gründe, die Sie angegeben haben. Außerdem kann ich nicht auf das x: Key uiMyCollectionGrid von meinem ViewModel mit dem MVVM-Muster zugreifen. Interessanterweise sagt das CollectionViewSource-Dokument http://msdn.microsoft.com/en-us/library/system.windows.data.collectionviewource.aspx, dass Änderungen, die durch das CollectionChanged-Ereignis ausgelöst werden, an die Ansichten weitergegeben werden. Vielleicht ist es das Essen der PropertyChange, die tatsächlich ausgelöst wird, wenn die Eigenschaft MyCollection einen neuen Wert zugewiesen wird. – aidesigner

Verwandte Themen