Conor Watson Conor Watson - 2 months ago 14
C# Question

How to set label text in Windows Forms from a BackgroundWorker

So I am currently writing a Level Generator for a game using Windows Forms and C#. I have a

BackgroundWorker
that is doing all of the Generation so that the UI thread is not held up and can update itself as necessary. I currently update a progress bar using the BackgroundWorkers
ReportProgress()
function, but id also like to be able to update a label based on where the generator is at, i.e "Initialising Level 2", "Placing objects in Level 3" etc.

I tried to call the
updateProgress()
function from the backgroundWorker (I pass it and the form into the Generator constructor) to do that but it doesn't work because I get a Cross-Threading error.

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);
}

}


And it would be getting called like this inside the Generator:

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;
}


How should I tell the Windows Form Label to update from within the Generator?

Answer

Based on the comment i just leaved.

 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;
    }

Also the user state is an object, so you can send anything you want.