A
A
astrotrain2016-01-08 12:26:13
C++ / C#
astrotrain, 2016-01-08 12:26:13

[C#] How to make changes to the user interface from another thread of another class?

I have a class that must implement multithreading (you will see everything on the example). It performs some actions, and the graphical interface should be updated accordingly. I know it's a bad practice to link gui and logic (it's sort of like using events for this), but at the moment I need to figure out exactly this approach. Here is the class code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Windows.Forms;
using System.Collections;
using System.Threading;

namespace WindowsFormsApplication2
{
   
    class test
    {
        
        public List<Thread> threads = new List<Thread>();
        public int nThreads = 0;
        public int maxThreads = 5;
        public ListBox Lb;
        public object obj = new object();

        public void DoWork(object data)
        {
           
            string mess = (string)data;
            //MessageBox.Show(mess);        
            Action action = () =>
            {
                Lb.Items.Add(mess);
            };

            lock(obj)
            {

                if (Lb.InvokeRequired)
                    Lb.Invoke(action);
                else
                     action();                

            }      
                              
                      
        }

        public void CreateThread(object data)
        {
            if (nThreads >= maxThreads)
                return;
            Thread newThread = new Thread(DoWork);
            threads.Add(newThread);
            newThread.IsBackground = true;
            newThread.Start(data);
            nThreads++;
            

        }

        public void WindUpThreads()
        {
            //MessageBox.Show("count: " + nThreads.ToString());
            for(int i = 0; i < threads.Count; i++)
            {
                if (threads[i].IsAlive == false)
                {
                    threads[i].Abort();
                    threads.RemoveAt(i);
                   //MessageBox.Show("removing at " + i.ToString());
                }

            }

            nThreads = threads.Count;
        }
        
    }

      

}

That is, I pass a listbox object into it and call invoke at a certain time. Here is how the class is called from the form:
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.Threading;
using System.IO;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public object obj = new object();
        public Form1()
        {
            InitializeComponent();

           //MessageBox.Show("Done");
           //thTest.WindUpThreads();
           //MessageBox.Show(thTest.nThreads.ToString());
           
            
        }

        private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            test thTest = new test();
            thTest.Lb = listBox1;
            

            string[] strings;
            try
            {

                strings = File.ReadAllLines("C:\\users\\alex\\desktop\\test.txt");
            }

            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }
                       
            bool flag = true;
            int counter = 0;
            int dataCount = strings.Length;

           

            while (flag == true)
            {
                if (counter >= dataCount)
                {
                    flag = false;
                }

                while (thTest.nThreads < thTest.maxThreads)
                {
                    if (flag == false)
                        break;
                    
                    thTest.CreateThread(strings[counter]);
                    
                    counter++;
                }

                thTest.WindUpThreads();

                if (flag == false)
                {
                    do
                    {
                        thTest.WindUpThreads();

                    } while (thTest.nThreads != 0);
                }
                


            }
           
            listBox1.Items.Add("Done");

        }

             

    }
}

But the program hangs, and an exception is shown in the debugger instead of invoke (which for some reason is not thrown):
+		Lb	{SelectedItem = "((System.Windows.Forms.Control)(Lb)).Text" запустило исключение типа "System.InvalidOperationException"}	System.Windows.Forms.ListBox

What could possibly be the problem? What did I miss? After all, this is a simple example, it should work.

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question