简体   繁体   中英

Inconsistent “Cross-thread operation not valid” exception

Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.

My colleague is getting this exception on my code but i am not.

On a form i have a control where a user is able to add some strings to a ListView.

Ive exposed a property in my control which returns the strings inside an XmlDocument.

public XmlDocument XmlConfig
{
    get
    {
        return GetXML();
    }
}

Get XML just takes the ListViewItem collection and formats them into an xml document.

private XmlDocument GetXML()
{
    foreach(ListViewItem lvi in myListView.Items)   <-- Exception Here
    {
         // Do Stuff
    }
}
  1. Why am i getting this when just trying to read the list view? I thought cross thread exceptions were when you were trying to update the control from a separate thread.

  2. Why am i not getting this exception too?

I thought cross thread exceptions were when you were trying to update the control from a separate thread

Not true. cross-thread exceptions occur when a control is accessed from not the main UI thread. The solution is trivial, check InvokeRequired and use Invoke .

As to why your friend hits this and you don't, is impossible to tell from the code you posted. It may be he compiles against different .Net target version, or it could be a race condition that your hardware doe snot hit (eg. he has more cores). Point is that is irrelevant. Your code needs to be thread safe as apparently GetXML can and is invoked from non main UI thread. It may well be that the responsibility to check for InvokeRequired should be on the caller, not the method. Again, is impossible to tell from the code posted.

When accessing Control in other than UI thread ( InvokeRequired returns true ) you should use Invoke insetead of direct call; in order not to duplicate the code (for UI thread and for other threads) let's use extension method:

  private XmlDocument GetXML() {
    myListView.InvokeSynchronized(() => {
      foreach(ListViewItem lvi in myListView.Items) {
        // Do Stuff
      }
    });
  }

  ...

  public static class ControlAsyncExtensions {
    public static void InvokeSynchronized(this Control control, Action action) {
      if (Object.ReferenceEquals(null, action))
        throw new ArgumentNullException("action");

      if (Object.ReferenceEquals(null, control))
        action();
      else if (control.InvokeRequired)
        control.Invoke(action);
      else
        action();
    }
  }

I thought cross thread exceptions were when you were trying to update the control from a separate thread.

That's not correct. Remember, most of the WinForms controls are wrappers around Windows common controls. And Windows controls use messages for both retrieving and updating, usually via SendMessage function . So in general, although some calls could be safe to be performed from another thread, for the safety reasons Control.CheckForIllegalCrossThreadCalls is used in the control implementations on every get/set property or method call.

Why am i not getting this exception too?

It doesn't matter, you should not be doing that at the first place.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM