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

发布于 2024-07-26 19:08:35 字数 781 浏览 3 评论 0原文

我倾向于在大多数应用程序的底部使用 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;
    }

I tend to use a StatusStrip at the bottom of most of my applications for simple status updates and occasionally a progress bar.

However, it appears ToolStripStatusLabels do not inherit from control, so they have no .Invoke, or .InvokeRequired. So how would I thread-safe make a call to change it's text property?

Coded answers for posterity and others that come searching:

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

or

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

澉约 2024-08-02 19:08:35

这是一个很好的问题!

虽然 ToolStripStatusLabel 不从控件继承,但包含的 ToolStrip 却继承自控件! 使用包含的 ToolStrip 的 Invoke 对 ToolStripStatusLabel 进行调用。

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

(我以前也遇到过这个问题。我在 另一个问题。我应该更新该文本以反映我最近的理解。)

This is a good question!

While ToolStripStatusLabel does not inherit from control, the containing ToolStrip does! Use the containing ToolStrip's Invoke to make calls against the ToolStripStatusLabel.

This is because the ToolStrip manually handles the drawing of its component bits, much the same way that WPF manages the drawing of all of its component bits, without generating a separate handle for each one. This is useful because it's easy to forget that every Control has an associated HANDLE and the system only has a finite number of those to dish out, e.g..

(I've run into this before also. I mentioned it in a sidebar on another question, for example. I should update that text to reflect my more recent understanding.)

那请放手 2024-08-02 19:08:35

另外,一般来说,您不必在代码中操作的同一控件上使用 InvokeRequired 和 BeginInvoke,只要您能保证该控件您正在操作的操作是在与您调用 InvokeRequired /BeginInvoke 的 UI 元素相同的线程上创建的(例如,在表单的初始化例程中)。

Also, in general, you do not Have to use the InvokeRequired and BeginInvoke on the exact same control that you are manipulating in code, as long as you can guarantee that the control you are manipulating was created on the same thread (e.g., in the forms' initialization routine), as the UI element you are calling InvokeRequired /BeginInvoke on.

追我者格杀勿论 2024-08-02 19:08:35

您可以使用 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...

You can do this by using the delegate key word and the Control.Invoke() method. This example shows how you manage a thread safe .Text and .ForeColor ajustment.

private delegate void SetToolStripDelegate(string text, Color color);

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

Inside the thread context you can make a thread-safe call of this method like this:

{ // thread begin...

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

} // thread end...
酒与心事 2024-08-02 19:08:35

简而言之,在传递 StatusStrip 项时,也在参数中传递 StatusStrip 并用作 StatusStrip.BeginInvoke 或 Invoke 方法,并将 Status strip 项放入其中。

下面的代码应该帮助您不仅从其他任务/线程,而且从其他类调用和更新 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 窗体屏幕截图

In simple words, while passing the StatusStrip Items, pass the StatusStrip too along in parameter and use as StatusStrip.BeginInvoke or Invoke method and place the Status strip items inside it.

Below code should help you how to call and update the StatusStrip not only from other Task/Thread, but also from other Class.

//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

只有一腔孤勇 2024-08-02 19:08:35

您尝试过 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();
    }
}

Have you tried GetCurrentParent()? This worked for me!

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();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文