Ways to trigger a sub on all objects in the list?

Hobbyist_programmer 621 Reputation points
2021-08-15T20:55:32.53+00:00

Hallo,

I have a following class and i have a List of Box. In the form i have option to change Unit system to SI or Imperial. I have a Boolean property and String property called UnitChanged and Unit. In the form start SI will be set as default unit. if user change the unit by clicking a button Unit property will be set to "SI" or "IM" and UnitChanged will be set to True and i want all the Length and Width values has to be converted to Imperial unit and vice versa.

I am looking for a way to trigger a sub when user changes the Unit in the form. Is there a way i can trigger it for all the objects in the list?

I can listen to the unitchange by using readonly property in the Box object but with readonly property i cant execute the sub.

Public Class Box

    Public Property Length As Integer
    Public Property Width As Integer

    Public Sub ChangeUnit()
        If Form1.UnitChanged Then
            If Form1.Unit.Equals("SI") Then
                Length = Length * 25.400013716
            Else
                Length = Length * 0.0393701
            End If
        Else
    End Sub

End Class

Thanks

Developer technologies | VB
0 comments No comments
{count} votes

Accepted answer
  1. Karen Payne MVP 35,586 Reputation points Volunteer Moderator
    2021-08-16T10:03:46.357+00:00

    Here is a possible solution (full source)

    123593-boxes.png

    Unit types

    Namespace Classes  
    	Public Enum Unit  
    		SI  
    		IM  
    	End Enum  
    End Namespace  
    

    Container

    Imports System.ComponentModel  
    Imports System.Runtime.CompilerServices  
      
    Namespace Classes  
    	Public Class Box  
    		Implements INotifyPropertyChanged  
      
    		Private _unit As Unit  
    		Private _length As Double  
      
    		Public Property Length() As Double  
    			Get  
    				Return _length  
    			End Get  
    			Set  
    				_length = Value  
    			End Set  
    		End Property  
      
    		Public Property Width() As Integer  
      
    		Public Property Unit() As Unit  
    			Get  
    				Return _unit  
    			End Get  
    			Set  
    				_unit = Value  
    				OnPropertyChanged()  
      
    				If Unit = Unit.SI Then  
    					Length *= 25.400013716  
    				Else  
    					Length *= 0.0393701  
    				End If  
      
    			End Set  
    		End Property  
      
    		Public Overrides Function ToString() As String  
    			Return Length.ToString()  
    		End Function  
      
    		Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged  
    		Protected Overridable Sub OnPropertyChanged(<CallerMemberName> Optional ByVal propertyName As String = Nothing)  
    			PropertyChangedEvent?.Invoke(Me, New PropertyChangedEventArgs(propertyName))  
    		End Sub  
      
    	End Class  
    End Namespace  
      
    

    Mocked data

    Namespace Classes  
    	Public Class MockedData  
    		Public Shared Function Boxes() As List(Of Box)  
    			Return New List(Of Box)() From {  
    				New Box() With {  
    					.Length = 25,  
    					.Unit = Unit.IM  
    				},  
    				New Box() With {  
    					.Length = 26,  
    					.Unit = Unit.IM  
    				},  
    				New Box() With {  
    					.Length = 27,  
    					.Unit = Unit.IM  
    				}  
    			}  
    		End Function  
    	End Class  
    End Namespace  
    

    Form code

    Note that each RadioButton has it's Tag property set eg.
    123621-boxes1.png

    Imports System.ComponentModel  
    Imports System.Windows.Forms  
    Imports Classes  
      
    Partial Public Class Form1  
        Inherits Form  
      
        Private ReadOnly _dataSource As New BindingList(Of Box)()  
        Public Sub New()  
            InitializeComponent()  
      
            _dataSource = New BindingList(Of Box)(MockedData.Boxes())  
      
            listBox1.DataSource = _dataSource  
      
            AdjustUnits()  
      
            AddHandler radioButtonIM.CheckedChanged, AddressOf RadioButtonOnCheckedChanged  
            AddHandler radioButtonSI.CheckedChanged, AddressOf RadioButtonOnCheckedChanged  
      
        End Sub  
      
        Private Sub RadioButtonOnCheckedChanged(ByVal sender As Object, ByVal e As EventArgs)  
            Dim rb = DirectCast(sender, RadioButton)  
      
            If rb IsNot Nothing Then  
                If rb.Checked Then  
                    AdjustUnits()  
                End If  
            End If  
      
        End Sub  
      
        Private Sub AdjustUnits()  
            Dim unitType As String = Controls.OfType(Of RadioButton)().FirstOrDefault(Function(r) r.Checked).Tag.ToString()  
      
            Dim unit As Unit  
      
            [Enum].TryParse(unitType, unit)  
      
            For index As Integer = 0 To listBox1.Items.Count - 1  
                Dim item As Box = _dataSource(index)  
                item.Unit = unit  
            Next  
      
        End Sub  
    End Class  
    
    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Xingyu Zhao-MSFT 5,381 Reputation points
    2021-08-16T02:28:52.567+00:00

    Hi @Hobbyist_programmer ,
    If you want to update all objects in a list, you can use List.ForEach(Sub(c) c.PropertyToChange = value)
    The code looks like:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click  
            Dim boxes As List(Of Box) = New List(Of Box) From { ...}  
      
            If Form1.UnitChanged Then  
                If Form1.Unit.Equals("SI") Then  
                    boxes.ForEach(Sub(c) c.Length *= 25.400013716)  
                Else  
                    boxes.ForEach(Sub(c) c.Length *= 0.0393701)  
                End If  
            Else  
                ...  
            End If  
        End Sub  
    

    Hope it could be helpful.

    Best Regards,
    Xingyu Zhao
    *
    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


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.