【问题标题】:How to make labels change in a C#.NET GUI-project如何在 C#.NET GUI 项目中更改标签
【发布时间】:2013-05-14 18:28:25
【问题描述】:

我正在为朋友的生日申请,应该会弹出一个带有不断变化的赞美的窗口。 但是,窗口会冻结,并且标签不会更改。我用谷歌搜索了它,并阅读了一些关于使用 Backgroundworker 的内容,以便将 GUI 线程与不断变化的进程分开。 还是不行。

这是我的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace ProjectL
{
    public partial class Form1 : Form
    {
        private MessageHandler theHandler = new MessageHandler();
        private BackgroundWorker theBackgroundWorker = new BackgroundWorker();
        public Form1()
        {
            InitializeComponent();
        }

        private void StartButton_Click(object sender, EventArgs e)
        {
            StartButton.Visible = false;
            theBackgroundWorker.DoWork += new DoWorkEventHandler(theBackgroundWorker_doYourWork);
            //theBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(theBackgroundWorker_doYourWork);
            theBackgroundWorker.RunWorkerAsync();        

            theHandler.RunMessage(hBDLabel, youAreLabel, mainLabel, this);
        }

        void theBackgroundWorker_doYourWork(object sender, DoWorkEventArgs e)
        {
            theHandler.RunMessage(hBDLabel, youAreLabel, mainLabel, this);
        }
    }
}

这是应该在后台发生的,使用我命名为 MessageHandler 的类:

class MessageHandler
{
    public List<String> GenerateComplimentTexts()
    {
        List<String> stringList = new List<String>();
        //Adding a bunch of compliments into a List<String>

        return stringList;
    }

    public void RunMessage(Label hBDLabel, Label youAreLabel, Label mainLabel, Form1 form)
    {
        List<String> stringList = GenerateComplimentTexts();
        Thread.Sleep(2000);
        form.Text = "Happy Birthday Goose!!!";
        hBDLabel.Text = "Happy Birthday Goose!";
        Thread.Sleep(3000);
        youAreLabel.Text = "You are...";
        Thread.Sleep(2000);
        foreach (String e in stringList)
        {
            mainLabel.Text = e;
            //form.Test = e

            Thread.Sleep(1000);
        }
        Thread.Sleep(3000);
        mainLabel.Text = "";
        youAreLabel.Text = FinalMessage;
    }

    private String _finalMessage = "FINAL MESSAGE";
    public String FinalMessage {get {return _finalMessage;}}
}

不过,我的窗口上没有任何变化。如果我选择取消注释,除了表单本身顶部栏中的文本外,所有内容都几乎被冻结 form.Text = e;

有什么建议吗?

【问题讨论】:

  • 您不能从后台线程更改 GUI 元素,使用计时器来创建基于时间的事件
  • 尝试 System.Application.DoEvents。 makc 是对的,这不是最好的方法(显然它甚至不起作用)。你不应该从 Backgroundworker-Thread 触摸 GUI 对象。而是通过 Backgroundworkerarguments 传递它们。

标签: c# multithreading user-interface label


【解决方案1】:

您可以使用 Timers 而不是 BackgroundWorker 来实现它。

它可能看起来像这样:

主窗体:

public partial class Form1 : Form
{
    private Timer timer;
    private MessageHandler theHandler = new MessageHandler();

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        timer = new Timer();
        timer.Interval = 1000;
        timer.Tick += TimerOnTick;
        // Initialize the other labels with static text here
    }

    private void TimerOnTick(object sender, EventArgs eventArgs)
    {
        theHandler.ShowNext(label1);
    }

    private void StartButton_Click(object sender, EventArgs e)
    {
        timer.Start();
    }
}

还有 MessageHandler 类:

public class MessageHandler
{
    private List<String> compliments = new List<string>();
    private int index = 0;

    public MessageHandler()
    {
        GenerateComplimentTexts();
    }

    private void GenerateComplimentTexts()
    {
        List<String> stringList = new List<String>();
        //Adding a bunch of compliments into a List<String>
        compliments = stringList;
    }

    public void ShowNext(Label label)
    {
        label.Text = compliments.ElementAt(index);
        index = (index >= compliments.Count - 1) ? 0 : index + 1;
    }
}

【讨论】:

  • +1 Timer 比 Bg worker 更优雅。但是,请注意您使用的计时器。在这种情况下,最适合的计时器似乎是System.Windows.Forms.Timer,它在上面的代码中正确显示。但是,您的答案中提供的链接是 System.Timers.Timer,您必须特别注意在 GUI 线程上引发其事件。
  • @YK1 哎呀,感谢您指出这一点。没注意就在谷歌上挑了第一个链接哈哈
【解决方案2】:

要更新 UI,请使用后台工作程序的 ReportProgress 方法。 ReportProgress 引发 ProgressChanged 事件,您可以从那里更新您的 UI。请务必将 backgroundworker 的 WorkerReportsProgress 属性设置为 true。

【讨论】:

    【解决方案3】:

    试试这个代码:

    private void StartButton_Click(object sender, EventArgs e)
        {
            StartButton.Visible = false;
            theBackgroundWorker.DoWork += new DoWorkEventHandler(theBackgroundWorker_doYourWork);      
            theBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(theBackgroundWorker_ProgressChanged);
            theBackgroundWorker.RunWorkerAsync();        
    
        }
    
        void theBackgroundWorker_doYourWork(object sender, DoWorkEventArgs e)
        {
             var w = sender as BackgroundWorker;
    
             List<String> stringList = GenerateComplimentTexts();
             Thread.Sleep(2000);
             w.ReportProgress(0, "Happy Birthday Goose!!!");
             w.ReportProgress(1, "Happy Birthday Goose!");      
             Thread.Sleep(3000);
             w.ReportProgress(2, "You are...");    
             Thread.Sleep(2000);
             foreach (String e in stringList)
             {
                 w.ReportProgress(3, e);                
                 Thread.Sleep(1000);
             }
             Thread.Sleep(3000);
             w.ReportProgress(3, "");  
             w.ReportProgress(2, FinalMessage);
        }
    
        void theBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
    
            var msg = e.UserState.ToString();
            switch (e.ProgressPercentage)
            { 
                case 0:
                     form.Text = msg;
                     break;
                case 1:
                    hBDLabel.Text=msg;
                    break;
                case 2:
                    youAreLabel.Text =msg;
                    break;
                case 3:
                    mainLabel.Text=msg;
                    break;
    
            }        
        }
    

    【讨论】:

      【解决方案4】:

      试试这个: 1.) 将计时器复制到表单 2.) 将以下代码复制到 timer1_tick-Event 中。

      private int _counter;
      private int _currentIndex;
      
        private void timer1_Tick(object sender, EventArgs e)
          {
                  switch (_counter)
                  {
                      case 1:
                         form.Text = "Happy Birthday Goose!!!";
                         hBDLabel.Text = "Happy Birthday Goose!";
                         break;
      
                      case 2:
                          timer1.Interval = 3000;
                          break;
                      case 3:
                          youAreLabel.Text = "You are...";
                          break;
                      case 4:
                          if (stringlist.count = (_currentIndex -1))
                          {
                              timer1.Enabled = false;
      
                          }else {
                               mainLabel.Text = e;
                               timer1.Interval = 1000;
                             return;
                          }
                           break;
                          }
      
                 _counter ++;
      
      }
      

      不是最优雅的方式,但应该可以。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-29
        • 1970-01-01
        • 1970-01-01
        • 2017-11-12
        相关资源
        最近更新 更多