当我更新 DataGrid 控件中的数据时,实现 INotifyPropertyChanged 的 ViewModel 的属性是否应该自动更新它们?
我可能对 INotifyPropertyChanged 和 Silverlight 背后的目的感到困惑...
我有在设计器中创建的 XAML:
<UserControl.Resources>
<CollectionViewSource x:Key="theViewSource" d:DesignSource="{d:DesignInstance my:transferObject, CreateList=True}" />
</UserControl.Resources>
以及这个
<Canvas DataContext="{StaticResource theViewSource}">
<sdk:DataGrid ItemsSource="{Binding}" Name="theDataGrid">
<sdk:DataGrid.Columns>
<!-- columns omitted from post -->
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Canvas>
我还有一些代码隐藏:
Private Sub control_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
If Not (System.ComponentModel.DesignerProperties.GetIsInDesignMode(Me)) Then
Dim myCollectionViewSource As System.Windows.Data.CollectionViewSource =
CType(Me.Resources("theViewSource"), System.Windows.Data.CollectionViewSource)
Dim myViewModel As New ViewModels.ViewModelThatHasAnObservableCollectionProperty()
myCollectionViewSource.Source = myViewModel.TheObservableCollection()
End If
End Sub
和一个看起来有点像这样的 ViewModel:
Public Class ViewModelBase
Implements ComponentModel.INotifyPropertyChanged
Protected Sub RaisePropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
Public Class ViewModelThatHasAnObservableCollectionProperty
Inherits ViewModelBase
Public Sub RetrieveCollectionCompletedHandler(ByVal sender As Object, ByVal e As SilverlightConsumableService.RetrieveMyCollectionCompletedEventArgs)
Dim unobservable As List(Of TransferObjects.TheTransferObject) = e.Result
'I was hoping for this next line of code to force a refresh of the DataGrid
TheObservableCollection = New ObservableCollection(Of TransferObjects.transferObject)(unobservable)
End Sub
Public Sub New()
Dim theClient As New SilverlightConsumableService.SilverlightConsumableSoapClient
AddHandler theClient.RetrieveMyCollectionCompleted, AddressOf RetrieveCollectionCompletedHandler
theClient.RetrieveMyCollectionAsync()
End Sub
Private _theObservableCollection As ObservableCollection(Of TransferObjects.transferObject)
Public Property TheObservableCollection() As ObservableCollection(Of TransferObjects.transferObject)
Get
Return _theObservableCollection
End Get
Set(ByVal value As ObservableCollection(Of TransferObjects.transferObject))
_theObservableCollection = value
RaisePropertyChanged("TheObservableCollection")
End Set
End Property
End Class
结果是 Silverlight 呈现数据网格没有结果,因为 TheObservableCollection 尚未由事件处理程序填充。这是可以预料的。我所希望的是,在异步调用 Web 服务之后,TheObservableCollection 的 Setter 被调用,随后 RaisePropertyChanged 也被调用。
我的期望是 Silverlight 会通过将 dataGrid 重新绑定到属性来处理这个问题...使用 INotifyPropertyChanged 的目的不是为了让我不必以编程方式重新绑定网格,还是我对此感到困惑?
I may be confused about the purpose behind INotifyPropertyChanged and Silverlight...
I have XAML that I created in the designer:
<UserControl.Resources>
<CollectionViewSource x:Key="theViewSource" d:DesignSource="{d:DesignInstance my:transferObject, CreateList=True}" />
</UserControl.Resources>
as well as this
<Canvas DataContext="{StaticResource theViewSource}">
<sdk:DataGrid ItemsSource="{Binding}" Name="theDataGrid">
<sdk:DataGrid.Columns>
<!-- columns omitted from post -->
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Canvas>
And I also have some codebehind:
Private Sub control_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
If Not (System.ComponentModel.DesignerProperties.GetIsInDesignMode(Me)) Then
Dim myCollectionViewSource As System.Windows.Data.CollectionViewSource =
CType(Me.Resources("theViewSource"), System.Windows.Data.CollectionViewSource)
Dim myViewModel As New ViewModels.ViewModelThatHasAnObservableCollectionProperty()
myCollectionViewSource.Source = myViewModel.TheObservableCollection()
End If
End Sub
And a ViewModel that looks somewhat like this:
Public Class ViewModelBase
Implements ComponentModel.INotifyPropertyChanged
Protected Sub RaisePropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
Public Class ViewModelThatHasAnObservableCollectionProperty
Inherits ViewModelBase
Public Sub RetrieveCollectionCompletedHandler(ByVal sender As Object, ByVal e As SilverlightConsumableService.RetrieveMyCollectionCompletedEventArgs)
Dim unobservable As List(Of TransferObjects.TheTransferObject) = e.Result
'I was hoping for this next line of code to force a refresh of the DataGrid
TheObservableCollection = New ObservableCollection(Of TransferObjects.transferObject)(unobservable)
End Sub
Public Sub New()
Dim theClient As New SilverlightConsumableService.SilverlightConsumableSoapClient
AddHandler theClient.RetrieveMyCollectionCompleted, AddressOf RetrieveCollectionCompletedHandler
theClient.RetrieveMyCollectionAsync()
End Sub
Private _theObservableCollection As ObservableCollection(Of TransferObjects.transferObject)
Public Property TheObservableCollection() As ObservableCollection(Of TransferObjects.transferObject)
Get
Return _theObservableCollection
End Get
Set(ByVal value As ObservableCollection(Of TransferObjects.transferObject))
_theObservableCollection = value
RaisePropertyChanged("TheObservableCollection")
End Set
End Property
End Class
The result is that Silverlight renders the datagrid with no results because TheObservableCollection hasn't been populated by the event handler yet. That's to be expected. What I was hoping for was that after the asychronous call to the web service, the Setter for TheObservableCollection gets called, and subsequently so does RaisePropertyChanged.
My expectation was that Silverlight would handle this by rebinding the dataGrid to the property... Isn't the purpose behind using INotifyPropertyChanged to make it so that I don't have to rebind the grid programmatically, or am I confused about that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在 Silverlight 中(与 WPF 不同),您无需在服务响应处理程序中分配 ObservableCollection。这将打破绑定。
相反,请清除已绑定的集合并使用服务响应中的项目重新填充它。更新集合将正确引发通知事件。如果重新分配集合的引用,与 UI 元素的绑定将被破坏。
INotifyPropertyChanged 背后的目的是通知所有绑定成员属性的值已更改。对于集合,重新分配引用不算作值更改。更新集合成员的数量即可。同样,只要您调用 PropertyChanged 事件,更改单个属性就会引发通知事件。该接口的目的是为 View 提供一个监听 ViewModel 的契约。
In Silverlight (unlike WPF), you don't assign the ObservableCollection in your service response handler. This will break the binding.
Instead, clear out the already bound collection and re-populate it with the items from your service response. Updating the collection will properly raise the notification events. If you re-assign the collection's reference, the binding to the UI element will be broken.
The purpose behind INotifyPropertyChanged is to inform any bound members that the value of the property changed. In the case of collections, re-assigning the reference does not count as a value change. Updating the number of collection members does. Likewise, changing individual properties will raise the notify events as long as you call the PropertyChanged event. The purpose of the interface is to provide a contract for the View to listen to the ViewModel.