Asynchronous Calls And Thread-Safe Control Usage In .NET

Introduction

When using asynchronous programming with Windows Forms controls, you need to remember that background threads cannot directly invoke controls that were not created by them. If you want a control to be manipulated from within a background thread, you first need to check if the call to the control is safe or not and then make a call to it. To achieve this, you use a combination of the InvokeRequired property and Invoke() method of the Control class.

Working of InvokeRequired Property

The InvokeRequired property returns false if the current thread is one that created the control and no special invoke is required to use the control. The property returns true if the control is being accessed from a different thread than the one it was created on and has to be invoked using the Invoke() method. The following code demonstrates this,

public delegate void SetColorDelegate()
public void setColor() {
    MessageBox.Show(pnlstatus.InvokeRequired.ToString());
    if (pnlStatus.InvokeRequired) {
        Set ColorDelegate del = new SetColorDelegate(SetColor);
        this.Invoke(del);
    } else {
        pnlStatus.BackColor = Color.Tomato;
    }
}
private void bgWrkrDownload_DoWork(object sender, DoWorkEventArgs e) {
    //some background action
    set Color();
}

 When the background task is in progress, the panel background color needs to change. However, if you try to access the panel control directly through the background thread, an error may occur because the owner of the control is different from the one invoking it. To avoid the error, you check the InvokeRequired property and create a delegate for the method containing the action and call Invoke with that delegate. Within Invoke, you pass a delegate to a method that will actually perform the action desired on the control. For example, in this case, you want to change the background color of the panel. Instead of doing it directly, you change it within a method named SetColor() and call SetColor() in the DoWork event handler. This way, you can be sure that you are making thread-safe calls to the control.

Summary

The InvokeRequired property returns false if the current thread is one that created the control and no special invoke is required to use the control. Use InvokeRequired property and create a delegate for the method containing the action and call Invoke with that delegate.