How to Respond to a Collection Changed Event

RogerSchlueter-7899 1,446 Reputation points
2021-08-07T17:38:10+00:00

I have two ObservableCollections, ocOrganization and ocVendoers. The Organization object has a ReadOnly property to signal whether an Organization is also a Vendor:

Public ReadOnly Property IsVendor As Boolean
    Get
        Dim vdr As Vendor = ocVendors.FirstOrDefault(Function(v) v.OrganizationID = clsOrganizationID)
        Return vdr IsNot Nothing
    End Get
End Property

There is a button on the wpf window that displays each organization that allows the user to make an organization also a vendor. When clicked, I want that ReadOnly property to be reevaluated. To do that I have created this event handler:

  Public Sub VendorsCollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
        ????????
    End Sub

So I've got all the pieces in place but I don't know what to replace the "????????" with in the above Sub in order to wire them together. Or is there a different approach altogether that I should be using?

Developer technologies | Windows Presentation Foundation
Developer technologies | VB
{count} votes

2 answers

Sort by: Most helpful
  1. RogerSchlueter-7899 1,446 Reputation points
    2021-08-10T23:19:11.847+00:00
    Public Class Organization
        Implements INotifyPropertyChanged
    
        Public Property OrganizationID As Integer
        <Many more....>
    
        Public ReadOnly Property IsVendor As Boolean
            Get
               Dim vdr As Vendor = ocVendors.FirstOrDefault(Function(v) v.OrganizationID = clsOrganizationID)
               Return vdr IsNot Nothing
            End Get
        End Property
    
        <Other methods>
    
    End Class
    
    
    Public Class Vendor
        Implements INotifyPropertyChanged
    
        Public Property VendorID() As Integer
        Public Property OrganizationID As Integer
        <Many more....>
        <Other methods>
    
    End Class
    

    ocOrganzatiions and ocVendors are the ObservableCollections of those classes.

    On my wpf Window there is a button to make an existing organization a vendor:

    Private Sub AddVendor(sender As Object, e As RoutedEventArgs) Handles btnVendor.Click
        cv = New Vendor With
            {
            .IsActive = True,
            .OrganizationID = co.OrganizationID
            }
        ocVendors.Add(cv)
        pnlVendor.DataContext = cv
    End Sub
    

    cv stands for CurrentVendor. pnlVendor is a stackpanel on the window that contains all the controls for the Vendor properties.

    After AddVendor is invoked, since ocVendors has changed, I expected the ReadOnly Propety IsVendor to be re-evaluated automatically but apparently I have to do it in code and I don't know how to do that.

    I should add that I know I could reove the ":ReadOnly" part and just set IsVendor = True but that seems quite inelegant and unnecessary. I will go that route if there is no other way.

    0 comments No comments

  2. Hui Liu-MSFT 48,681 Reputation points Microsoft External Staff
    2021-08-13T09:48:56.237+00:00

    Maybe I didn't ask clearly at the beginning, I want to confirm whether the change of your isVender property is caused by clsOrganizationID? Do you want to set isVender to true when OrganizationID and clsOrganizationID are equal? If so, you could add RaisePropertyChanged("IsVendor") to the get method of clsOrganizationIDproperty to trigger isVender property change. Like the demo below:
    The code of xaml:

    <StackPanel>  
            <DataGrid Width="400" Height="100" ItemsSource="{Binding OcOrganization, Mode=TwoWay ,UpdateSourceTrigger=PropertyChanged  }" AutoGenerateColumns="False">  
                <DataGrid.Columns>  
                    <DataGridTextColumn Width="Auto" Header="OrganizationID" Binding="{Binding  OrganizationID}"/>  
                    <DataGridTextColumn Width="*" Header="clsOrganizationID" Binding="{Binding clsOrganizationID}"/>  
                    <DataGridTextColumn Width="*" Header="is render" Binding="{Binding IsVendor}"/>  
                </DataGrid.Columns>  
            </DataGrid>  
            <DataGrid ItemsSource="{Binding Orders, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="400" AutoGenerateColumns="False" >  
                <DataGrid.Columns>  
                    <DataGridTextColumn Width="Auto" Header="Name" Binding="{Binding  Name}"/>  
                   <DataGridTextColumn Width="Auto" Header="Price" Binding="{Binding Price}"/>  
                    <DataGridTextColumn Width="Auto" Header="Quantity" Binding="{Binding Quantity}"/>  
                    <DataGridTextColumn Width="Auto" Header="TotalPrice" Binding="{Binding TotalPrice}"/>  
                </DataGrid.Columns>  
            </DataGrid>  
        </StackPanel>  
    

    The code of xaml.vb:

    Imports System.Collections.ObjectModel  
    Imports System.ComponentModel  
    Imports Microsoft.VisualBasic.CompilerServices  
    
    Partial Public Class MainWindow  
        Inherits Window  
    
        Public Sub New()  
            InitializeComponent()  
            Me.DataContext = New ViewModel()  
        End Sub  
        Friend Class ViewModel  
            Implements INotifyPropertyChanged  
    
            Private ocVendorsField As ObservableCollection(Of Vendor)  
    
            Public Property OCVendors As ObservableCollection(Of Vendor)  
                Get  
                    Return ocVendorsField  
    
                End Get  
                Set(ByVal value As ObservableCollection(Of Vendor))  
                    ocVendorsField = value  
                    RaisePropertyChanged("OCVendors")  
                End Set  
            End Property  
    
            Private ocOrganizationField As ObservableCollection(Of Organization)  
    
            Public Property OcOrganization As ObservableCollection(Of Organization)  
                Get  
                    Return ocOrganizationField  
                End Get  
                Set(ByVal value As ObservableCollection(Of Organization))  
                    ocOrganizationField = value  
                    RaisePropertyChanged("OcOrganization")  
                End Set  
            End Property  
    
            Private ordersField As ObservableCollection(Of Order)  
    
            Public Property Orders As ObservableCollection(Of Order)  
                Get  
                    Return ordersField  
                End Get  
                Set(ByVal value As ObservableCollection(Of Order))  
                    ordersField = value  
                    RaisePropertyChanged("OCVendors")  
                End Set  
            End Property  
    
            Public Sub New()  
                ocVendorsField = New ObservableCollection(Of Vendor) From {  
                New Vendor With {  
                    .OrganizationID = 0,  
                    .clsOrganizationID = 1  
                },  
                New Vendor With {  
                    .OrganizationID = 1,  
                    .clsOrganizationID = 1  
                }  
            }  
                ocOrganizationField = New ObservableCollection(Of Organization) From {  
                New Organization With {  
                    .OrganizationID = 1,  
                    .clsOrganizationID = 5,  
                    .OCVendors = ocVendorsField  
                }  
            }  
                ordersField = New ObservableCollection(Of Order) From {  
                New Order() With {  
                    .Name = "apple",  
                    .Price = 1.3,  
                    .Quantity = 4  
                },  
                New Order() With {  
                    .Name = "orange",  
                    .Price = 3.5,  
                    .Quantity = 4  
                }  
            }  
            End Sub  
    
            Public Event PropertyChanged As PropertyChangedEventHandler _  
            Implements INotifyPropertyChanged.PropertyChanged  
    
            Public Sub RaisePropertyChanged(ByVal propertyName As String)  
                Dim handler As PropertyChangedEventHandler = PropertyChangedEvent  
    
                If handler IsNot Nothing Then  
                    handler(Me, New PropertyChangedEventArgs(propertyName))  
                End If  
            End Sub  
        End Class  
    
        Public Class Vendor  
            Implements INotifyPropertyChanged  
    
            Private organizationIDField As Integer  
    
            Public Property OrganizationID As Integer  
                Get  
                    Return organizationIDField  
                End Get  
                Set(ByVal value As Integer)  
                    organizationIDField = value  
                    RaisePropertyChanged("LoOrganizationIDg")  
                End Set  
            End Property  
    
            Private _clsOrganizationID As Integer  
    
            Public Property clsOrganizationID As Integer  
                Get  
                    Return _clsOrganizationID  
                End Get  
                Set(ByVal value As Integer)  
                    _clsOrganizationID = value  
                    RaisePropertyChanged("clsOrganizationID")  
    
                End Set  
            End Property  
    
            Public Event PropertyChanged As PropertyChangedEventHandler _  
            Implements INotifyPropertyChanged.PropertyChanged  
    
            Public Sub RaisePropertyChanged(ByVal propertyName As String)  
                Dim handler As PropertyChangedEventHandler = PropertyChangedEvent  
    
                If handler IsNot Nothing Then  
                    handler(Me, New PropertyChangedEventArgs(propertyName))  
                End If  
            End Sub  
    
            Public Overrides Function ToString() As String  
                Return OrganizationID & " " & clsOrganizationID  
            End Function  
        End Class  
    
        Public Class Organization  
            Implements INotifyPropertyChanged  
    
            Private organizationIDField As Integer  
    
            Public Property OrganizationID As Integer  
                Get  
                    Return organizationIDField  
                End Get  
                Set(ByVal value As Integer)  
                    organizationIDField = value  
                    RaisePropertyChanged("OrganizationID")  
                End Set  
            End Property  
    
            Private ocVendorsField As ObservableCollection(Of Vendor)  
    
            Public Property OCVendors As ObservableCollection(Of Vendor)  
                Get  
                    Return ocVendorsField  
                End Get  
                Set(ByVal value As ObservableCollection(Of Vendor))  
                    ocVendorsField = value  
                    RaisePropertyChanged("OCVendors")  
                End Set  
            End Property  
    
            Private _clsOrganizationID As Integer  
    
            Public Property clsOrganizationID As Integer  
                Get  
                    Return _clsOrganizationID  
                End Get  
                Set(ByVal value As Integer)  
                    _clsOrganizationID = value  
                    RaisePropertyChanged("clsOrganizationID")  
                    RaisePropertyChanged("IsVendor")  
                End Set  
            End Property  
    
            Public ReadOnly Property IsVendor As Boolean  
                Get  
                    Dim vdr As Vendor = OCVendors.FirstOrDefault(Function(v) v.OrganizationID = clsOrganizationID)  
    
                    Return vdr IsNot Nothing  
    
                End Get  
            End Property  
    
            Public Event PropertyChanged As PropertyChangedEventHandler _  
            Implements INotifyPropertyChanged.PropertyChanged  
    
            Public Sub RaisePropertyChanged(ByVal propertyName As String)  
                Dim handler As PropertyChangedEventHandler = PropertyChangedEvent  
    
                If handler IsNot Nothing Then  
                    handler(Me, New PropertyChangedEventArgs(propertyName))  
                End If  
            End Sub  
        End Class  
    
        Public Class Order  
            Implements INotifyPropertyChanged  
    
            Public Event PropertyChanged As PropertyChangedEventHandler _  
            Implements INotifyPropertyChanged.PropertyChanged  
    
            Public Sub RaisePropertyChanged(ByVal propertyName As String)  
                Dim handler As PropertyChangedEventHandler = PropertyChangedEvent  
    
                If handler IsNot Nothing Then  
                    handler(Me, New PropertyChangedEventArgs(propertyName))  
                End If  
            End Sub  
    
            Private nameField As String  
            Private priceField As Double  
            Private quantityField As Integer  
    
            Public Property Name As String  
                Get  
                    Return nameField  
                End Get  
                Set(ByVal value As String)  
    
                    If value IsNot nameField Then  
                        nameField = value  
                        RaisePropertyChanged("Name")  
                    End If  
                End Set  
            End Property  
    
            Public Property Price As Double  
                Get  
                    Return priceField  
                End Get  
                Set(ByVal value As Double)  
    
                    If value <> priceField Then  
                        priceField = value  
                        RaisePropertyChanged("Price")  
                        RaisePropertyChanged("TotalPrice")  
                    End If  
                End Set  
            End Property  
    
            Public Property Quantity As Integer  
                Get  
                    Return quantityField  
                End Get  
                Set(ByVal value As Integer)  
    
                    If value <> quantityField Then  
                        quantityField = value  
                        RaisePropertyChanged("Quantity")  
                    End If  
                End Set  
            End Property  
    
            Public ReadOnly Property TotalPrice As Double  
                Get  
                    Return Price * Quantity  
                End Get  
            End Property  
        End Class  
    End Class  
    

    Demo Result:
    123015-3.gif


    If the response is helpful, please click "Accept Answer" and upvote it.
     Note: Please follow the steps in our [documentation][3] to enable e-mail notifications if you want to receive the related email notification for this thread. 

    [3]: https://learn.microsoft.com/en-us/answers/articles/67444/email-notifications.html

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.