【问题标题】:How to set label text in Windows Forms from a BackgroundWorker如何从 BackgroundWorker 在 Windows 窗体中设置标签文本
【发布时间】:2016-10-05 10:29:07
【问题描述】:

所以我目前正在使用 Windows 窗体和 C# 为游戏编写关卡生成器。我有一个 BackgroundWorker 正在执行所有生成操作,这样 UI 线程就不会被阻塞,并且可以根据需要自行更新。我目前使用 BackgroundWorkers ReportProgress() 函数更新进度条,但 id 也希望能够根据生成器所在的位置更新标签,即“初始化级别 2”、“将对象放置在级别 3”等。

我尝试从 backgroundWorker 调用 updateProgress() 函数(我将它和表单传递给 Generator 构造函数)来执行此操作,但它不起作用,因为我收到了跨线程错误。

 public partial class mainForm : Form
    {
        LevelGen Generator;
        List<Level> levelSet;

        public mainForm()
        {
            InitializeComponent();;
            Generator = new LevelGen(this, backgroundWorker, timer);
        }



        private void button_GenLevels_Click(object sender, EventArgs e)
        {             
            if (!backgroundWorker.IsBusy)
            {
                progressBar.Value = 0;

                backgroundWorker.RunWorkerAsync();
            }
            else
            {
                backgroundWorker.CancelAsync();
            }
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            levelSet = Generator.startGeneration();
        }

        public void updateProgress(int percentage, string currentWork)
        {
            label_processInfo.Text = percentage + " - " + currentWork;
            backgroundWorker.ReportProgress(percentage);
        }

        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar.Value = e.ProgressPercentage;
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ListLevels(levelSet);
        }

    }

它会在生成器中被这样调用:

public Level generateLevel(int noOfLevels, int noOfBoxes, int roomHeight, int roomWidth, int difficulty, int levelNum, int totalLevels)
        {
            bool generationSuccessful = false;
            Level newLevel = new Level();
            float percentage;
            int indProcesses = 2;
            int totalProcesses = totalLevels * (indProcesses + 1);

            while (!generationSuccessful)
            {
                newLevel = new Level();

                calculateProperties(ref noOfBoxes, ref difficulty, ref roomHeight, ref roomWidth);

                percentage = (((levelNum * indProcesses)) * 100) / totalProcesses;
                form.updateProgress((int)percentage, "Init Level " + levelNum);

                initLevel(ref newLevel, roomHeight, roomWidth);

                percentage = (((levelNum * indProcesses) + 1) * 100) / totalProcesses;
                form.updateProgress((int)percentage, "Placing Patterns in Level " + levelNum);

                placePatterns(ref newLevel, roomHeight, roomWidth);

                generationSuccessful = true;
            }

            percentage = (((levelNum * indProcesses) + 2) * 100) / totalProcesses;
            form.updateProgress((int)percentage, "Level " + levelNum + " Generated");

            return newLevel;
        }

我应该如何告诉 Windows 窗体标签从生成器中更新?

【问题讨论】:

  • 您可以使用 ReportProgress 方法的第二个参数 userState 将数据发送到 backgroundWorker_ProgressChanged 方法。然后你可以从事件参数 e.UserState 中得到它。

标签: c# winforms


【解决方案1】:

根据我刚刚发表的评论。

 public void updateProgress(int percentage, string currentWork)
    {
        label_processInfo.Text = percentage + " - " + currentWork;
        backgroundWorker.ReportProgress(percentage,"New Label Value");
    }
 private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar.Value = e.ProgressPercentage;
        string newLabelValue = (String)e.UserState;
    }

用户状态也是一个对象,所以你可以发送任何你想要的东西。

【讨论】:

  • 你需要在ProgressChanged事件中设置标签Text
  • @Ehsan Sajjad 是的。而是 string newLabelValue = (String)e.UserState;他将需要设置标签值。但这就是他从事件参数中得到它的方式。
  • 太棒了,效果很好!现在我看到了,这是一个非常明显的解决方案。
  • @Conor Watson 很高兴我能帮上忙。
【解决方案2】:

您还可以使用委托并检查 .InvokeRequired 是否以线程安全的方式更新 UI 元素:

delegate void SetTextCallback(string text);
private void SetDebugText(string RxString)
    {
        if (this.btnDebug.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetDebugText);
            this.Invoke(d, new object[] { RxString });

        }
        else
        {
            this.btnDebug.Text = RxString;
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-12
    • 2013-08-18
    相关资源
    最近更新 更多