0

我有一个Canvas里面有很多小帆布。如果我单击其中任何一个,它会Thread使用特定方法创建一个(例如,将另一个小画布添加到主画布并在其周围移动)。当我点击一个特定的按钮时,我需要让一些小画布变大。所以我尝试了一个foreach循环,但应用程序崩溃并向我显示了这个错误:

InvalidOperationException:集合已修改;枚举操作可能无法执行

我认为发生这种情况是因为存在上下文切换,所以我在方法中添加了一个锁,但问题仍然存在。我的代码如下:

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()
      }
    }
  }
}

我不知道是否foreach可以做到这一点。我必须使用很多线程,因为所有小画布都在主画布周围不断移动。问题是,我能做些什么来让这些画布中的一些受到 growMethod() 的影响?

4

1 回答 1

0

听起来您有多个线程更改了您要尝试的集合foreach。简单地说,这行不通。以下是我能想到的几个选项:

  • 放置所有修改(添加/删除)您正在循环的集合中的东西。但是,这将部分消除使用多个线程的好处,并且取决于您编写代码的方式,可能会导致死锁,因为它们都在等待锁定,所以没有线程可以继续。
  • 如果growMethod()需要大量时间,您可以尝试在迭代之前获取列表的副本...... LINQ 扩展方法.ToList().ToArray()应该工作。但是您可能仍然会遇到异常,因此您最终可能会添加重试逻辑等……哎呀。
  • 您可以通过在访问和修改集合时加锁来限制对集合的访问:

    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);
      }
    }
    

    我仍然不相信这是一个好方法,但它可能会奏效......

于 2013-11-12T23:24:12.477 回答