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