Electronics DIY blog

DIY is fun and is food for the brain and spirit. Don't be afraid to learn.



Showing posts with label Threads. Show all posts
Showing posts with label Threads. Show all posts

Thursday, February 7, 2013

C# Getting around Illegal Thread Safe Calls

Every time you try to mess with a control from a thread other than the owner-thread you will get the IllegalCrossThreadCall exception and your app will crash.

The lazy/dangerous way to get around this is to set the Control.CheckForIllegalCrossThreadCalls on the owner/parent control to false.

If your absolutely sure of what you're doing it's ok. But still not advisable.

The right way is to perform a check on the InvokeRequired property of the control and if so Invoke/BeginInvoke (synchronously or asynchronously it's up to you) the method via a delegate.
This is fine but if you have to expand this along your code it gets kind of boring.

If you read my previous article I've talked about a cool .NET feature called Extension Methods.

What I'll show you next is a very handy peace of code that you can put in a library and reuse in any app you do.

using System;
using System.Windows.Forms;

namespace Extensions
{
    public delegate void UIDelegate();

    /// <summary>
    /// Control class extension methods
    /// </summary>
    static public class ControlExtensions
    {
        /// <summary>
        /// Performs a UI Thread safe Control.Invoke.
        /// </summary>
        /// <param name="control">Target control.</param>
        /// <param name="dlg">delegate method to be invoked.</param>
        static public void SafeInvoke(this Control control, UIDelegate dlg)
        {
            if (control.InvokeRequired)
            {
                control.Invoke(dlg);
                return;
            }

            dlg.Invoke();
        }

        /// <summary>
        /// Performs a UI Thread safe Control.BeginInvoke.
        /// </summary>
        /// <param name="control"></param>
        /// <param name="dlg">delegate method to be invoked asynchronously.</param>
        static public void BeginSafeInvoke(this Control control, UIDelegate dlg)
        {
            if (control.InvokeRequired)
            {
                control.BeginInvoke(dlg);
                return;
            }

            dlg.Invoke(null, null);
        }
    }
}

Basically I've extended the Control type class and "added" 2 new methods.

To perform a thread safe operation inside, for example a form, we only have to add our Extensions namespace and call the code like this.

this.SafeInvoke(delegate
{
    /// do stuff...
});

That's it. It's a pretty clean away of performing operations over controls in a thread safe manner.

;-)