问题
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