问题
Accessing controls in a thread-safe manner takes longer to code than seems necessary because I have to repeat functions like the following over and over:
Private Sub SettbEnabled(tb As TrackBar, value As Integer)
If tb.InvokeRequired Then
tb.Invoke(Sub() tb.Enabled = value)
Else
tb.Enabled = value
End If
End Sub
I could end up writing one for every method and property of every control.
Is there a more efficient way to code this? Ideally just one sub for the entire app, that I can use no matter what properties and methods of what controls I want to access?
回答1:
In my opinion performing invocation (like you do) is the best practice. I don't think there is a general best practice, but the Control.Invoke() and Control.BeginInvoke() methods are used by many.
Accessing controls in a thread-safe manner takes longer to code than seems necessary because I have to repeat functions like the following over and over
I could end up writing one for every method and property of every control.
Not necessarily, you can still simplify your code in a few different ways. For instance, a TrackBar derives from System.Windows.Forms.Control which means it may be casted into the Control class, thus you can generalize the functions:
Private Sub SetEnabled(ctrl As Control, value As Integer)
If ctrl.InvokeRequired Then
ctrl.Invoke(Sub() ctrl.Enabled = value)
Else
ctrl.Enabled = value
End If
End Sub
But there's actually an even simpler way to do it: via Extension methods. You can create an extension method that will automatically perform the invocation and the InvokeRequired check for you.
Thanks to that a Sub()-lambda expression can be casted/converted into a delegate, you can use it as an argument for your method and call it at will:
Imports System.Runtime.CompilerServices
Public Module Extensions
<Extension()> _
Public Sub InvokeIfRequired(ByVal Control As Control, ByVal Method As [Delegate], ByVal ParamArray Parameters As Object())
If Parameters IsNot Nothing AndAlso _
Parameters.Length = 0 Then Parameters = Nothing 'If Parameters has a length of zero then no parameters should be passed.
If Control.InvokeRequired = True Then
Control.Invoke(Method, Parameters)
Else
Method.DynamicInvoke(Parameters)
End If
End Sub
End Module
With this extension method, which you can call on any class that derives from System.Windows.Forms.Control, you will now be able to call for example:
Me.InvokeIfRequired(Sub() TrackBar1.Enabled = True)
'Me is the current form. I prefer to let the form do the invocation.
By having this you may also invoke longer statements:
Me.InvokeIfRequired(Sub()
Button1.Enabled = False
Label1.Text = "Something happened..."
ProgressBar1.Value += 5
End Sub)
来源:https://stackoverflow.com/questions/39602012/what-is-the-best-practice-for-thread-safe-access-to-controls