2012-04-10 102 views
5

編輯更改CollectionViewSource來源:我創建了一個新的VS2010 WPF appilication只有3個文件MainWindow.xaml,MainWindow.xaml.cs和MainWindowViewModel.cs(上市下面)。如果有人覺得真的有幫助,可以在幾秒鐘內重新創建問題(複製/粘貼)。當你運行應用程序時,DataGrid將顯示錯誤的字符串「OldCollection」。如果您將ItemsSource綁定更改爲MyCollection,則會顯示「NewCollection」,這是正確的。在MVVM世界

完整描述: 起初我有一個DataGrid,它的ItemsSource綁定到MyCollection。我有/需要一個方法UpdateCollection分配一個新的ObservableCollection <> MyCollection。隨着NotifyPropertyChange添加到MyCollection UI更新。

接下來有必要引入一個CollectionViewSource來啓用分組。通過綁定到MyCollectionView的UI,對UpdateCollection的調用現在不起作用。調試器確認MyCollectionView始終包含最初的MyCollection。我怎樣才能讓我的NewCollection被反映在視圖中?我試過View.Refresh(),綁定CollectionViewSource和其他無數的策略。

注意:其他人主要關心的是收集項目的更改,不更新視圖(分組/排序)而不調用刷新。我的問題是我正在爲CollectionViewSource分配一個全新的集合,並且視圖/ UI從不改變。

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

感謝,

回答

4

我會選擇以下兩種解決方案之一。

首先,您可以帶上您的ObservableCollection並創建一次ICollectionView(分組,排序)。您可以使用.Clear()而不是替換ObservableCollection,並添加新集合中的項目。這有額外的好處,不會破壞你的分組和排序。

第二種方法:無論何時替換ObservableCollection,您都必須創建一個新的ICollectionView進行排序和分組。

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

你可以簡單地綁定到你的收藏,如果你把默認視圖

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

,你可以扔掉CollectionViewSource代碼結合的東西。

0

的問題肯定是,你是不是源綁定到您的MyCollection的屬性,你一旦分配給它的事實,它永遠不會被再次更新。

你應該做一些這樣的:

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

我道歉,如果上面沒有馬上沒有調整工作 - 這通常是的事情,我在XAML中設置的類型,因爲它是多那裏更容易。

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

另請參見:How do I change the binding of a CollectionView.Source?

+0

這個問題讓我非常沮喪,我編輯了這個問題(請參閱編輯部分),以便任何人都可以在幾秒鐘內重現問題。根據你的建議,我添加了CollectionViewSource綁定到上面的代碼,但它沒有效果。 – aidesigner 2012-04-10 19:33:41

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

感謝您的嘗試,但我更喜歡別的因爲您陳述的原因。此外,我無法通過MVVM模式從我的ViewModel訪問x:Key uiMyCollectionGrid。有趣的是,CollectionViewSource文檔http://msdn.microsoft.com/en-us/library/system.windows.data.collectionviewsource.aspx表示「由CollectionChanged事件引發的更改傳播到視圖」。也許它正在吃PropertyChange,它是MyCollection屬性分配一個新值時實際觸發的。 – aidesigner 2012-04-10 20:35:50