Electronics DIY blog

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



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.

;-)

No comments:

Post a Comment