如何在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.
  }

如何在c#的后台线程中刷新Windows窗体中的标签?

不能在静态方法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();
    }
} 

两个问题:

  1. 您不能从静态上下文中使用this引用。
  2. 你不能从后台线程更新UI。

解决方案:

  1. 将方法ShowValue标记为实例方法(例如:去掉static)
  2. 使用后台worker或阅读这个问题,它解释得很好

ShowValue函数设置为静态并不是强制性的。将其保留为非静态并将您的逻辑Form1.ShowValue(num2)行替换为以下代码:

 if (label1.InvokeRequired)
       label1.BeginInvoke(new Action(() => ShowValue(num2)));
 else
      label1.Invoke(new Action(() => ShowValue(num2)));