在开发具有集合类型属性的自己的UserControl时,Select CompanyName
From tblCompany
left join tblInvoice
ON tblCompany.CompanyID = tblInvoice.CompanyID
Where tblInvoice.CompanyID IS NULL
似乎非常合适,因为它会通知控件有关项目级别的更改。但是,基础ViewModel属性的类型为ObservableCollection<T>
,虽然可以使用List<T>
构建ObservableCollection<T>
,但我不确定双向绑定在该方案中的工作方式。
我查看List<T>
作为参考,但看起来MS家伙并不认为ItemsControl.ItemSource
是出于他们的目的,而是生活在穷人的ObservableCollection
上。我不确定IEnumerable
如何支持项目级更改,因为ItemsControl
没有提供此类通知。
我应该将IEnumerable
,IEnumerable
或List<T>
用于我的收藏属性吗?我应该如何进行双向绑定和收集更改通知?
我的VM包含名为ObservableCollection<T>
的{{1}}类型的属性(List<Point>
是一个复杂的模型级类型,但出于我们的目的,您可以将其视为X,Y坐标) 。 VM在启动时从模型中读取所有点,然后通过Points
属性将它们公开给View层。
我的UserControl显示这些点,并允许用户添加新点或删除现有点。由于UserControl通常不直接绑定到VM,而是提供View可以绑定到底层VM属性的公共属性,因此我在控件中添加了一个名为Point
的属性。在UserControl中Points
后,我相应地更新MyPoints
,但是也需要在底层VM中反映这些更改。
答案 0 :(得分:1)
理想情况下,您希望VM拥有ObservableCollection
- 这可以在每次需要更新时告诉视图。假设您有能力修改VM,我建议您这样做。如果您的VM未包含ObservableCollection
,则您将无法接收项目级更新。
要启用双向绑定,您需要在View中使用依赖项属性(只有依赖项属性(和特别设计的类)才能接受绑定)
在您的视图中(假设它被称为MyControl):
// Provide a dependency property to enable binding
public static readonly DependencyProperty MyPointsProperty = DependencyProperty.Register( "MyPoints", typeof(ObservableCollection<Points>) ,new FrameworkPropertyMetadata( null, FrameworkPopertyMetatdataOptions.None, MyPointsPropertyChangedHandler ) );
// Provide a CLR property for convenience - this will not get called by the binding engine!
public ObservableCollection<Points> MyPoints {
get { return (ObservableCollection<Points>) GetValue( MyPointsProperty ); }
set { SetValue( MyPointsProperty, value ); }
}
//Listen for changes to the dependency property (note this is a static method)
public static void MyPointsPropertyChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e) {
MyControl me = obj as MyControl;
if( me != null ) {
// Call a non-static method on the object whose property has changed
me.OnMyPointsChanged( (ObservableCollection<Points>) e.OldValue, (ObservableCollection<Points>) e.NewValue );
}
}
// ...
// Listen for changes to the property (non-static) to register CollectionChanged handlers
protected virtual void OnMyPointsChanged(ObservableCollection<Points> oldValue, ObservableCollection<Points> newValue) {
if(oldValue!=null){
oldValue.CollectionChanged -= MyCollectionChangedHandler;
}
if( newValue!=null ) {
newValue.CollectionChanged += MyCollectionChangedHandler;
}
}
有了这个,你现在可以做到:
<ns:MyControl MyPoints="{Binding vmPointsCollection}" />
此代码不会按原样运行,但应作为实现提供绑定所需的必要功能的指南。
作为旁注,ItemsControl.ItemsSource
与ItemsControl.Items
一起使用以产生整体效果,Items为ItemCollecton
,其中包含CollectionChanged
个事件。当您设置ItemsSource
,Items
被告知此情况时,请开始关注ItemsSource
中的更改并通过其CollectionChanged
事件报告。
编辑:这个控件的更好实现会有一个IEnumerable作为MyPoints集合的类型,当在处理程序中找到它时,检查它是否实现了INotifyCollectionChanged并适当地附加处理程序