Darw1n34
Darw1n34

Reputation: 332

Dynamic Label Text within a for loop

I made a simple WF in C# in an attempt to change the label dynamically.

However, when I run this code, there is no visible change, until after the code has run, and then it changes to "Processing 9" 0-8 are not ever shown. Is it because it is within the loop?

 private void button1_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < 10; i++)
        {
            label9.Text = "Processing " + i.ToString();
            Thread.Sleep(1000);
        }
    }

EDIT: X-Tech's code worked but when I tried to incorporate it into my code, I get the following threading issue. I am trying to dynamically change the label.text in the loop while the progress bar is rocking:

An exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll but was not handled in user code Additional information: Cross-thread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on. If there is a handler for this exception, the program may be safely continued

I am not sure how to attack this since I am not super familiar with Task.Factory.StartNew() and Invoke statements.

EDIT 2: Adapted Code:

 Task.Factory.StartNew(() =>
 {
      for (int i = 0; i < lstFilesToZip.Items.Count; i++)
      {
          zipArray[i] = lstFilesToZip.Items[i].ToString();
          // Report progress.
          ExecuteSecure(() => label9.Text = "Processing :" + Path.GetFileNameWithoutExtension(lstFilesToZip.Items[i].ToString()));
          ExecuteSecure(() => progressBar1.PerformStep());

          string zipFileName = Path.GetFileName(zipArray[i]);
          string newFolder = txtDestinationFolder.Text + "\\" + Path.GetFileNameWithoutExtension(zipArray[i]);
          //check to see if a directory with the file name for the zip file already exists, if not, it will create it
          if (Directory.Exists(newFolder) == false)
          {
                DirectoryInfo newPath = Directory.CreateDirectory(newFolder);
                if (lstCommonFiles.Items.Count > 0)
                {
                     //copies each file in the common file list to each new folder created, the boolean indicates that it will overwrite existing files (true) or won't (false)
                     for (int k = 0; k < lstCommonFiles.Items.Count; k++)
                     {
                          File.Copy(lstCommonFiles.Items[k].ToString(), (newFolder + "\\" + Path.GetFileName(commonArray[k])), true);
                     }
                }
                //adds the zip file into the folder as well
                File.Copy(zipArray[i], (newFolder + "\\" + zipFileName), true);

          }
    }

    if (txtCommonFiles.Text.Length <= 0)
    {
          string result = "There are no common files selected, would you still like to proceed?";
          DialogResult result1 = MessageBox.Show(result, "Common Files Missing", MessageBoxButtons.YesNo);
          if (result1 == DialogResult.No)
          {
               return;
          }
    }
    string[] dirs = Directory.GetDirectories(txtDestinationFolder.Text);

    // Grabs the folders in the newly created directory
    foreach (string dir in dirs)
          lstDestinationFinal.Items.Add(dir);

    //send sample file contents to preview window
    string[] sampleFiles = Directory.GetFiles(lstDestinationFinal.Items[0].ToString());

    //grabs the files
    foreach (string zipFiles in sampleFiles)
         lstSampleFile.Items.Add(zipFiles);

    ExecuteSecure(() =>tabControl1.SelectedTab = tabPage2);
});

}

And the added Method:

 private void ExecuteSecure(Action action)
    {
        if (InvokeRequired)
        {
            Invoke(new MethodInvoker(() => action()));
        }
        else
        {
            action();
        }
    }

Upvotes: 2

Views: 2703

Answers (4)

M. Nasir Javaid
M. Nasir Javaid

Reputation: 5990

Try this

Task.Factory.StartNew(() =>
{
     for (int i = 0; i < 10; i++)
     {              
          Invoke(new MethodInvoker(() => label9.Text = "Processing " + i.ToString()));
          Thread.Sleep(1000);
     }
});

EDIT:

Task.Factory.StartNew(() =>
{
     for (int i = 0; i < 10; i++)
     {
          // Any GUI control which you want to use within thread,
          // you need Invoke using GUI thread. I have declare a method below for this
          //Now use this method as
          ExecuteSecure(() => label9.Text = "Processing " + i);
          ExecuteSecure(() => progressBar1.Value = i * 10);
          //... other code etc.
          Thread.Sleep(1000);
     }
});


//---
private void ExecuteSecure(Action action)
{
    if (InvokeRequired)
    {
        Invoke(new MethodInvoker(() => action()));
    }
    else
    {
        action();
    }
}

Upvotes: 4

Kilazur
Kilazur

Reputation: 3188

Use a BackgroundWorker if you want your UI to be updated in real time, else all the work is done on the UI thread and it remains frozen until the work is over.

private void button1_Click(object sender, EventArgs e)
    {
        int limit = 10;
        var bw = new BackgroundWorker();
        bw.WorkerReportsProgress = true;
        bw.DoWork += (s, ee) =>
        {
            for (int i = 0; i < limit; i++)
            {
                bw.ReportProgress(i);
                Thread.Sleep(1000);
            }
        };
        bw.ProgressChanged += (s, ee) => label9.Text = "Processing" + ee.ProgressPercentage.ToString();
        bw.RunWorkerAsync();
    }

Upvotes: 1

Jake
Jake

Reputation: 397

Try this:

private void button1_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < 10; i++)
        {
            label9.Text = "Processing " + i.ToString();
            Application.DoEvents();
            Thread.Sleep(1000);
        }
    }

Upvotes: -2

iamwillie
iamwillie

Reputation: 56

Maybe try

 private void button1_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 10; i++)
    {
        label9.Text = "Processing " + i.ToString();
        Thread.Sleep(1000);
        Form1.Refresh();
    }
}

Upvotes: -1

Related Questions