如何对ToolStripStatusLabel进行跨线程调用?

时间:2009-07-14 20:53:08

标签: .net multithreading toolstrip

我倾向于在大多数应用程序的底部使用StatusStrip进行简单的状态更新,偶尔也会使用进度条。

但是,看起来ToolStripStatusLabels不会从控件继承,因此它们没有.Invoke或.InvokeRequired。那么我如何线程安全地调用来改变它的文本属性呢?

后代和其他搜索的代码答案:

Action<string> test=(text) =>
            {
                if (this._statusStrip.InvokeRequired) this._statusStrip.Invoke(
               new MethodInvoker(() => this._lblStatus.Text = text));
                else this._lblStatus.Text = text;
            };

private void TestInvoker(string text)
    {
        if (this._statusStrip.InvokeRequired) 
            this._statusStrip.Invoke(
                   new MethodInvoker(() => this._lblStatus.Text = text));
        else this._lblStatus.Text = text;
    }

5 个答案:

答案 0 :(得分:28)

这是一个很好的问题!

虽然ToolStripStatusLabel不从控件继承,但包含ToolStrip的确是如此!使用包含ToolStrip的Invoke来对ToolStripStatusLabel进行调用。

这是因为ToolStrip手动处理其组件位的绘制,这与WPF管理所有其组件位的绘制的方式非常相似,而不为每个位生成单独的句柄。这很有用,因为很容易忘记每个Control都有一个关联的HANDLE,并且系统只有有限数量的那些要出来,例如..

(我之前也遇到过这个问题。例如,我在another question的侧边栏中提到过它。我应该更新该文字以反映我最近的理解。)

答案 1 :(得分:2)

另外,一般情况下,你没有 拥有 来在代码中操作的完全相同的控件上使用InvokeRequired和BeginInvoke,只要你能保证您正在操作的控件是在同一个线程上创建的(例如,在表单的初始化例程中),作为您调用InvokeRequired / BeginInvoke的UI元素。

答案 2 :(得分:1)

您可以使用 delegate 关键字和Control.Invoke()方法来完成此操作。此示例显示了如何管理线程安全 .Text .ForeColor 调整。

&#xA;&#xA;&#xA;&#xA;
  private delegate void SetToolStripDelegate(string text,Color color);&#xA;&#xA; private void SetToolStrip(string text,Color color)&#xA; {&#xA; statusBar.Text = text;&#xA; statusBar.ForeColor = color;&#xA;}&#xA;  
&#xA;&#xA;

在线程上下文中,您可以对此方法进行线程安全调用,如这个:

&#xA;&#xA;

&#xA;&#xA;
  {//线程开始...&#xA;&#xA ; //线程内的某个地方&#xA;调用(新的SetToolStripDelegate(SetToolStrip),“已连接。”,Color.Green);&#xA;&#xA;} //线程结束...&#xA;  
&#xA;

答案 3 :(得分:0)

简单来说,在传递StatusStrip项时,在参数中传递StatusStrip并使用StatusStrip.BeginInvoke或Invoke方法并将状态条项放在其中。

下面的代码应该可以帮助您不仅从其他任务/线程调用和更新StatusStrip,还可以从其他类调用和更新。

//Coded by Chandraprakash [2017-07-18]
//frozenprakash.com

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace UIUpdateFromOtherClass
{

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        FN_Execute();
    }

    async void FN_Execute()
    {
        Second s = new Second();
        await Task.Run(() => s.Execute(lbl1,
                                        pb1,
                                        ss1,
                                        ss1Lbl1,
                                        ss1Pb1)
                        );
        MessageBox.Show("End");
    }

}

public class Second
{
    public void Execute(Label lbl1,
                        ProgressBar pb1,

                        StatusStrip ss1,
                        ToolStripLabel tsLbl1,
                        ToolStripProgressBar tsPb1)
    {
        lbl1.BeginInvoke(new Action(() =>
            lbl1.Text = "Second"
        ));

        pb1.BeginInvoke(new Action(() =>
        {
            pb1.Style = ProgressBarStyle.Marquee;
            pb1.MarqueeAnimationSpeed = 10;
        }));

        ss1.BeginInvoke(new Action(() =>
        {
            tsLbl1.Text = "Second";

            tsPb1.Style = ProgressBarStyle.Marquee;
            tsPb1.MarqueeAnimationSpeed = 10;
        }));

        Thread.Sleep(3000);
    }
}

}

Windows Forms Screenshot

答案 4 :(得分:0)

您是否尝试过 GetCurrentParent()?这对我有用!

private delegate void SetToolStripStatusLabelTextDelegate(ToolStripStatusLabel label, string text);
public static void SetToolStripStatusLabelText(ToolStripStatusLabel label, string text)
{
    if (label.GetCurrentParent().InvokeRequired)
    {
        label.GetCurrentParent().Invoke(new SetToolStripStatusLabelTextDelegate(SetToolStripStatusLabelText), label, text);
    }
    else
    {
        label.Text = text;
        label.Invalidate();
    }
}