【问题标题】:Why does the StatusBar.Invoke method not work for a ToolStripProgressBar?为什么 StatusBar.Invoke 方法不适用于 ToolStripProgressBar?
【发布时间】:2011-10-05 07:39:09
【问题描述】:

我最近一直在开发一个应用程序,我想通过包含在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 为假,从而允许Increment 方法触发。

我真的很想知道为什么这不起作用。正如我所说,我已经改用BackgroundWorker,我只是想要一个解释。

【问题讨论】:

  • TSPB 没有什么特别之处,可以为您提供简单的解释。如果主线程被阻塞,Control.Invoke() 往往很容易死锁,因此“什么都没有发生”并不少见。坚持使用 BackgroundWorker。
  • 我从来没有说过我想要一个“简单”的解释,复杂的解释也可以。简单地告诉我 Control.Invoke() 会导致死锁并不足以让我理解原因。提供 Control.Invoke() 是有原因的,为什么我不能将它用于这个控件,当使用相同代码以类似方式处理的控件可以正常工作时。
  • 发布演示问题的重现代码,任何人都可以测试,你会得到答案。

标签: c# winforms invoke multithreading invokerequired


【解决方案1】:

Invoke 调用 postmessage API 并在 windows 消息上排队消息。如果 UI 线程被阻塞,那么你可能会出现死锁,因为它无法推送排队的消息,所以什么都不会发生。调用所需的另一端没有被触发,如果有东西在等待它,砰,死锁。

这就是您需要小心调用 Invoke 的原因。

How to invoke a function on parent thread in .NET?

但是您的问题在于委托的创建,它是一个空委托,您需要在调用调用它的同一线程上创建委托,因为否则,底层系统将无法封送委托(它是一个指针)。

    private void changeStatusMessageMethod(String message)
    {
        if (this.InvokeRequired)
        {
            var changeStatusMessageDelegate = new changeStatusMessage(changeStatusMessageMethod);
            this.Invoke(changeStatusMessageDelegate, new Object[] { message });
        }
        else
        {
            toolstripLabel.Text = message;
        }
    }
    delegate void incrementProgressBar(int value);
    private void incrementProgressBarMethod(int value)
    {
        if (this.InvokeRequired)
        {
            var incrementProgressBarDelegate = new incrementProgressBar(incrementProgressBarMethod);
            this.Invoke(incrementProgressBarDelegate, new Object[] { value });
        }
        else
        {
            toolstripProgress.Increment(value);
        }
    }

这适用于 dotnet framework v4

    private void button1_Click(object sender, EventArgs e)
    {
        var t = new System.Threading.Thread(new System.Threading.ThreadStart(x));
        t.Start();
    }

    private void x()
    {
        do
        {
            changeStatusMessageMethod(DateTime.Now.ToString());
            System.Threading.Thread.Sleep(1000);
        } while (true);
    }

    private void button2_Click(object sender, EventArgs e)
    {
        var t = new System.Threading.Thread(new System.Threading.ThreadStart(y));
        t.Start();
    }

    private void y()
    {
        do
        {
            incrementProgressBarMethod(1);
            System.Threading.Thread.Sleep(1000);
        } while (true);
    }

【讨论】:

    猜你喜欢
    • 2020-09-25
    • 2015-11-24
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-20
    相关资源
    最近更新 更多