17

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

但是,似乎 ToolStripStatusLabels 没有从控件继承,因此它们没有 .Invoke 或 .InvokeRequired。那么我将如何进行线程安全调用来更改它的 text 属性呢?

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

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;
    }
4

5 回答 5

29

这是一个很好的问题!

虽然ToolStripStatusLabel不从控件继承,但包含ToolStrip!使用包含ToolStrip的 Invoke 对ToolStripStatusLabel.

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

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

于 2009-07-14T20:54:35.710 回答
2

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

于 2009-07-14T20:58:53.893 回答
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...
于 2016-06-20T09:12:37.793 回答
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 窗体屏幕截图

于 2017-07-18T16:27:32.577 回答
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();
    }
}
于 2021-03-25T15:47:57.307 回答