如何在c#的后台线程中刷新Windows窗体中的标签?
本文关键字:刷新 Windows 窗体 标签 线程 后台 | 更新日期: 2023-09-27 18:12:40
我有一个线程与主表单(UI)并行运行。它所做的(目前)只是每秒增加一个计数器。我想在Windows窗体中使用标签显示计数器的值。这可能吗?当我尝试下面的代码时,我在ShowValue方法中得到一个编译错误。我必须声明ShowValue为"static",这样我才能从后台线程调用它。但是,如果我这样做,我不能使用"this."来访问ShowValue Form1中的标签。这是正确的做法吗?任何提示将不胜感激,谢谢!
private void count_secs()
{
while (!stopThread)
{
if (stopThread)
{
break;
}
num2++; // increment counter
Form1.ShowValue(num2); // display the counter value in the main Form
try
{
Thread.Sleep(1000); // wait 1 sec.
}
catch (ThreadInterruptedException)
{
if (stopThread)
{
break;
}
}
}
}
然后在Form1类中,我有:
public static void ShowValue(int num)
{
this.label7.Text = num.ToString();
// compiler error here: "Keyword 'this' is not valid in a static method.
}
不能在静态方法ShowValue(int num)
中引用局部变量(this.label7
)
你的方法应该像这样:
public void ShowValue(int num)
{
if(label7.InvokeREquired)
{
Action a = () => ShowValue(num);
label7.Invoke(a);
}
else
this.label7.Text = num.ToString();
}
在此代码中,将对表单的静态调用替换为实例:
private void count_secs()
{
var frm = new Form1(); //create instance
frm.Show(); // show form
while (!stopThread)
{
if (stopThread)
{
break;
}
num2++; // increment counter
//use form instance
frm.ShowValue(num2); // display the counter value in the main Form
try
{
Thread.Sleep(1000); // wait 1 sec.
}
catch (ThreadInterruptedException)
{
if (stopThread)
{
break;
}
}
}
编辑
你可能想在方法count_secs()
之外声明表单实例
您不能从不同的线程随机访问GUI元素。对你的问题的简短回答是:使用现有的结构。
- 如果你只是想频繁地做事情,使用计时器。它会通知你的主线程("拥有"GUI),当时间到了,你可以更新GUI元素。 如果你真的想创建自己的线程,那就使用Backgroundworker。它将提供线程安全的事件,您可以从中更新GUI元素。
你的第一个问题是获得表单实例,如果你没有在你的调用表单上的表单实例,那么你导致应用程序。OpenForms属性:
Form1 frm = Application.OpenForms["Form1"] as Form1;
if(frm != null)
frm.ShowValue(num2);
你的第二个问题是,你需要修改你的方法作为实例方法,并保存它从跨线程异常修改它像:
public void ShowValue(int num)
{
if (label7.InvokeRequired)
{
label7.BeginInvoke((MethodInvoker)delegate { label7.Text = num.ToString(); });
}
else
{
label7.Text = num.ToString();
}
}
两个问题:
- 您不能从静态上下文中使用
this
引用。 - 你不能从后台线程更新UI。
解决方案:
- 将方法
ShowValue
标记为实例方法(例如:去掉static
) - 使用后台worker或阅读这个问题,它解释得很好
将ShowValue
函数设置为静态并不是强制性的。将其保留为非静态并将您的逻辑Form1.ShowValue(num2)
行替换为以下代码:
if (label1.InvokeRequired)
label1.BeginInvoke(new Action(() => ShowValue(num2)));
else
label1.Invoke(new Action(() => ShowValue(num2)));