当可观察集合在 VB.NET 中的 WPF 中更改时,INotifyPropertyChanged 事件不会触发

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11847189/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 04:52:57  来源:igfitidea点击:

INotifyPropertyChanged event not firing when Observable Collection changed in WPF in VB.NET

wpfvb.netobservablecollectioninotifypropertychanged

提问by KyleMit

I'm trying to use databinding in WPF with an MVVM pattern. So far, it seems that everything is plumbed up properly and I'm using the right type of classes and objects. My observable collection loads to first time correctly, but won't refresh on the datagrid when it changes. Observable Collections should automatically implement INPC and I've also provided a handler for it in my base class, so I'm confused why it is still not working and updating my UI. Here's my code below:

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

ViewModelBase Class:

视图模型基类:

#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 Class:

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

The GetRecords function is a call to a database that gets the most recent set of records available.

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

In my view, I'm actually binding to a CollectionViewSource and binding that to a datagrid:

在我看来,我实际上是绑定到 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>

The Personclass has properties LastNameand FirstName(amoung others). As I understand it, if the ObservableCollection itself changes - like what I do by clearning and filling it back up, it should automatically fire the INPC event, but my DataGrid doesn't seem to refresh the second time around. Any ideas would be really helpful.

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

Thanks!

谢谢!

*EDIT*Here's how I wound up solving the problem:

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

Public Shared Property CoreInfoData() As ObservableCollection(Of Person)

公共共享属性 CoreInfoData() 作为 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

The First time the Set Method is called it will create a new _coreInfoData variable. Subsequent calls will replace the existing one by clear it's entire contents and looping through each item to add it back into the collection. Thanks to Clemens, Dan Busha, and Charleh (and others) for their helpful comments!

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

回答by Clemens

No PropertyChanged event will be raised automatically simply because the type of a property is ObservableCollection. You would have to raise it in the setter:

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

Set(ByVal value As ObservableCollection(Of Person)) 
    _coreInfoData = value
    OnPropertyChanged("CoreInfoData")
End Set 

回答by Dan Busha

It looks like you're assigning a value to your ObservableCollection which doesn't change your collection it replaces it. Either raise a PropertyChanged event for for the CoreInfoData property or add the items one by one from the setvalue to the ObservableCollection (the ObservableCollection should manage the raising of the PropertyChanged event for you).

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

回答by RichardOD

You are confusing INotifyPropertyChangedwith INotifyCollectionChanged.

您将INotifyPropertyChangedINotifyCollectionChanged混淆了。

ObservableCollection does implement INotifyPropertyChanged, this is used to fire the event for properties like Count and the indexer Item[]. It does not extend to the functionality you require it to achieve.

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

回答by blindmeis

first - why is your collection Shared/static?

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

when working with ObservableColelction then usually you create a instance just once and use clear, add remove.

当使用 ObservableColelction 时,通常你只创建一个实例并使用 clear, add remove.

if you wanna set a new instance like you did in your setter you have to call OnPropertyChanged("CoreInfoData") too.

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

but i would prefer clear and add

但我更喜欢清除并添加

    CoreInfoData.Clear()
    CoreInfoData.AddRange(GetRecords())