1

So we are working the MVP design patterns in VB.net. We have a simple Logon View and Interface:

Public Interface ILogonView
    ReadOnly Property Username() As String
End Interface

Public Class LogonView
    Implements ILogonView
    Public ReadOnly Propery Username As String Implements ILogonView.Username
        Get
            tbUsername.Text
        End Get
    End Property
End Class

The trouble is that we need to modify the Get so that it is thread-safe. Doing so means we need to optionally wrap the code in a Control.Invoke() call to ensure we only access UI objects from the main thread.

For example, if instead of doing this with a Property, we instead did this with a standard getter, we'd use recursion. Something like:

Function GetUsername() as String
    If Me.InvokeRequired Then
        Return Me.Invoke(Sub() GetUsername())
    End If
    Return tbUsername.Text
End Function

My question is -- can we call a Property recursively from within the property's Getter? My Vb.net is a bit rusty, and I can't discover the syntax magic to accomplish this.

user590028
  • 11,364
  • 3
  • 40
  • 57

2 Answers2

3

Yes, return when invoke is not required. If it's required on the first pass through, the subsequent call won't be.

Public ReadOnly Property GetUsername As String
    Get
        If tbUsername.InvokeRequired Then
            Return tbUsername.Invoke(Function() GetUsername())
        Else
            Return tbUsername.Text
        End If
    End Get
End Property

See Automating the InvokeRequired code pattern

You can write extension methods to automate it

<Extension()>
Public Function InvokeIfRequired(Of TR)(ByVal control As Control, func As Func(Of TR)) As TR
    If control.InvokeRequired Then
        Return CType(control.Invoke(func), TR)
    Else
        Return func()
    End If
End Function

<Extension()> _
Public Sub InvokeIfRequired(ByVal control As Control, action As MethodInvoker)
    If control.InvokeRequired Then
        control.Invoke(action)
    Else
        action()
    End If
End Sub

Then

Public Property GetUsername As String
    Get
        Return tbUsername.InvokeIfRequired(Function() tbUsername.Text)
    End Get
    Set(value As String)
        tbUsername.InvokeIfRequired(Sub() tbUsername.Text = value)
    End Set
End Property

You can ignore compiler warnings related to recursive property calls in a project, in the Project Property Pages >> Compile >> Warning Configurations >> Recursive operator or property access = None, but it may do more harm than good is it applies to the entire project.

Community
  • 1
  • 1
djv
  • 15,168
  • 7
  • 48
  • 72
  • This is a good tip -- but I think you missed my question. I was using the Control.Invoke() code as an example of what I was trying to accomplish via vb.net `Property`. I'm searching for how to accomplish this from within a property. – user590028 May 02 '17 at 19:07
  • There is a compiler warning with the property, but it works. You could probably add a directive to ignore it. Looking into it. – djv May 02 '17 at 19:10
  • 1
    Does [this](http://stackoverflow.com/questions/33110135/does-vb-net-have-an-equivalent-to-pragma-warning-disable-restore) help with the warning? – Mark May 02 '17 at 19:24
  • 1st of all -- you have 110% answered my question. If I could up-vote you more than once...I would. I hate to be greedy, but this `` solution is brilliant. Would you mind extending it to include the setter? – user590028 May 02 '17 at 19:27
  • 1
    There you go. I actually have 9x Func and 9x Action overloads of `InvokeIfRequired`, one for each number of arguments from 0 to 8. For example, the Func with 8 arguments is declared `Public Function InvokeIfRequired(Of T1, T2, T3, T4, T5, T6, T7, T8, TR)(ByVal control As Control, func As Func(Of T1, T2, T3, T4, T5, T6, T7, T8, TR), arg1 As T1, arg2 As T2, arg3 As T3, arg4 As T4, arg5 As T5, arg6 As T6, arg7 As T7, arg8 As T8) As TR` ... you can figure out the rest as you feel fit :) – djv May 02 '17 at 20:31
  • You can disable and enable individual warnings in vb, no need to turn it off at the project level. – jmoreno Sep 15 '18 at 11:39
0

Non recursive approach

Public ReadOnly Property GetUsername As String
    Get
        Dim rv As String
        If tbUsername.InvokeRequired Then
            tbUsername.Invoke(Sub()
                                  rv = tbUsername.Text
                              End Sub)
        Else
            rv = tbUsername.Text
        End If
        Return rv
    End Get
End Property
dbasnett
  • 11,334
  • 2
  • 25
  • 33