当我更新 DataGrid 控件中的数据时,实现 INotifyPropertyChanged 的​​ ViewModel 的属性是否应该自动更新它们?

发布于 2024-09-10 19:36:07 字数 3435 浏览 4 评论 0原文

我可能对 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一袭白衣梦中忆 2024-09-17 19:36:08

在 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文