Как сделать перекрестные вызовы на ToolStripStatusLabel?
Я склонен использовать 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;
}
Ответы
Ответ 1
Это хороший вопрос!
Пока ToolStripStatusLabel
не наследуется от элемента управления, содержит ToolStrip
. Используйте содержащий ToolStrip
Invoke для совершения вызовов с помощью ToolStripStatusLabel
.
Это связано с тем, что ToolStrip вручную обрабатывает чертеж своих компонентных битов, подобно тому, как WPF управляет рисованием всех своих компонентных битов без создания отдельного дескриптора для каждого из них. Это полезно, потому что легко забыть, что каждый Control
имеет связанный с ним HANDLE
, и система имеет только конечное число тех, которые могут быть вырезаны, например.
(Я уже сталкивался с этим раньше. Я упомянул его в боковой панели на еще один вопрос, например. Я должен обновить этот текст, чтобы отразить мою недавнюю понимание.)
Ответ 2
Кроме того, вы не используете Have, чтобы использовать InvokeRequired и BeginInvoke в том же самом элементе управления, который вы манипулируете кодом, если вы можете гарантировать, что управляющий элемент, которым вы управляете, был созданный в том же потоке (например, в процедуре инициализации форм), в качестве элемента пользовательского интерфейса, вызываемого InvokeRequired/BeginInvoke.
Ответ 3
Вы можете сделать это, используя ключевое слово 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...
Ответ 4
Простыми словами, передавая элементы 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