2013-11-12 2 views
0

У меня есть Canvas с большим количеством небольшого холста внутри. Если я нажму на любой из них, он создаст Thread с определенным методом (добавьте еще один маленький холст к основному холсту и передвигайтесь по нему, например). Мне нужно сделать некоторые из этих маленьких холстов, когда я нажимаю на определенную кнопку. Так что я попытался с foreach цикла, но аварий приложений и показывает мне эту ошибку:C# Wpf Foreach InvalidOperationException Многопоточность

InvalidOperationException: Collection was modified; enumeration operation may not execute

Я думал, что происходит, потому что было переключение контекста, поэтому я добавил замок к методу, но проблема по-прежнему. Мой код ниже:

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

+0

Если вы хотите получить какую-то коллекцию, она ожидает, что сбор не изменится (т.е. вы можете добавить или удалить из коллекции). Я предполагаю, что внутри вас 'growMethod()' он меняет то, что будет частью коллекции 'CanvasSimulador.Children'. Если вы не можете определить проблему самостоятельно, не могли бы вы отредактировать вопрос, чтобы включить код в 'growMethod()'? –

+0

Я могу включить код, но я думаю, что это не поможет. Если я поставлю вместо growMethod MessageBox. Показать («Привет»); проблема продолжается. Другие методы, связанные с другими потоками, меняют коллекцию. –

ответ

0

Похоже, что у вас есть несколько потоков, которые меняют коллекцию, которую вы пытаетесь сделать foreach. Проще говоря, это не сработает. Вот несколько вариантов, о которых я могу думать:

  • Оденьте все, что изменяет (добавляет/удаляет) из коллекции, которую вы зацикливаете. Это, однако, частично устранит преимущество использования нескольких потоков и в зависимости от того, как вы пишете код, может привести к тупиковой ситуации, когда нить не может продолжаться, так как они все ждут блокировки.
  • Если growMethod() занимает значительное количество времени, вы можете попробовать получить копию списка перед итерацией по нему ... методы расширения LINQ .ToList() или .ToArray() должны работать. Но вы, вероятно, все равно попадете в исключение, так что вы можете добавить логику повтора и т. Д. ... yuck.
  • Вы могли бы потенциально ограничить доступ к вашей коллекции, поставив замок вокруг, когда вы получаете доступ и изменить его:

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

    Я все еще не уверен, что это хороший метод, но он может работать ...

+0

Я решил, что он приглашает делегатов. Но ваше решение хорошо работает, спасибо. –

Смежные вопросы