为什么 StatusBar.Invoke 方法不适用于 ToolStripProgressBar?
我最近一直在开发一个应用程序,我想通过 StatusBar
控件中包含的 ToolStripProgressBar
控件在状态栏中显示另一个线程的进度。在尝试添加此代码之前,我最初使用代码更改了 ToolStripStatusLabel
控件的文本,为此,我使用带有委托的 Invoke 方法,一切正常。但是,我发现当我尝试使用 ToolStripProgressBar
执行此操作时,对状态栏的 Invoke
方法的调用失败,并且没有通知(没有错误,没有异常,没有任何通知)。我后来了解到,要以这种方式使用进度条,我必须使用 BackgroundWorker
控件。所以我的代码可以工作,但我不明白为什么我不能使用似乎已经可以工作的 Invoke
方法。
一些有效和无效的示例:
这个有效
public delegate void changeStatusMessage(String message);
public changeStatusMessage changeStatusMessageDelegate;
public void changeStatusMessageMethod(String message){
if(statusbar.InvokeRequired){
statusbar.Invoke(changeStatusMessageDelegate, new Object[] {message});
}else{
toolstripLabel.Text = message;
}
}
这个无效
public delegate void incrementProgressBar(int value);
public incrementProgressBar incrementProgressBarDelegate;
public void incrementProgressBarMethod(int value){
if(statusbar.InvokeRequired){
statusbar.Invoke(incrementProgressBarDelegate, new Object[] {value});
}else{
toolstripProgress.Increment(value);
}
}
在无效的示例中,InvokeRequired
属性为 true,因此调用 Invoke
方法然后什么也没有发生。正如我预期的那样,这次它会再次调用 incrementProgressBarMethod
,其中 InvokeRequired
为 false,从而允许触发 Increment
方法。
我真的很想知道为什么这不起作用。正如我所说,我已经重新调整以使用 BackgroundWorker
,我只是想要一个解释。
I have recently been working on an application where I wanted to display the progress of another thread in the status bar via the ToolStripProgressBar
control that is contained in the StatusBar
control. Before I attempted to add this code I originally had the code changing the text of a ToolStripStatusLabel
control and to do this I used the Invoke method with delegates and everything worked fine. However, I found that when I attempted this with the ToolStripProgressBar
the call to the status bar's Invoke
method failed without a notification (no error, no exception, nothing). What I have since learned is that to use a progress bar in this way I had to use a BackgroundWorker
control. So my code works but I don't understand why I couldn't use the Invoke
method that already seemed to work.
Some examples of what worked and what didn't:
This worked
public delegate void changeStatusMessage(String message);
public changeStatusMessage changeStatusMessageDelegate;
public void changeStatusMessageMethod(String message){
if(statusbar.InvokeRequired){
statusbar.Invoke(changeStatusMessageDelegate, new Object[] {message});
}else{
toolstripLabel.Text = message;
}
}
This did not work
public delegate void incrementProgressBar(int value);
public incrementProgressBar incrementProgressBarDelegate;
public void incrementProgressBarMethod(int value){
if(statusbar.InvokeRequired){
statusbar.Invoke(incrementProgressBarDelegate, new Object[] {value});
}else{
toolstripProgress.Increment(value);
}
}
In the example that didn't work the InvokeRequired
property is true so the Invoke
method is called and then nothing happens. Where as I expected it to call the incrementProgressBarMethod
again this time where InvokeRequired
is false and thus allowing the Increment
method to fire.
I would really like to know why this doesn't work. As I said I have already retooled to use a BackgroundWorker
, I just want an explanation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Invoke 调用 postmessage API 并将消息放入 Windows 消息队列中。如果 UI 线程被阻塞,那么可能会出现死锁,因为它无法推送排队的消息,什么也不会发生。所需调用的另一端不会被触发,如果有东西在等待它,就会发生死锁。
这就是您需要小心 Invoke 的原因。
如何在 .NET 中调用父线程上的函数?
但是您的问题在于创建委托,它是一个空委托,您需要在调用调用它的同一线程上创建委托,因为其他方式,底层系统将无法封送委托(它是一个指针)。
这适用于 dotnet 框架 v4
Invoke calls postmessage API and enqueue message on windows message. If UI thread is blocked, then you can have a deadlock, because it cant push queued message, nothing will happens. The other side of invoke required is not fired, and if something is waiting for it, bang, deadlock.
This is the reason you need to be careful with Invoke.
How to invoke a function on parent thread in .NET?
But your problem is on creation of the delegate, it is a null delegate, you need to create the delegate on same thread that it is being called by invoke, because other way, the underling system will fail on marshaling the delegate (its a pointer).
This works on dotnet framework v4