线程安全访问控件的最佳实践是什么
以线程安全的方式访问控件花费的时间比看起来需要的时间长,因为我必须一遍又一遍地重复如下功能:
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?
在我看来,执行调用(像您一样)是最佳实践.我不认为有一般的最佳实践,但 Control.Invoke()
和 Control.BeginInvoke()
方法被很多人使用.
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.
不一定,您仍然可以通过几种不同的方式简化代码.例如,TrackBar
派生自 System.Windows.Forms.Control
这意味着它可以被转换成 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
但实际上有一种更简单的方法:通过扩展方法.您可以创建一个扩展方法来自动执行调用和 InvokeRequired
检查.
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.
多亏了 Sub()
-lambda 表达式可以转换/转换为委托,您可以将其用作方法的参数并随意调用它:
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
有了这个扩展方法,你可以在任何派生自 System.Windows.Forms.Control
的类上调用它,你现在可以调用例如:
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)