-4

I'm trying to accomplish a simple task, update a progress bar in a Form from a different thread, after more than 4 hour or so of googleing around I'm still not able to master that.. This is my code so far, where I'm getting wrong? can Anyone point me in the right direction?

namespace ImageLoader
{
    public partial class Form1 : Form
    {
        BackgroundWorker bgw = new BackgroundWorker();
        public Form1()
        {
            InitializeComponent();
            bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
            bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);
            bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
            bgw.WorkerReportsProgress = true;
        }
        private void button1_Click(object sender, EventArgs e)
        {

            bgw.RunWorkerAsync();
        }
        void bgw_DoWork(object sender, DoWorkEventArgs e)
        {

            Excel.Worksheet activeWorksheet = ((Excel.Worksheet)Globals.ThisAddIn.Application.ActiveSheet);
            bool test = false;
            bool testStr = false;
            int urlsColPos = 0;
            int imgColPos = 0;
            object result;
            object result2;
            result = textBox1.Text;
            result2 = textBox2.Text;
            string urlValidi = "http";
            if (result == "" || result2 == "")
            {
                MessageBox.Show("Uno dei due campi non è stato valorizzato, compilare entrambi i campi prima di continuare.");
                test = false;
            }
            else
            {
                urlsColPos = char.ToUpper(Convert.ToChar(result)) - 64;
                imgColPos = char.ToUpper(Convert.ToChar(result2)) - 64;
                var s1 = (activeWorksheet.Cells[2, urlsColPos] as Excel.Range).Value.ToString();
                var s2 = (activeWorksheet.Cells[2, imgColPos] as Excel.Range).Value;
                testStr = s1.Contains(urlValidi);
                if (testStr == false)
                {
                    MessageBox.Show("La colonna specificata per l'origine URLs non contiene URL validi");
                }
                if (s2 != null)
                {
                    MessageBox.Show("La colonna dove inserire le immagini non è vuota");
                }
                if (testStr == true && s2 == null)
                {
                    test = true;
                }
            }
            if (test == true)
            {
                HttpWebResponse response = null;
                Excel.Range range = activeWorksheet.UsedRange;
                double lastRow = range.Rows.Count;
                activeWorksheet.Rows.RowHeight = 62;
                activeWorksheet.Columns.ColumnWidth = 12;
                for (var i = 2; i <= lastRow; i++)
                {
                    Application.DoEvents();
                    Microsoft.Office.Interop.Excel.Range oRange = (Microsoft.Office.Interop.Excel.Range)activeWorksheet.Cells[i, imgColPos];
                    //const float ImageSize = 45;
                    float Left = (float)((double)oRange.Left + 2);
                    float Top = (float)((double)oRange.Top + 1);
                    var imgUrl = (string)(activeWorksheet.Cells[i, urlsColPos] as Excel.Range).Value;
                    int ultimaRiga = (int)lastRow;
                    int percents = (i * 100) / ultimaRiga;
                    //progressBar1.Step = 1;
                    //progressBar1.Value = i;
                    bgw.ReportProgress(percents, i);
                    try
                    {
                        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(imgUrl);
                        request.Method = "GET";
                        response = (HttpWebResponse)request.GetResponse();
                        StreamReader sr = new StreamReader(response.GetResponseStream());
                        byte[] imgData = new WebClient().DownloadData(imgUrl);
                        MemoryStream imgStream = new MemoryStream(imgData);
                        Image img = Image.FromStream(imgStream);
                        float wSize = img.Width;
                        float hSize = img.Height;
                        if (hSize > wSize) //Verticale
                        {
                            activeWorksheet.Shapes.AddPicture(imgUrl, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, Left + 14, Top, 40, 60);
                        }
                        else
                        {
                            activeWorksheet.Shapes.AddPicture(imgUrl, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, Left + 3, Top + 10, 60, 40);
                        }
                        Application.DoEvents();

                        //Console.Write(sr.ReadToEnd());

                    }
                    catch (WebException f)
                    {
                        activeWorksheet.Cells[i, 10] = "Errore Server Remoto Nuxie";
                    }
                    finally
                    {
                        response.Close();
                    }


                }
                this.Close();
            }
        }
        void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;

        }
        void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            return;
        }
    }
}
FabioEnne
  • 732
  • 1
  • 14
  • 43
  • 2
    What is the problem and what are the min and max values of the prograssbar? – Romano Zumbé Jul 17 '17 at 12:42
  • Is the code fragment in `DoWork` executed in some sort of loop? – Romano Zumbé Jul 17 '17 at 12:43
  • @RomanoZumbé well actually tha doesn't matter it says that I can't access my progressbar due to "Invalid cross threading operation" – FabioEnne Jul 17 '17 at 12:44
  • and that exception is thrown in `bgw_ProgressChanged`? – Romano Zumbé Jul 17 '17 at 12:45
  • You might have left out the actual faulty code. – user6144226 Jul 17 '17 at 12:48
  • I just rebuilt your program and can't validate your results. There must be something else happening. Do you really start the `BackgroundWorker` from a Button click? – Romano Zumbé Jul 17 '17 at 12:50
  • @RomanoZumbé the error occour on "progressBar1.Value = e.ProgressPercentage;" – FabioEnne Jul 17 '17 at 12:56
  • @FabioEnne That can only be the case if you start the `BackgroundWorker` from another `Thread` than the `Form` is running in. So I assume, that you don't start it on the `Button` click? – Romano Zumbé Jul 17 '17 at 12:59
  • @RomanoZumbé yes is starting on butto click..as per my above code: private void button1_Click(object sender, EventArgs e) { bgw.DoWork += new DoWorkEventHandler(bgw_DoWork); bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged); bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted); bgw.WorkerReportsProgress = true; bgw.RunWorkerAsync(); } – FabioEnne Jul 17 '17 at 13:01
  • Possible duplicate of [How to update the GUI from another thread in C#?](https://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c) – C-Pound Guru Jul 17 '17 at 13:02
  • @C-PoundGuru this is a completely different topic – Romano Zumbé Jul 17 '17 at 13:08
  • @FabioEnne BGW is a very old class, available since the first days of .NET. If there were any problems people would have noticed 15 years ago. The ProgressChanged event won't throw because it's raised in the original thread, ie the UI thread. Post *actual* code that reproduces the problem and the *call stack*. – Panagiotis Kanavos Jul 17 '17 at 13:08
  • @FabioEnne `MessageBox.Show` inside `DoWork`? I seriously doubt the exception was thrown in `ProgressChanged` – Panagiotis Kanavos Jul 17 '17 at 13:10
  • 1
    @FabioEnne touching a COM Automation object from a *different* thread than the one that created it, will also cause cross-threading issues – Panagiotis Kanavos Jul 17 '17 at 13:12
  • 1
    @FabioEnne `Application.DoEvents()` from a background thread, that's another thing that touches UI controls from a background thread – Panagiotis Kanavos Jul 17 '17 at 13:14
  • @FabioEnne I agree with Panagiotis. There are several issues with your code. You should fix them and then try again. The part in ProgressChanged should work without problems – Romano Zumbé Jul 17 '17 at 13:15

1 Answers1

0

Apparently there are some erros that could be generate the cross-threading issues.

For example, you don't need to use the Application.DoEvents(), because you are using the BackgroundWorker, so the Progress Bar will refresh automatically when you set the value at the bgw_ProgressChanged method.

And also you don't need to "calculate" the percentage, like in the line:

int percents = (i * 100) / ultimaRiga;

If you just set the Progress Bar Maximum and after the Value, Windows Forms will automatically calculate the percentage, and set the progress correctly in Progress Bar.

In you code you can do this:

//...
double lastRow = range.Rows.Count;
bgw.ReportProgress(-1, lastRow); // Just to set the Maximum value
//...

//...
//int ultimaRiga = (int)lastRow;
//int percents = (i * 100) / ultimaRiga;
bgw.ReportProgress(i); // Just send the actual value / step
//...

//...
void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    if (e.ProgressPercentage == -1)
    {
        progressBar1.Maximum = (int)e.UserState;
        progressBar1.Value = 0;
    }
    else
        progressBar1.Value = e.ProgressPercentage;
}
//...