1

我正在尝试在具有 MVVM 模式的 WPF 中使用数据绑定。到目前为止,似乎一切都已正确完成,并且我使用了正确类型的类和对象。我的可观察集合首次正确加载,但在数据网格更改时不会刷新。Observable Collections 应该自动实现 INPC,并且我还在我的基类中为它提供了一个处理程序,所以我很困惑为什么它仍然无法工作并更新我的 UI。下面是我的代码:

视图模型基类:

#Region "INotifyPropertyChanged Members"
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(ByVal propertyName As String)
    VerifyPropertyName(propertyName)
    Dim handler As PropertyChangedEventHandler = PropertyChangedEvent
    If handler IsNot Nothing Then
        Dim e = New PropertyChangedEventArgs(propertyName)
        handler(Me, e)
    End If
End Sub
#End Region

MainWindowViewModel 类:

Public Class MainWindowViewModel
    Inherits ViewModelBase

    Private Shared _coreInfoData As ObservableCollection(Of Person)
    Public Shared Property CoreInfoData() As ObservableCollection(Of Person)
        Get
            Return _coreInfoData
        End Get
        Set(ByVal value As ObservableCollection(Of Person))
            _coreInfoData = value
        End Set

    Public Sub Main()
        If CoreInfoData IsNot Nothing Then
            CoreInfoData.Clear()
        End If
        CoreInfoData = GetRecords()
    End Sub

GetRecords 函数是对获取最新可用记录集的数据库的调用。

在我看来,我实际上是绑定到 CollectionViewSource 并将其绑定到数据网格:

<UserControl.Resources>
    <CollectionViewSource Source="{Binding Path=CoreInfoData, Mode=TwoWay}" x:Key="cvs">
        <CollectionViewSource.GroupDescriptions>
            <dat:PropertyGroupDescription PropertyName="GroupId"/>
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>
</UserControl.Resources>
<DataGrid ItemsSource="{Binding Source={StaticResource cvs}}" AutoGenerateColumns="False" >
    <DataGrid.Columns>
        <DataGridTextColumn Header="Last Name" Binding="{Binding Path=LastName}" IsReadOnly="True" />
        <DataGridTextColumn Header="First Name" Binding="{Binding Path=FirstName}" IsReadOnly="True"/>
    </DataGrid.Columns>
</DataGrid>

该类Person具有属性LastNameFirstName(以及其他)。据我了解,如果 ObservableCollection 本身发生变化 - 就像我通过清除和填充它所做的那样,它应该自动触发 INPC 事件,但我的 DataGrid 似乎没有第二次刷新。任何想法都会非常有帮助。

谢谢!

*编辑* 以下是我解决问题的方法:

公共共享属性 CoreInfoData() As ObservableCollection(Of Person)

Public Shared Property CoreInfoData() As ObservableCollection(Of Person)
    Get
        Return _coreInfoData
    End Get
    Set(ByVal value As ObservableCollection(Of Person))
        If _coreInfoData Is Nothing Then
            'get data
             _coreInfoData = value
        Else
             'refresh data
             _coreInfoData.Clear()
              For i = 0 To value.Count - 1
                    _coreInfoData.Add(value(i))
              Next
        End If
    End Set
End Property

第一次调用 Set 方法时,它将创建一个新的 _coreInfoData 变量。随后的调用将通过清除它的全部内容并循环遍历每个项目以将其重新添加到集合中来替换现有的调用。感谢 Clemens、Dan Busha 和 Charleh(和其他人)的有益评论!

4

4 回答 4

3

不会仅仅因为属性的类型是 就自动引发 PropertyChanged 事件ObservableCollection。您必须在 setter 中提出它:

Set(ByVal value As ObservableCollection(Of Person)) 
    _coreInfoData = value
    OnPropertyChanged("CoreInfoData")
End Set 
于 2012-08-07T13:40:13.307 回答
2

看起来您正在为 ObservableCollection 分配一个值,该值不会更改您的集合,而是替换它。为 CoreInfoData 属性引发 PropertyChanged 事件,或者将set值中的项目一一添加到 ObservableCollection(ObservableCollection 应该为您管理 PropertyChanged 事件的引发)。

于 2012-08-07T13:45:51.587 回答
2

您将INotifyPropertyChangedINotifyCollectionChanged混淆了。

ObservableCollection 确实实现了 INotifyPropertyChanged,这用于触发 Count 和索引器 Item[] 等属性的事件。它不会扩展到您需要它实现的功能。

于 2012-08-07T14:11:34.587 回答
1

首先 - 为什么您的收藏是共享/静态的?

使用 ObservableColelction 时,通常只创建一次实例并使用 clear, add remove。

如果你想像在 setter 中那样设置一个新实例,你也必须调用 OnPropertyChanged("CoreInfoData") 。

但我更喜欢明确并添加

    CoreInfoData.Clear()
    CoreInfoData.AddRange(GetRecords())
于 2012-08-07T13:48:09.233 回答