Hi,
INotifyPropertyChanged can be used wherever changes are to be reported to the user of an object. This can be in the ViewModel to update the UI. This can also be necessary in data objects if the collection does not forward changes in properties of a data object, but this is necessary, e.g. to update the UI. INotifyPropertyChanged can also be used to report changes in values of the properties of a data object to the business logic so that it can react to the changes.
Example for forwarding NotifyPropertyChanged in data objects to UI:
Imports System.Collections.ObjectModel
Imports System.Collections.Specialized
Imports System.ComponentModel
''' <summary>
''' Implements the "ItemPropertyChanged" Event for a ObservableCollection
''' </summary>
''' <typeparam name="T"></typeparam>
''' <seealso cref="System.Collections.ObjectModel.ObservableCollection(Of T)" />
Public NotInheritable Class TrulyObservableCollection(Of T As INotifyPropertyChanged)
Inherits ObservableCollection(Of T)
Implements ICollectionItemPropertyChanged(Of T)
''' <summary>
''' Initializes a new instance of the <see cref="TrulyObservableCollection(Of T)"/> class.
''' </summary>
Public Sub New()
AddHandler CollectionChanged, AddressOf FullObservableCollectionCollectionChanged
End Sub
''' <summary>
''' Initializes a new instance of the <see cref="TrulyObservableCollection(Of T)"/> class.
''' </summary>
''' <param name="pItems">The p items.</param>
Public Sub New(pItems As IEnumerable(Of T))
MyClass.New
For Each itm In pItems
Me.Add(itm)
Next
End Sub
Public Event ItemChanged As EventHandler(Of ItemChangedEventArgs(Of T)) Implements ICollectionItemPropertyChanged(Of T).ItemChanged
''' <summary>
''' Fulls the observable collection collection changed.
''' </summary>
''' <param name="sender">The sender.</param>
''' <param name="e">The <see cref="NotifyCollectionChangedEventArgs"/> instance containing the event data.</param>
Private Sub FullObservableCollectionCollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
If e.NewItems IsNot Nothing Then
For Each itm In e.NewItems
AddHandler CType(itm, INotifyPropertyChanged).PropertyChanged, AddressOf ItemPropertyChanged
Next
End If
If e.OldItems IsNot Nothing Then
For Each itm In e.OldItems
RemoveHandler CType(itm, INotifyPropertyChanged).PropertyChanged, AddressOf ItemPropertyChanged
Next
End If
End Sub
''' <summary>
''' Items the property changed.
''' </summary>
''' <param name="sender">The sender.</param>
''' <param name="e">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
Private Sub ItemPropertyChanged(sender As Object, e As PropertyChangedEventArgs)
Dim args As New CollectionItemPropertyChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf(CType(sender, T)), e.PropertyName)
OnCollectionChanged(args)
End Sub
End Class
Friend Interface ICollectionItemPropertyChanged(Of T)
Event ItemChanged As EventHandler(Of ItemChangedEventArgs(Of T))
End Interface
Public Class ItemChangedEventArgs(Of T)
Public ReadOnly Property ChangedItem As T
Public ReadOnly Property PropertyName As String
Public Sub New(item As T, propertyName As String)
Me.ChangedItem = item
Me.PropertyName = propertyName
End Sub
End Class
Public Class CollectionItemPropertyChangedEventArgs
Inherits NotifyCollectionChangedEventArgs
Public Sub New(action As NotifyCollectionChangedAction, newItem As Object, oldItem As Object, index As Integer, itemPropertyName As String)
MyBase.New(action, newItem, oldItem, index)
If itemPropertyName Is Nothing Then Throw New ArgumentNullException(NameOf(itemPropertyName))
PropertyName = itemPropertyName
End Sub
''' <summary>
''' Gets the name of the collection item's property that changed.
''' </summary>
''' <returns>The name of the collection item's property that changed.</returns>
Public Overridable ReadOnly Property PropertyName As String
End Class
'Using this Event
'Public Class Demo
' Private WithEvents c As New TrulyObservableCollection(Of Demo2)
' Private Sub c_CollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs) Handles c.CollectionChanged
' Dim e1 = TryCast(e, CollectionItemPropertyChangedEventArgs)
' If e1 Is Nothing Then Exit Sub
' If e1.PropertyName = "SomeProperty" Then
' ' deal with item property change
' End If
' End Sub
'End Class
'Public Class Demo2
' Implements INotifyPropertyChanged
' Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
'End Class
Or another implementation in C#:NET
public sealed class TrulyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
public TrulyObservableCollection() => CollectionChanged += FullObservableCollectionCollectionChanged;
public TrulyObservableCollection(IEnumerable<T> pItems) : this()
{
foreach (var item in pItems) this.Add(item);
}
private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null) foreach (Object item in e.NewItems) ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
if (e.OldItems != null) foreach (Object item in e.OldItems) ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
}
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e) => OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender)));
}