Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / ListView ошибка "Коллекция была изменена; невозможно выполнить операцию перечисления." / 5 сообщений из 5, страница 1 из 1
05.11.2014, 16:05
    #38796496
yura-007
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ListView ошибка "Коллекция была изменена; невозможно выполнить операцию перечисления."
Добрый день.
На форме есть ListView работающий в виртуальном режиме, ошибка возникает в событии RetrieveVirtualItem:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
        private void listView1_RetrieveVirtualItem_1(object sender, RetrieveVirtualItemEventArgs e)
        {
            d++;
            listView1.VirtualListSize = listView1.dictionaryAlarms.Count;
            var msg = (Msg)listView1.dictionaryAlarms.ElementAt(e.ItemIndex).Value;

            e.Item = new ListViewItem(
                new string[] { msg.obj, msg.startTime, msg.allTime, msg.unit, msg.message, msg.severity, msg.comment, msg.paramID, msg.node, msg.acn, msg.needAcn, msg.userID}) 
                { Tag = msg };
            listView1.Invalidate();
        }


в строке:
Код: c#
1.
var msg = (Msg)listView1.dictionaryAlarms.ElementAt(e.ItemIndex).Value;


Msg - это созданный мной класс с полями, пробовал структуру, но показалось работает медленней, а может только показалось.
listView1 - это экземпляр созданного мной класса ListViewEx:
Код: c#
1.
2.
3.
4.
5.
class ListViewEx: ListView
    {
        public Dictionary<int, Msg> dictionaryAlarms = new Dictionary<int, Msg>();
        ...
    }


В данном классе есть список dictionaryAlarms и функции заполнения\модификации данного списка. После запуска программы, после инициализации dictionaryAlarms он корректно отрисовывается в listView1, но при следующей итерации цикла обновления dictionaryAlarms происходит его модификация(удаление части старых, добавление новых, обновление оставшихся) и выскакивает данная ошибка.
Как корректно отобразить содержимое dictionaryAlarms в listView1?
Может лучше хранить то что нужно отобразить в таблице в чем-то другом, не в Dictionary? В Dictionary вроде удобно сортировать, поэтому выбор пал именно на него, пробовал List и HashTable, но опыт работы со всем что тут описано не большой, с точки зрения производительности быстрей всего получилось с Dictionary.
...
Рейтинг: 0 / 0
05.11.2014, 16:28
    #38796525
Ilya81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ListView ошибка "Коллекция была изменена; невозможно выполнить операцию перечисления."
Из каких потоков модифицируется dictionaryAlarms? Вероятно, где-то нужны блокировки с выборкой в неизменяемую коллекцию. Или ConcurrentDictionary в случае .Net 4.5.
...
Рейтинг: 0 / 0
05.11.2014, 16:40
    #38796536
yura-007
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ListView ошибка "Коллекция была изменена; невозможно выполнить операцию перечисления."
Ilya81,

dictionaryAlarms модифицируется асинхронным методом:
Код: c#
1.
2.
3.
public delegate void updateMsg(AxAWXVIEW32ocxLib.AxAWXVIEW32OCX awxViewer);
updateMsg updMsg = listView1.UpdateHashMsgList;
IAsyncResult ar = updMsg.BeginInvoke(form.awxViever, null, null);


ну т.е. listView1.UpdateHashMsgList вызывается асинхронно.
Использую .Net 4.0
блокировки с выборкой в неизменяемую коллекцию, можно чуть подробней или ссылку?
...
Рейтинг: 0 / 0
05.11.2014, 17:04
    #38796564
Ilya81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ListView ошибка "Коллекция была изменена; невозможно выполнить операцию перечисления."
Поищите для начала про оператор lock (хотя, это лишь один из способов, не всегда самый подходящий). С его использованием будет выглядеть примерно так (тоже лишь один из возможных вариантов):
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
private readonly object dictionaryAlarmsLocker = new object();
private KeyValuePair<int, Msg>[] dictionaryAlarmsSnapshot;

//после обновления
lock (dictionaryAlarmsLocker)
  dictionaryAlarmsSnapshot = dictionaryAlarms.ToArray();

//внутри метода form.awxViever тоже не забывать lock (dictionaryAlarmsLocker) !!!

var msg = (Msg)listView1.dictionaryAlarmsSnapshot.ElementAt(e.ItemIndex).Value;



А вообще, книг и статей про многопоточность достаточно.
...
Рейтинг: 0 / 0
06.11.2014, 09:49
    #38796981
yura-007
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ListView ошибка "Коллекция была изменена; невозможно выполнить операцию перечисления."
Ilya81,

Спасибо за помощь. С многопоточностью время от времени приходится работать, всплывают задачи, поэтому оператор lock не является черным ящиком. Тут проблема именно с архитектурой, как это все увязать чтоб оно работало. Вставил приведенные вами конструкции в свой код, работает как нужно! Огромное спасибо, сам бы долго догадывался)
Тема закрыта.
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / ListView ошибка "Коллекция была изменена; невозможно выполнить операцию перечисления." / 5 сообщений из 5, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]