Search code examples
c#.netmultithreadingbackgroundworker

Cannot access form handle from within BackgroundWorker


I'm experiencing something weird. I can access many of my form's controls from within my BackgroundWorker DoWork method, but trying to get the Handle property on any of them will give me "Cross-thread operation not valid".

For example:

private void backgroundWorker1_DoWork(object sender,
    System.ComponentModel.DoWorkEventArgs e)
    {
        var usefulText = textbox1.Text;
        var formName = this.Name;
        var formHandle = this.Handle;    // this line won't work
    }


Why is it that I can access some of the Properties except for the Handle one (or so it seems)?


Solution

  • The "Cross-thread operation not valid" InvalidOperationException is the norm. I have found that for reasons unknown to me, some controls have members that can be successfully called from the wrong thread, but the documentation is very clear about which ones are expected to work:

    In addition to the InvokeRequired property, there are four methods on a control that are thread safe to call: Invoke, BeginInvoke, EndInvoke and CreateGraphics

    In other words, the real mystery in your question isn't why you get an exception trying to call the Handle property getter. It's why you don't get an exception calling the Text or Name getters.

    Personally, I find that mystery less interesting. The bottom line is that if you need to retrieve the Handle property in your DoWork event handler, you will need to use the Control.Invoke() method to access the property on the UI thread and return it back to your code in the worker thread. Alternatively, retrieve the handle value before starting the worker, and make it available to the DoWork event handler via the mechanism of your choice.


    EDIT:

    Even though I don't find the mystery all that interesting, I did go ahead and look at the referencesource.microsoft.com web site, and I can see that the Text property is handled as an explicit exception to the "no cross-thread calls" rule. There's even a comment that reads "it's okay to call GetWindowText cross-thread", and the code there (in the internal WindowText property) uses the MultithreadSafeCallScope class to disable the cross-thread check for the duration of the operaton.

    It would be nice if this were better-documented (i.e. on MSDN itself), but there you go. :)