VB.NET 委托和调用 - 有人可以向我解释这些吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17334425/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
VB.NET Delegates and Invoke - can somebody explain these to me?
提问by synoptica
I'm new to the world of threading, but a few aspects of an app I'm working on require me to use a BackgroundWorker control to prevent the UI freezing up while it's doing some file operations.
我是线程世界的新手,但我正在处理的应用程序的一些方面要求我使用 BackgroundWorker 控件来防止 UI 在执行某些文件操作时冻结。
What I'm trying to do is update a couple of form labels from within the BackgroundWorker. Having never worked with this before I very quickly discovered that I can't access controls that weren't created within the same thread, so after a bit of research I've implemented the following code that seems to make everything work:
我想要做的是从 BackgroundWorker 中更新几个表单标签。在我很快发现我无法访问不是在同一线程中创建的控件之前从未使用过它,因此经过一些研究,我实现了以下代码,这些代码似乎使一切正常:
Private Delegate Sub DelegateUpdateStatus(ByVal statusText As String, ByRef currentFile As String)
Private Sub UpdateStatus(ByVal statusText As String, ByVal currentFile As String)
If InvokeRequired Then
Invoke(Sub() LblStatus.Text = statusText)
Invoke(Sub() LblCurrentFile.Text = currentFile)
Else
LblStatus.Text = statusText
LblCurrentFile.Text = currentFile
End If
End Sub
Thing is though, I have no understanding of what this code is doing, or why it's required.
问题是,我不明白这段代码在做什么,或者为什么需要它。
I've done a bit of research but I've not done any real work with this kind of thing, and most articles I've read assume some kind of prior knowledge.
我做了一些研究,但我还没有对这种事情做过任何实际工作,而且我读过的大多数文章都假设了某种先验知识。
The three main things I looking to gain an understanding of:
我希望了解的三件主要事情:
- Why this code is required (as in, why the controls can't be accessed directly from the BackgroundWorker)
- What a delegate is, and when the use of it is required
- What the Invoke method does, and what I'm checking for with InvokeRequired
- 为什么需要此代码(例如,为什么不能直接从 BackgroundWorker 访问控件)
- 什么是委托,何时需要使用它
- Invoke 方法的作用,以及我使用 InvokeRequired 检查的内容
As said, threading is still quite a foreign concept, so any answers in plain English would be really helpful - thanks!
如前所述,线程仍然是一个相当陌生的概念,所以任何简单的英语答案都会非常有帮助 - 谢谢!
EDIT: Thanks for the responses so far everybody. I've done some further reading, and I'm wondering if I'm going about this the right way. The reason I'm using a BackgroundWorker is to ensure that the UI remains responsive while I'm performing file operations. The issue is, I still need to wait until the BackgroundWorker has done its job so I can return a boolean indicating the success of the operation. There's ways to work around this, but from my reading, having to wait for a BackgroundWorker to complete its work is defeating the purpose of using it in the first place. So, what's the best way to go about preventing the UI from locking up?
编辑:感谢到目前为止大家的回应。我已经做了一些进一步的阅读,我想知道我是否以正确的方式解决这个问题。我使用 BackgroundWorker 的原因是为了确保在我执行文件操作时 UI 保持响应。问题是,我仍然需要等到 BackgroundWorker 完成它的工作,这样我才能返回一个指示操作成功的布尔值。有很多方法可以解决这个问题,但从我的阅读来看,必须等待 BackgroundWorker 完成其工作首先违背了使用它的目的。那么,防止 UI 锁定的最佳方法是什么?
回答by Adriaan Stander
OK, well done for getting so far.
好的,到目前为止做得很好。
Lets start with point 1.
让我们从第 1 点开始。
From How to: Make Thread-Safe Calls to Windows Forms Controls
If you use multithreading to improve the performance of your Windows Forms applications, you must make sure that you make calls to your controls in a thread-safe way.
Access to Windows Forms controls is not inherently thread safe. If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state.
如果使用多线程来提高 Windows 窗体应用程序的性能,则必须确保以线程安全的方式调用控件。
对 Windows 窗体控件的访问本质上不是线程安全的。如果您有两个或多个线程操作控件的状态,则可能会强制控件进入不一致的状态。
So, as you can see, you need to ensure that when changing the state of a control, it is done in a threadsafe manner.
因此,如您所见,您需要确保在更改控件状态时以线程安全的方式完成。
Now, the property Control.InvokeRequiredchecks whether the code you are executing is on a different thread to the one that originally created the control.
现在,属性Control.InvokeRequired检查您正在执行的代码是否在与最初创建控件的线程不同的线程上。
If it is, we need some way to call code on that original thread.
如果是,我们需要某种方式来调用原始线程上的代码。
For this reason you need to use Control.Invoke Method to execute such code on the original thread.
为此,您需要使用Control.Invoke 方法在原始线程上执行此类代码。
Executes a delegate on the thread that owns the control's underlying window handle.
在拥有控件的基础窗口句柄的线程上执行委托。
Now the thing is, you need to tell that thread what it should be executing, and this is done using the delegate.
现在的事情是,您需要告诉该线程它应该执行什么,这是使用委托完成的。
Represents a delegate, which is a data structure that refers to a static method or to a class instance and an instance method of that class.
代表一个委托,它是一种数据结构,引用静态方法或类实例和该类的实例方法。
Now, the last thing I would recommend is that you look at what the differences between Delegates, Anonymous Delegates, Anonymous Methods and Lamda expressions.
现在,我建议的最后一件事是您查看委托、匿名委托、匿名方法和 Lamda 表达式之间的区别。
回答by OneFineDay
InvokeRequired
asks 'Am I on the right thread?', if so carry on, else I need a delegate - in your code you see a lambda Sub
InvokeRequired
问“我在正确的线程上吗?”,如果是这样继续,否则我需要一个委托 - 在你的代码中你会看到一个 lambda Sub
Invoke(Sub() LblStatus.Text = statusText)
The other way this could work is to direct the result to a diff Sub routine(where the delegate has crossed over to the correct thread), but here we are able to run a Sub inside the Invoke method itself - just a simpler way to do it.
另一种可行的方法是将结果定向到一个 diff Sub 例程(其中委托已经跨越到正确的线程),但在这里我们能够在 Invoke 方法本身内运行一个 Sub - 只是一种更简单的方法它。
A delegate is required any time you use a separate thread to do work async.
每当您使用单独的线程进行异步工作时,都需要委托。
回答by qwr
BackgroundWorker is another way to have thread and make thread-safe call from it. on
ProgressChanged
, andRunWorkerCompleted
you can make thread-safe calls to UIDelegate is just reference to the method
BackgroundWorker 是另一种拥有线程并从中进行线程安全调用的方法。on
ProgressChanged
,RunWorkerCompleted
您可以对 UI 进行线程安全调用委托只是对方法的引用
Control.Invoke(Delegate)
Control.Invoke(委托)
Executes the specified delegate on the thread that owns the control's underlying window handle.
在拥有控件的基础窗口句柄的线程上执行指定的委托。
Control.InvokeRequired
Control.InvokeRequired
Gets a value indicating whether the caller must call an invoke method when making method calls to the control because the caller is on a different thread than the one the control was created on.
获取一个值,该值指示调用者在对控件进行方法调用时是否必须调用 invoke 方法,因为调用者与创建控件的线程位于不同的线程上。
And Why we need it all these stuffs . From msdn document it is clarified :
以及为什么我们需要它所有这些东西。从 msdn 文件中澄清:
If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state. Other thread-related bugs are possible, such as race conditions and deadlocks. It is important to make sure that access to your controls is performed in a thread-safe way.
So for safety reasons we have to implement this, otherwise our worker threads and UI thread may both try to access the data member at once, and it will wreak havoc on our application . So instead of disabling it and having a chance crash possibility of your application, you should better use thread-safe patterns .
如果您有两个或多个线程操作控件的状态,则可能会强制控件进入不一致的状态。其他与线程相关的错误也是可能的,例如竞争条件和死锁。确保以线程安全的方式执行对控件的访问非常重要。
所以出于安全原因,我们必须实现这一点,否则我们的工作线程和 UI 线程可能会同时尝试访问数据成员,这将对我们的应用程序造成严重破坏。因此,与其禁用它并使您的应用程序有可能崩溃,不如使用线程安全模式。