user3803552
user3803552

Reputation: 13

What is the proper method for using invoke to avoid threading errors?

I have been recently learning C# and have a problem I just cant seem to wrap my head around. Please forgive me if this is noobish as I am very new to C# but my question is about delegates and invoke. I have read many many tutorials online and watched many video tutorials about this as well but I am still getting the same error in my code and I just dont seem to grasp the subtleties. As I understand it a delegate is a pointer to a function and can be used to invoke that function from say another thread to update a textbox. I understand creating a delegate, that much I think I am doing right but when I invoke the delegate from a threat I always get the error Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.

The callback appears to be functional as it is calling the function that it is designed to however it does not seem to do it on the correct thread which I thought was the whole point of doing it this way. I know there is the option to set that warning break to false but I would rather learn what I am doing wrong and how to code this type of method properly. I appreciate any help, suggestions or answers you can provide as I am not sure any more of the tutorials are getting me any closer at this point to understanding where I have gone wrong.

My code is very basic and as I am just trying to understand the most basic concepts of properly coding for multithreading. Below is my code.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Media;
using System.Threading;
using System.Reflection;

namespace WindowsFormsApplication3
{   

    //declair delegate name(vars) CORRECT
    public delegate void Textboxdelegate(Int64 MyVar);

    public partial class Form1 : Form
    {

         public Form1()
         {
             InitializeComponent();
         }

         public void button1_Click(object sender, EventArgs e)
         {
             runme();
         }

         public void runme()
         {
             textBox1.Text = "87";
             textupdate(44);

             int target = 0;
             Textboxdelegate TD = new Textboxdelegate(textupdate);
             Number number = new Number(target, TD);
             TD(11);
             Thread thread1 = new Thread(new ThreadStart(number.worker));
             thread1.Start();

         }
        public void textupdate(Int64 cntr) 
        {
           textBox1.Text += cntr.ToString();
        }

    }

    class Number
    {

    int _target;
    Textboxdelegate _callbackMethod;

    public Number(int target, Textboxdelegate TDD)
    {
        this._target = target;
        this._callbackMethod = TDD;
    }

    public void worker()
    {

            Int64 counter = 0;
            byte[] lifeforms = new byte[2146435071];

            for (long y = 1; y <= 2146; y++)
            {

                for (long X = 1; X <= 1000000; X++)
                {
                    lifeforms[X * y] = 20;
                }

                counter += 1;
                if(_callbackMethod != null)
                {
                _callbackMethod(counter);
                }

            }

            MessageBox.Show("Done!");
        }

    }
}

Upvotes: 0

Views: 188

Answers (1)

terrybozzio
terrybozzio

Reputation: 4542

This crude example should do it for what you want to do:

    //public delegate void Textboxdelegate(Int64 MyVar);

    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
        }

        public Action<Int64> Textboxdelegate;
        public void runme()
        {
            textBox1.Text = "87";
            textupdate(44);

            int target = 0;
            Textboxdelegate = textupdate;
            Number number = new Number(target, Textboxdelegate,this);
            Textboxdelegate(11);
            Thread thread1 = new Thread(new ThreadStart(number.worker));
            thread1.Start();

        }
        public void textupdate(Int64 cntr)
        {
            textBox1.Text += cntr.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            runme();
        }

    }

    class Number
    {

        int _target;
        Action<Int64> _callbackMethod;
        Form1 frm;

        public Number(int target, Action<Int64> act,Form1 frm)
        {
            this._target = target;
            this._callbackMethod = act;
            this.frm = frm;
        }

        public void worker()
        {

            Int64 counter = 0;
            byte[] lifeforms = new byte[214643507];

            for (long y = 1; y <= 2146; y++)
            {

                for (long X = 1; X <= 100000; X++)
                {
                    lifeforms[X * y] = 20;
                }

                counter += 1;
                if (_callbackMethod != null)
                {
                    if (frm.InvokeRequired)
                    {
                        frm.Invoke(_callbackMethod,new object[]{counter});
                    }
                    else
                    {
                        _callbackMethod(counter);
                    }
                }

            }

            MessageBox.Show("Done!");
        }

    }

Controls have thread-afinity,meaning they can only be accessed from the thread that created them,and you where accessing them by another thread.Now the Invoke method of the Control class(the base of form and all its controls)will allow you to safelly access them(very summarized explanation).

Upvotes: 1

Related Questions