线程安全访问控件的最佳实践是什么?

时间:2016-09-20 19:08:15

标签: vb.net multithreading thread-safety

以线程安全的方式访问控件需要更长的代码而不是必要的,因为我必须反复重复以下功能:

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

我最终可能会为每个控件的每个方法和属性编写一个。

有更有效的方法对此进行编码吗?理想情况下,只需要整个应用程序的一个子程序,无论我想要访问哪些控件的属性和方法,我都可以使用它?

1 个答案:

答案 0 :(得分:3)

在我看来,执行调用(就像你一样)是最好的做法。我不认为有一般的最佳做法,但许多人使用Control.Invoke()Control.BeginInvoke()方法。

  

以线程安全的方式访问控件需要更长的代码而不是必要,因为我必须重复执行以下功能

     

我最终可能会为每个控件的每个方法和属性编写一个。

不一定,您仍然可以通过几种不同的方式简化代码。例如,TrackBar派生自System.Windows.Forms.Control,这意味着它可以被转换为Control类,因此您可以概括函数:

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

但实际上有一种更简单的方法:通过Extension methods。您可以创建一个扩展方法,该方法将自动执行调用并为您进行InvokeRequired检查。

由于可以将Sub() - lambda表达式转换/转换为委托,您可以将其用作方法的参数并随意调用:

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

使用此扩展方法,您可以在派生自System.Windows.Forms.Control的任何类上调用此方法,您现在可以调用例如:

Me.InvokeIfRequired(Sub() TrackBar1.Enabled = True)
'Me is the current form. I prefer to let the form do the invocation.

通过这个你也可以调用更长的语句:

Me.InvokeIfRequired(Sub()
                        Button1.Enabled = False
                        Label1.Text = "Something happened..."
                        ProgressBar1.Value += 5
                    End Sub)