question

Hobbyistprogrammer-7674 avatar image
0 Votes"
Hobbyistprogrammer-7674 asked Hobbyistprogrammer-7674 commented

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

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

dotnet-visual-basic
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered

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



boxes.png (4.8 KiB)
boxes1.png (2.7 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

XingyuZhao-MSFT avatar image
0 Votes"
XingyuZhao-MSFT answered Hobbyistprogrammer-7674 commented

Hi @Hobbyistprogrammer-7674 ,
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.


· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hallo XingyuZaho

Thanks for the answer, is there any way i can make it in object level (inside the object) or it is bad idea to do it that way?

0 Votes 0 ·

II am getting "for each is not a member of IEnumerable" error. It worked 2 days before no w i am getting this error. In the mean time i just updated my ClosedXML package and OpenDocumentXML.

Any idea why this error . Same code worked 2 days ago.

0 Votes 0 ·