What is the Best Practice for thread-safe access to controls

爷,独闯天下 提交于 2019-12-31 05:20:39

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!