简体   繁体   中英

C# Wpf Foreach InvalidOperationException Multithreading

I have a Canvas with a lot of little Canvas inside. If I click any of them, it creates a Thread with a specific method (add another little canvas to the main canvas and move around it for example). I need to make some of those little canvas grow when I click a specific button. So I tried with a foreach loop but the application crashes and shows me this error:

InvalidOperationException: Collection was modified; enumeration operation may not execute

I thought that happens because there was a context switching, so I added a lock to the method, but the problem continues. My code is below:

private void BacteriaPsiEspecial(object sender , MouseButtonEventArgs e) 
{
  lock (sender)//Maybe here is the problem
  {
    //The application crashes here
    foreach (Canvas LittleCanvas in CanvasSimulador.Children)
    {
      if(LittleCanvas.Uid.Equals("SomeId")) 
      {
        //Method to make each one grow growMethod()
      }
    }
  }
}

I don't know if foreach works to do this. I have to use a lot of threads because all the little canvases are continually moving around the main canvas. The question is, what can I do to make some of those canvas be affected by growMethod()?

It sounds like you have multiple threads changes the collection you're trying to foreach over. Simply put, this won't work. Here are a few options I can think of:

  • Put around everything that modifies (add/removes) from the collection you're looping over. This however, will partially eliminate the benefit of using multiple threads, and depending how you write you code, could lead to a deadlock where no thread can proceed since they're all waiting for the lock.
  • If the growMethod() takes a significant amount of time, you could try getting a copy of the list before iterating over it... the LINQ extension methods .ToList() or .ToArray() should work. But you'd probably still hit the exception, so you might end up adding retry logic, etc... yuck.
  • You could potentially limit access to your collection by putting a lock around when you access and modify it:

     private IEnumerable<Canvas> GetLittleChildren() { lock(lockObject) { return CanvasSimulador.Children.ToArray(); } } private IEnumerable<Canvas> AddChild(Canvas littleCanvas) { lock(lockObject) { CanvasSimulador.Children.Add(littleCanvas); } } private IEnumerable<Canvas> RemoveChild(Canvas littleCanvas) { lock(lockObject) { CanvasSimulador.Children.Remove(littleCanvas); } } 

    I'm still not convinced that's a good method, but it might work...

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