更新项属性更改的ObservableCollection

时间:2015-03-06 07:50:35

标签: vb.net observablecollection

当项目的属性发生变化时,我正试图让ObservableCollection触发CollectionChanged事件。我使用了here中的代码来执行此操作但是我在从C#转换为Vb.net时遇到了错误。在任何情况下item_PropertyChanged都没有被解雇。我在这里缺少什么?

代码:

Imports System.ComponentModel
Imports System.Collections.Specialized
Imports System.Collections.ObjectModel

Class MainWindow

    Public Class TrulyObservableCollection(Of T As INotifyPropertyChanged)
        Inherits ObservableCollection(Of T)
        Public Sub New()
            MyBase.New()
            AddHandler CollectionChanged, AddressOf TrulyObservableCollection_CollectionChanged
        End Sub

        Private Sub TrulyObservableCollection_CollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
            If e.NewItems IsNot Nothing Then
                For Each item As [Object] In e.NewItems
                    AddHandler TryCast(item, INotifyPropertyChanged).PropertyChanged, AddressOf item_PropertyChanged
                Next
            End If
            If e.OldItems IsNot Nothing Then
                For Each item As [Object] In e.OldItems
                    RemoveHandler TryCast(item, INotifyPropertyChanged).PropertyChanged, AddressOf item_PropertyChanged
                Next
            End If
        End Sub

        Private Sub item_PropertyChanged(sender As Object, e As PropertyChangedEventArgs)
            Dim a As New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)
            OnCollectionChanged(a)
        End Sub
    End Class

    Public Class edm
        Implements INotifyPropertyChanged
        Property ip As String
        Property status As String
        Public Sub New(ip As String, status As String)
            Me.ip = ip
            Me.status = status
        End Sub

        Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    End Class

    Public Property edms As New TrulyObservableCollection(Of edm)

    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        DataContext = Me
        edms.Add(New edm("192.168.1.111", "On"))
        edms.Add(New edm("192.168.1.112", "Off"))
        edms.Add(New edm("192.168.1.113", "On"))

    End Sub

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        edms.Where(Function(edm) edm.ip = "192.168.1.111").First().status = "Off"
    End Sub
End Class

编辑:

Bjørn和Liero都提供了很好的答案,在这种情况下,我发现很难将其标记为正确而不是另一个,所以我选择的理由是,当Bjørn的帖子回答了我提出的问题时,我标记了Liero的答案,因为他的评论引导我找到适用于我的方案的最佳解决方案。

2 个答案:

答案 0 :(得分:2)

如果值与支持字段不同,则需要在每个属性的setter中引发属性更改事件。

Public Property Foo() As String
    Get
        Return Me.m_foo
    End Get
    Set(value As String)
        If (value <> Me.m_foo) Then
            Me.m_foo = value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Foo"))
        End If
    End Set
End Property

因此,您的edm课程应该更像这样:

Public Class Edm
    Implements INotifyPropertyChanged

    Public Sub New(ip As String, status As String)
        Me.m_ip = ip
        Me.m_status = status
    End Sub

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Public Property Ip() As String
        Get
            Return Me.m_ip
        End Get
        Set(value As String)
            If (value <> Me.m_ip) Then
                Me.m_ip = value
                Me.NotifyPropertyChanged("Ip")
            End If
        End Set
    End Property

    Public Property Status() As String
        Get
            Return Me.m_status
        End Get
        Set(value As String)
            If (value <> Me.m_status) Then
                Me.m_status = value
                Me.NotifyPropertyChanged("Status")
            End If
        End Set
    End Property

    Private Sub NotifyPropertyChanged(propertyName As String)
        Me.OnPropertyChanged(New PropertyChangedEventArgs(propertyName))
    End Sub

    Protected Overridable Sub OnPropertyChanged(e As PropertyChangedEventArgs)
        RaiseEvent PropertyChanged(Me, e)
    End Sub

    Private m_ip As String
    Private m_status As String

End Class

而且,正如lieroanswer正确指出的那样,您最好覆盖InsertItemSetItemRemoveItem和{{1}而不是处理ClearItems事件。

CollectionChanged

答案 1 :(得分:1)

你是对的,你需要附加每个项目的PropertyChanged事件。但是订阅时你不能依赖于CollectionChanged事件。例如,清除集合时,旧项不在事件参数中。还可以将项目传递给ObservableCollection ctor。

更好的方法是覆盖方法ClearItemsRemoveItemInsertItemSetItem

已经有一些实现,例如:

当然我前段时间写过自己的:) 但由于WPF引入了实时整形,我并不需要它:

编辑:不要忘记在属性发生变化时触发propertychanged事件,就像@Bjørn-RogerKringsjå提议的那样。根据评论,您的问题不在于observablecollection,而在于您的类的INotifyPropertyChanged实现