I'm trying to add a progress bar to a working theaded program that uses a cancelation token too. The structure of the program is:
I have a button "BeginButton" that calls the function "MyFunction()". The function runs in another thread and
a cancellation token listens if I press a Cancel button. I needed to add the thread since the UI freezes when
MyFunction() runs and I wasn't able to stop it.

Since the MyFunction() reads a file in chunks of 1024 bytes, my logic to show the progress is get the 1% of
File.Length and check when the loop increases each 1% of File size. Then I increment the progressBaar1
when Module of "BytesRead" and "(1% of File size)" = 0, this is "BytesRead % OnePercent == 0". This logic
works in a program that doesn't use threads, but in my code with thread is not working.

How can I add the progress bar to my code?

I've added the progressBar1 control to the Form and added this code inside the while loop of my threaded program.

FileLength = (int)reader.BaseStream.Length; //Filename size
//Getting the 1% of FileName size
decimal OnePercent = Math.Truncate((Decimal)(FileLength/1024)/100); 

if ( BytesRead % OnePercent == 0 && progressBar1.Value < 100)
{
    progressBar1.Value++;
    progressBar1.CreateGraphics().DrawString(
                    progressBar1.Value.ToString() + "%", 
                    new Font("Arial",(float)8.25),Brushes.Black,100,5);
}                       
BytesRead++;    

But I get this error:

System.Reflection.TargetInvocationException: 
Exception has been thrown by the target of an invocation. 
---> System.InvalidOperationException: 
Cross-thread operation not valid: Control 'progressBar1' accessed from a thread 
other than the thread it was created on.
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Control.SendMessage(Int32 msg, Int32 wparam, Int32 lparam)
at System.Windows.Forms.ProgressBar.UpdatePos()
at System.Windows.Forms.ProgressBar.set_Value(Int32 value)
at DumpDecode1.MainForm.GetRecords(String fileName, CancellationToken token)

The was how it looks the program is:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AddingProgressBar
{
    public partial class MainForm : Form        
    {               
        // Create the token source.
        CancellationTokenSource cts = new CancellationTokenSource();      

        public MainForm()
        {   
            InitializeComponent();  
        }

        async void BeginButton_Click(object sender, EventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }           
            cts = new CancellationTokenSource();            
            await Task.Run(() => MyFunction(filename, cts.Token), cts.Token);               
        }

        public void MyFunction(string inputfile, CancellationToken token)
        {
            int BytesRead = 0;
            using (BinaryReader reader = new BinaryReader(File.Open(inputfile, FileMode.Open)))
            {
                FileLength = (int)reader.BaseStream.Length; //Filename size
                //Getting the 1% of FileName size
                decimal OnePercent = Math.Truncate((Decimal)(FileLength/1024)/100); 

                while (chunk.Length > 0) //The while loop runs Filename.Size/1024 times
                {
                    if (token.IsCancellationRequested) { break; } // ### To Cancel Thread ###                                                       

                    chunk = reader.ReadBytes(1024);
                    //Some more code

                    // ######### Code added for Progress Bar #########
                    //Checking while loop grows up in 1 percent
                    if ( BytesRead % OnePercent == 0 && progressBar1.Value < 100)
                    {
                        progressBar1.Value++;
                        progressBar1.CreateGraphics().DrawString(
                                        progressBar1.Value.ToString() + "%", 
                                        new Font("Arial",(float)8.25),Brushes.Black,100,5);
                    }                       
                    BytesRead++;
                    // ######### Code added for Progress Bar #########                  
                }                           
            }
        }       
    }
}

The main error message starts on line 4 :

Cross-thread operation not valid: Control 'progressBar1' accessed from a thread
5.other than the thread it was created on.

TRy to create the progresbar in the same thread

Hi ddanbe, thanks for your answer.
I can the function inside start button like this

await Task.Run(() => MyFunction(filename, cts.Token), cts.Token);

But the processing is done in the function, so I check the number of while loops inside the "while" that is in the function. How can I monitor the number of loops creating the progressbar inside the code of start button?

or when you say, create it in the same thread, is not needed to created inside the same Star button code where I call the "MyFunction()"?

Maybe you can help me with a little example.

Thanks in advance.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.