绑定到ItemSsource时内部会发生什么?

时间:2013-07-31 11:19:34

标签: c# wpf data-binding mvvm itemssource

我很好奇这是如何工作的,因为我有一个MainViewModel,它有一个名为SubViewModel的Property,它有一个ObservableCollection属性(我们称之为Property1。)

我已经在所有内容上实现了INotifyChangedProperty。

我的主窗口

<Window ..
    DataContext="{Binding MainViewModel}" />
...
    <StackPanel DataContext="{Binding SubViewModel}">
        <local:SomeControl DataContext="{Binding}" />
    </StackPanel>
</Window>

我的UserControl

<UserControl Name="SomeControl">
    <DataGrid Name="MyDataGrid" ItemSource="{Binding Property1, Mode=TwoWay}" CurrentCellChanged="TestMethod" />
    ...
</UserControl>

在我的测试方法中,作为一个测试来确定为什么这些更改没有推广到主视图模型我做了类似的事情

private void TestMethod()
{
    var vm = this.DataContext as SubViewModel;

    var itemSourceObservableCollection = MyDataGrid.ItemsSource as ObservableCollection<MyType>;

    //I thought vm.Property1 would be equal to itemSourceObservableCollection
    //but they are not, itemSourceObservableCollection shows the changes I've made
    //vm.Property1 has not reflected any changes made, even though I though they were the same item
}

所以我发现ItemSource必须创建你绑定它的项目的副本?我被困在这里,如何手动通知viewModel此属性已更改并需要更新?我以为那是INotifyPropertyChanged的工作?

我认为我的问题的一部分是我缺乏对这种内部如何运作的理解。如果有人能够指出一篇好的博客文章或文档来帮助我理解为什么我的代码没有按照我的预期运作,那就太棒了。

2 个答案:

答案 0 :(得分:1)

1)没有复制。

2)ObservableCollection将传播对集合所做的更改,而不是集合中的项目。因此,您将看到添加,删除等,但不会对集合中的项目进行属性更改。

3)如果要查看ObservableCollection中对各个项目所做的更改,则需要对这些项目实施INotifyPropertyChanged

答案 1 :(得分:0)

这里实际上有两个不同的问题。绑定到集合时内部会发生什么? AND 为什么用户界面上的更改不会传播回View模型。根据你所写的内容,这两个问题没有关联,但让我们一次一个......

对于第一个问题...绑定集合时,WPF绑定引擎会创建一个“CollectionView”类,它在对象存储和逻辑树之间进行调解。如果需要,您可以使用CollectionViewSource上的静态方法获取“CollectionView”的副本...

var cvs = CollectionViewSource.GetDefaultView(MyCollectionOfThings);

结果中有几个有趣的属性,其中一些包含允许您修改CollectionView的目录的写访问器。

对于第二个问题...... SubViewModel中的业务类需要从INotifyPropertyChanged继承,以便通过WPF绑定引擎“公布”更改。您的VM应该是发布者,但也可以是订阅者。参与INotifyPropertyChanged管道的属性被声明为......

    private string _name;
    [Description("Name of the driver")]
    public string Name
    {
        [DebuggerStepThrough]
        get { return _name; }
        [DebuggerStepThrough]
        set
        {
            if (value != _name)
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }
    }

此代码发布更改,但也可以通过在Xaml中设置适当的属性来订阅在用户界面上所做的更改。

背景阅读:What is a CollectionView? 另外,Similar question