如何在不同线程间调用ToolStripStatusLabel?

17

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

然而,似乎ToolStripStatusLabel没有从控件继承,因此它们没有.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;
    }

@Maslow:在使用Control.Invoke时要小心逻辑。如果不仔细阅读文档中规定的规则,很容易出现错误。请查看我在答案链接中提供的代码,以获得更加安全的Invoke使用方法。例如,你的实现没有验证ToolStrip是否已被释放,也没有验证ToolStrip的句柄是否已创建。 - Greg D
除了句柄尚未创建之外,看起来这些情况无论如何都只会抛出异常,对吗?如果句柄尚未创建,假装什么也没发生并且不抛出异常是否有用,我不确定。 - Maslow
5个回答

29

这是一个好问题!

ToolStripStatusLabel 没有从控件继承,但包含它的 ToolStrip 控件确实继承了!使用包含的 ToolStrip 的 Invoke 方法来调用 ToolStripStatusLabel

这是因为 ToolStrip 手动处理其组件位的绘制,就像 WPF 管理所有组件位的绘制一样,而不会为每个组件生成单独的句柄。这很有用,因为很容易忘记每个 Control 都有一个关联的 HANDLE,而系统只有有限数量的处理能力。

(我之前也遇到过这个问题。例如,在另一个问题的侧边栏中提到过。我应该更新文本以反映我更近期的理解。)


1
是的,你甚至可以使用Forms Invoke方法,因为它在同一线程上创建。但我会选择Greg D的解决方案,因为它更合乎逻辑。 - sindre j
@sindre,不一定,但可能会……而ToolStripStatusLabels必须在与StatusStrip相同的线程上创建。 - Charles Bretana

2

通常情况下,在代码中操作的控件上不一定需要使用InvokeRequired和BeginInvoke,只要您可以保证操作的控件与调用InvokeRequired/BeginInvoke的UI元素在同一个线程上创建(例如, 在表单的初始化程序中)。


1
你可以使用delegate关键字和Control.Invoke()方法来实现此操作。以下示例演示了如何管理线程安全的.Text.ForeColor调整。
private delegate void SetToolStripDelegate(string text, Color color);

private void SetToolStrip(string text, Color color)
{
    statusBar.Text = text;
    statusBar.ForeColor = color;
}

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

{ // thread begin...

    // somewhere inside the thread
    Invoke(new SetToolStripDelegate(SetToolStrip), "Connected.", Color.Green);

} // thread end...

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();
    }
}

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 截图


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接