c# - 在 MVVM 世界中更改 CollectionViewSource 源

标签 c# wpf data-binding mvvm observablecollection

已编辑:我创建了一个新的 VS2010 WPF 应用程序,其中只有 3 个文件 MainWindow.xaml、MainWindow.xaml.cs 和 MainWindowViewModel.cs(在下面列出)。如果有人觉得真的有帮助,您可以在几秒钟内重现问题(复制/粘贴)。当您运行该应用程序时,DataGrid 将显示错误的字符串“OldCollection”。如果您将 ItemsSource 绑定(bind)更改为 MyCollection,它会显示正确的“NewCollection”。

完整描述: 起初我有一个 DataGrid,其 ItemsSource 绑定(bind)到 MyCollection。我有/需要一个方法 UpdateCollection,它将一个新的 ObservableCollection<> 分配给 MyCollection。通过将 NotifyPropertyChange 添加到 MyCollection,UI 会更新。

接下来有必要引入一个 CollectionViewSource 来启用分组。将 UI 绑定(bind)到 MyCollectionView 后,对 UpdateCollection 的调用现在无效。调试器确认 MyCollectionView 始终包含初始 MyCollection。如何让我的 NewCollection 反射(reflect)在 View 中?我尝试过 View.Refresh()、绑定(bind) CollectionViewSource 和无数其他策略。

注意:主要是其他人关注的是对集合项的更改,而不是在不调用刷新的情况下更新 View (分组/排序)。我的问题是我将一个全新的集合分配给 CollectionViewSource 并且 View /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; }
    }
}

谢谢,

最佳答案

我会选择以下两种解决方案之一。

首先,您可以使用 ObservableCollection 并创建一次 ICollectionView(分组、排序)。您可以使用 .Clear() 并添加新集合中的项目,而不是替换 ObservableCollection。这样做的额外好处是不会破坏您的分组和排序。

第二种方法:每当您替换 ObservableCollection 时,您都必须创建一个新的 ICollectionView 用于排序和分组。

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

如果你使用 DefaultView,你可以简单地绑定(bind)到你的集合

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

你可以扔掉你的 CollectionViewSource 代码绑定(bind)的东西。

关于c# - 在 MVVM 世界中更改 CollectionViewSource 源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10093579/

相关文章:

c# - 如果单元格的内容大于其宽度,如何在 DataGrid 中显示省略号?

javascript - 将数据从浏览器发送到服务器并返回

c# - WPF 数据绑定(bind)标签内容

c# - 如何从数据库表中提取浮点值并将其分配给 asp.net C# 中的 double 类型变量?

c# - 将 unicode 字符的十六进制序列解码为字符串的最佳方法

c# - 如何跳过类中接口(interface)的实现

.net - 如何在执行 DataBind 之前对 DataSet 进行排序?

c# - 使用 NUnit+Reflection,在我的 ActiveX 控件上找不到任何事件

c# - MVVM Light RelayCommand 参数

c# - 如何实现异步 INotifyPropertyChanged