Make InvokeRequired/Invoke easy

The problem

If you’re working on WinForms, you must know that you cannot call controls methods within a thread that is not the one that created those controls. To solve this problem, Microsoft recommend us to use the following code :

namespace TestWinForm
{
    public partial class MainForm : BaseForm
    {
        public MainForm()
        {
            InitializeComponent();
        }
        // a delegate that has been created specially for this method
        private delegate void DisplayDelegate(string text);

        // a method that may be called from a worker thread
        public virtual void Display(string text)
        {
            if (InvokeRequired)
            {
                Invoke(new DisplayDelegate(Display));
            }
            else
            {
                //the actual job is here
                textBox1.AppendText(text);
            }
        }
    }
}

This code is ugly because :

  • you need to create a delegate for each single public method you can call from outside
  • you need to put an “if/else” block in each method wich increase the complexity of your code

The trick

Here is a trick that could significantly reduce the amount of code needed to do the same job within a large project.

Within you base class

You probably have a common base class for all your UI components. Add this method :

namespace TestWinForm
{
    public class BaseForm : Form
    {
        // This allows a sub class to easily run a method within
        // an UI thread without the need of creating multiple 
        // delegate signatures for each method signatures
        protected virtual void ThreadSafe(MethodInvoker method)
        {
            if (InvokeRequired)
                Invoke(method);
            else
                method();
        }
    }
}

Within your UI classes

Now the only thing you need to do is to encapsulate the methode content with the ThreadSafe() method :

namespace TestWinForm
{
    public partial class MainForm : BaseForm
    {
        public MainForm()
        {
            InitializeComponent();
        }

        // public method that may be called from outside and within any
        // worker thread ...
        public virtual void Display(string text)
        {
            ThreadSafe(delegate
            {
                //do any UI related code here
                //note that because this is an anonym method, 
                //you can use the local parameter
                textBox1.AppendText(text);
            });
        }

Happy coding !

5 Replies to “Make InvokeRequired/Invoke easy”

  1. Hi German,

    The Display() can have any modifier on it, it does’nt matter.

    You could make it ‘private’ and remove the ‘virtual’ keyword if you don’t want other classes to have access to it.

    Manitra.

Leave a Reply

Your email address will not be published. Required fields are marked *