Link to home
Start Free TrialLog in
Avatar of deleyd
deleydFlag for United States of America

asked on

How does the delegate know which thread to run the method on?

The following sample program creates a form with a textbox and a button.
When the button is pressed, it writes "Written by the main thread" to the textbox
starts a second thread,
the second thread waits 2 seconds, then writes "Written by the background thread" to the textbox via:

line 50:    string text = "Written by the background thread.";
line 56:    SetTextCallback d = new SetTextCallback(SetText);
line 57:    this.Invoke (d, new object[] { text + " (Invoke)" });

Questions:
1. How does the delegate know which thread to run the SetText method on?

2. on line 57, Is the new object[] part necessary?
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace CrossThreadDemo
{
    public class Form1 : Form
    {
        // This delegate enables asynchronous calls for setting
        // the text property on a TextBox control.
        delegate void SetTextCallback(string text);

        // This thread is used to demonstrate thread-safe way
        // to call a Windows Forms control.
        private Thread demoThread = null;
        private TextBox textBox1;
        private Button setTextSafeBtn;

        public Form1()
        {
            InitializeComponent();
        }

        // This event handler creates a thread that calls a
        // Windows Forms control in a thread-safe way.
        private void setTextSafeBtn_Click(
            object sender,
            EventArgs e)
        {
            // Create a background thread and start it.
            this.demoThread = new Thread(new ThreadStart(this.ThreadProcSafe));
            this.demoThread.Start();

            // Continue in the main thread.  Set a textbox value
            // that will be overwritten by demoThread.
            textBox1.Text = "Written by the main thread.";
        }

        // If the calling thread is different from the thread that
        // created the TextBox control, this method passes in the
        // the SetText method to the SetTextCallback delegate and
        // passes in the delegate to the Invoke method.
        private void ThreadProcSafe()
        {
            // Wait two seconds to simulate some background work
            // being done.
            Thread.Sleep(2000);

            string text = "Written by the background thread.";
            // Check if this method is running on a different thread
            // than the thread that created the control.
            if (this.textBox1.InvokeRequired)
            {
                // It's on a different thread, so use Invoke.
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke (d, new object[] { text + " (Invoke)" });
            }
            else
            {
                // It's on the same thread, no need for Invoke
                this.textBox1.Text = text + " (No Invoke)";
            }
        }

        // This method is passed in to the SetTextCallBack delegate
        // to set the Text property of textBox1.
        private void SetText(string text)
        {
            this.textBox1.Text = text;
        }


        #region Windows Form Designer generated code
        private void InitializeComponent()
        {
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.setTextSafeBtn = new System.Windows.Forms.Button();
            this.SuspendLayout();
            //
            // textBox1
            //
            this.textBox1.Location = new System.Drawing.Point(12, 12);
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(360, 20);
            this.textBox1.TabIndex = 0;
            //
            // setTextSafeBtn
            //
            this.setTextSafeBtn.Location = new System.Drawing.Point(96, 55);
            this.setTextSafeBtn.Name = "setTextSafeBtn";
            this.setTextSafeBtn.TabIndex = 2;
            this.setTextSafeBtn.Text = "Safe Call";
            this.setTextSafeBtn.Click += new System.EventHandler(this.setTextSafeBtn_Click);
            //
            // Form1
            //
            this.ClientSize = new System.Drawing.Size(388, 96);
            this.Controls.Add(this.setTextSafeBtn);
            this.Controls.Add(this.textBox1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();
        }
        #endregion

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.Run(new Form1());
        }
    }
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of saragani
saragani

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of deleyd

ASKER

Interesting idea to put the InvokeRequired() check INSIDE the SetText() method. SetText() calls itself.

Why does it still work if I remove the new object[] part and just pass text? Why is this bad to do?
this.Invoke(d, text + " (Invoke)" );

Open in new window

It seems to compile and run without complaint.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of deleyd

ASKER

Super. I'm going to follow-up with another question which I'll start a new post and add comment here pointing to it.