以线程安全的方式访问控件需要更长的代码而不是必要的,因为我必须反复重复以下功能:
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
我最终可能会为每个控件的每个方法和属性编写一个。
有更有效的方法对此进行编码吗?理想情况下,只需要整个应用程序的一个子程序,无论我想要访问哪些控件的属性和方法,我都可以使用它?
答案 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)