关于INotifyPropertyChanged和更新Bindings的困惑

时间:2010-07-07 13:28:18

标签: .net wpf mvvm mvvm-light

据我所知,在ModelView中实现INotifyPropertyChanged,允许在属性被修改的情况下引发PropertyChanged事件。

通过这种方式,应该通知View底层属性已经更改,因此UI应该获取新的更改。

我的理论是否正确?

我面临的问题是我有一个绑定到ViewModel的Infragistics DataGrid。一旦我更改了日期值,我就可以看到如何正确设置ViewModel上的属性并引发事件。但是我没有从外部订阅此活动,UI如何得到通知?

我问这个是因为我认为用户界面根本没有说明。我已经放置了第二个文本框,它将ViewModel绑定到相同的底层Model属性。但是,如果我使用DataGrid修改该属性,TextBox(Mode = OneWay)不会自动更新。

我实际上使用MVVM-Light Frame工作并使用ViewModelBase而不是INotifyPropertyChanged并执行RaisePropertyChanged(...)。但结果应该是相似的。

我是否必须以某种方式手动将TextBox订阅到该事件?

编辑:我已经解决了这个问题,但是没有完全理解为什么会发生这种情况。在回答问题之前,我需要解释一下有关架构的更多信息。 Datgrid绑定到ViewModelA中的propertyA,返回ObservableCollection<ViewModelB>. ViewModelB实际上包含Grid应显示的所有属性。所有这些属性自然会在他们的Setter中触发OnProperyChanged。

TextBox绑定到PropertyB,它也存在于ViewModelA中。但它直接返回一个字符串,因此PerpertyB的底层getter返回:

_cashflowInputs[0].ProjectedDate.ToString();

但是,如果我不将TextBox绑定到此propertyB,但也将它绑定到PropertyA,它可以工作:

很奇怪。我期待它以同样的方式工作。两个属性都存在于同一个ViewModel上并访问相同的private ObservableCollection<ViewModelB>,为什么这很重要?

public ObservableCollection<ViewModelB> PropertyA
        {
            get { return _cashflowInputs;}
        }

        public string PropertyB
        {
            get { return _cashflowInputs[0].ProjectedDate.ToString(); }
        }

卡瓦

3 个答案:

答案 0 :(得分:2)

以下是数据对象实现INotifyPropertyChanged时数据对象与UI元素之间通知如何工作的快速回顾。

1)调用数据对象上的属性设置器来更改属性。

2)在setter中,数据对象更改属性值并引发事件以通知绑定到属性已更改的数据对象的任何UI元素。引发的事件将包含刚刚更改的属性的名称。

3)UI元素处理事件并检查事件参数以确定更改了哪个属性。

4)现在UI元素知道哪个属性已更改,它调用适当的getter来获取最新的属性值,并使用该值更新自身。

所以,在你的例子中。如果更新了属性“ProjectedDate”,则会引发一个事件,将属性名称“ProjectedDate”传递给UI元素。然后,UI元素将调用'ProjectedDate'属性的getter来刷新自身。

如果从未使用属性名称“PropertyB”作为争论引发事件,则UI元素不知道“PropertyB”已更改。因此,如果它绑定到'PropertyB',它将不会使用新值刷新自身。在某些时候,必须使用属性名称“PropertyB”引发事件作为UI元素的事件争论,以确定它需要使用最新的属性值刷新自身。

答案 1 :(得分:0)

您是否在文本框中设置了绑定?

<TextBox Text="{Binding Path=PathToMyValue}"/>

答案 2 :(得分:0)

绑定到DataGrid中数据模板内的控件中的PropertyB将无法工作,因为控件的数据上下文将是ViewModelB。如果要将数据模板中的元素绑定到数据模板上下文之外的某些内容,则需要将其数据上下文设置为其他内容,或者使用元素到元素数据绑定绑定到数据模板之外的内容。