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 に答える