2

I am trying to change the background color of a button (cmdLogQry) from a Set-procedure of a public property (LogQry) - according to the new value of the property.

It works if the property is being changed in the code belongig to the form containing the button (in the Click method of the same or even another button). But it does not work if the property is being changed from another module (handler procedure for COM ports DataReceived event). No error message or anything - the LogQry gets its value changed all right, but the color of the button does not change.

What do I do wrong?

Public Class Handler

Private _logQry As Boolean = False

Public Property LogQry() As Boolean
    Get
        Return _logQry
    End Get
    Set(ByVal value As Boolean)
        _logQry = value
        If value Then
            frmMain.cmdLogQry.BackColor = Color.Red
        Else
            frmMain.cmdLogQry.BackColor = Color.Blue
        End If
    End Set
End Property

Private Sub comPort_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
...
    LogQry = Not LogQry ' does NOT change color
...
End Sub

End Class

Public Class frmMain     
Private comm As New Handler()
...
Private Sub cmdLogQry_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmdLogQry.Click
    comm.LogQry = Not comm.LogQry ' does change color
End Sub
...
End Class
Hando
  • 23
  • 3

1 Answers1

2

This problem is caused by the default instance of the form class created by the VB.NET implementation. More on default instances could be found here and in this answer from Hans Passant.
Essentially when you define a form class, VB.NET compiler creates a default instance of that class named with the same name of the class, but this creates a lot of misunderstanding in an object oriented environment like NET.

To fix your problem you need to implement a constructor in your Handler class that receives the actual instance of frmMain, store it inside a class variable and use that instance when you want to modify something on the actual displayed form

Public Class Handler

    Private _logQry As Boolean = False
    Private _mainInstance As frmMain

    Public Sub New(mainInstance as frmMain)
        _mainInstance = mainInstance
    End Sub

    Public Property LogQry() As Boolean
        Get
            Return _logQry
        End Get
        Set(ByVal value As Boolean)
            _logQry = value
            If value Then
                _mainInstance.cmdLogQry.BackColor = Color.Red
            Else
                _mainInstance.cmdLogQry.BackColor = Color.Blue
            End If
        End Set
    End Property
    ....

End Class

Now, when you create the Handler instance pass the reference to the current frmMain

Public Class frmMain     

    Private comm As Handler
    ...
    Private Sub cmdLogQry_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmdLogQry.Click
        comm = new Handler(Me)
        comm.LogQry = Not comm.LogQry ' does change color
    End Sub
    ...
End Class

Keep in mind that this solution creates also problems. It couples the class Handler to your frmMain and the two are now inseparable. Probably a better approach is to create an Event in the Handler class so, every form that wants to be notified could subscribe to the event and receieves the information when needed.

Community
  • 1
  • 1
Steve
  • 213,761
  • 22
  • 232
  • 286