0

I am working on a C# program using Visual Studio. I'm trying to get a thread to change the controls (e.g. the text on a pushbutton) on a form and have been unsuccessful.

I have looked for examples on the Internet but have not found anything that matches what I'm trying to achieve.

An example of what I'm attempting is as follows:

  1. press a button on the form;
  2. create a thread that performs some actions (this thread needs to take in some parameters)
  3. on completion of the above thread, the text on another button on the form is changed (this button is also disabled).

A simplified set of example code of what I'm trying to achieve is shown in the four files below.

I have looked into callbacks and invokes but am getting very confused. I am new to C#, but have experience of using C/C++.

Can anyone explain how I change the controls in such a way, please?

Thanks

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DisableButtonFromThread
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Form1.cs

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

namespace DisableButtonFromThread
{
    public partial class Form1 : Form
    {
        int testInteger = 3;
                
                public Form1()
        {
            InitializeComponent();
        }

        private void btn_UseThreadDisableOtherButton_Click(object sender, EventArgs e)
        {
            // create object for thread
            DisableButton disButton = new DisableButton(testInteger);

            // create the thread
            Thread threadDisableButton = new Thread(new ThreadStart(disButton.ThreadProc));

            // start the thread
            threadDisableButton.Start();

        }

        /*
         * Callback
         */
        static void disableButtonCatcher()
        {
            btn_ToBeDisabled.Enabled = false;
            btn_ToBeDisabled.Text = "Now Disabled";
        }
    }
}

Form1.Designer.cs

namespace DisableButtonFromThread
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()...

        #endregion

        private System.Windows.Forms.Button btn_ToBeDisabled;
        private System.Windows.Forms.Button btn_UseThreadDisableOtherButton;
    }
}

DisableButton.cs

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

namespace DisableButtonFromThread
{
    class DisableButton
    {
        int dataIn = 0;

        public DisableButton(int _dataIn)
        {
            dataIn = _dataIn;
        }

        // the thread procedure to perform the task
        public void ThreadProc()
        {
            dataIn = dataIn * 2;

            // now change the text and disable the other button on Form1
            // ??
        }
    }

}
Ronw
  • 1
  • 1
  • Does this answer your question? [Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on](https://stackoverflow.com/questions/142003/cross-thread-operation-not-valid-control-accessed-from-a-thread-other-than-the) – Klaus Gütter Jul 06 '21 at 11:23
  • Why do you feel you need a multithreaded approach? – Caius Jard Jul 06 '21 at 11:26
  • 1
    There is an easier way to do what you want, without creating a `Thread` explicitly. You can offload the expensive calculation to a `ThreadPool` thread using the `Task.Run` method, then `await` the returned `Task` (the `btn_UseThreadDisableOtherButton_Click` handler must be marked with the `async` keyword), and you are back on the UI thread having the result of the calculation at hand. You can see an example of this approach [here](https://stackoverflow.com/questions/68052346/await-dispatcher-invokeasync-vs-dispatcher-invoke/68053609#68053609). – Theodor Zoulias Jul 06 '21 at 11:36
  • If you're sticked with `Threads` you should create an event in the `DisabledButton` class and the `Form1` should register on that. In that eventhandler you should check if `InvokeRequired` returns true. Check: https://stackoverflow.com/questions/2367718/automating-the-invokerequired-code-pattern – Jeroen van Langen Jul 06 '21 at 12:33
  • What you've described is one of the most commonly asked questions on SO and there are tons of resources on the internet about this. Can you explain why your situation is different? – Enigmativity Jul 07 '21 at 00:57

0 Answers0