【问题标题】:What happens internally when you bind to ItemSource?当您绑定到 ItemSsource 时,内部会发生什么?
【发布时间】:2013-07-31 11:19:34
【问题描述】:

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

我已经在所有东西上实现了 INotifyChangedProperty。

我的主窗口

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

还有我的用户控件

<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 的​​工作?

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

【问题讨论】:

  • 更改没有传播到主视图模型 - 什么样的更改? ItemsSource 不支持 Afaik Mode=TwoWay
  • 我认为那是 INotifyPropertyChanged 的​​工作? 不,那只能在另一个方向(ViewModel -> View)工作。
  • @HenkHolterman,wadr,模板项目支持它
  • @GarryVass - TwoWay 适用于单个项目,但您无法通过 ItemsSource 插入/删除。
  • @HenkHolterman,当此属性设置为 true 时,DataGrid 底部会显示一个空白行。用户可以在空白行中输入新项目。添加新行会将项目添加到 ItemsSource。您可以通过处理 InitializingNewItem 事件并以编程方式设置值来设置新项目的默认值。 msdn.microsoft.com/en-us/library/…

标签: c# wpf data-binding mvvm itemssource


【解决方案1】:

1) 没有复制。

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

3) 如果您想查看对 ObservableCollection 中单个项目的更改,您需要在这些项目上实现 INotifyPropertyChanged

【讨论】:

    【解决方案2】:

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

    对于第一个问题...当您绑定一个集合时,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

    【讨论】:

      猜你喜欢
      • 2018-07-15
      • 2017-07-12
      • 1970-01-01
      • 1970-01-01
      • 2011-03-06
      • 2018-10-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多