Обновлена ​​коллекция на основе бросков по таймеру. Коллекция изменена; операция перечисления может не выполняться. ' - PullRequest
0 голосов
/ 03 мая 2018

Я использую Reactive Extensions и ReactiveUI для периодического обновления коллекции Process объектов.

Когда флажок установлен, свойство Processes, связанное с DataGrid, заполняется, и таймер устанавливается для обновления каждые 200 мс всех процессов. Процессы, которые вышли, удалены.

Исключение Collection was modified; enumeration operation may not execute. иногда выдается при выполнении foreach. Я не понимаю, потому что я не удаляю и не добавляю объекты в коллекцию при итерации (просто устанавливаю свойство ProcessModel)

Также таймер ждет, пока все не будет завершено, прежде чем снова выстрелить?

ViewModel

private ReactiveList<IProcessModel> _processes = new ReactiveList<IProcessModel>() { ChangeTrackingEnabled = true };
public ReactiveList<IProcessModel> Processes { get { return _processes; } }

IDisposable timer;

private void DoShowProcesses(bool checkboxChecked)
{
    Processes.Clear();
    if (checkboxChecked)
    {
        //checkbox checked
        lock (Processes)
            Processes.AddRange(_monitorService.GetProcesses());
        timer = Observable.Timer(TimeSpan.FromMilliseconds(200.0))
            .Select(x =>
        {
            lock (Processes)
            {
                foreach (var process in Processes) //throws the 'Collection was modified; enumeration operation may not execute.'
                    process.UpdateMemory(); 

                return Processes.Where(p => p.ProcessObject.HasExited).ToList();
            }
        }).
        ObserveOnDispatcher()
        .Subscribe(processesExited =>
        {
            if (processesExited.Count() > 0)
            {
                lock (Processes)
                    Processes.RemoveAll(processesExited); //remove all processes that have exited
            }

        });
    }
    else
    {
        if (timer != null)
            timer.Dispose();
    }
}

ProcessModel

public class ProcessModel : ProcessModelBase, IProcessModel
{

    public ProcessModel(Process process)
    {
        ProcessObject = process;

    }

    public void UpdateMemory()
    {
        try
        {
            if (!ProcessObject.HasExited)
            {
                long mem = ProcessObject.PagedMemorySize64;
                ProcessObject.Refresh();
                if (mem != ProcessObject.PagedMemorySize64)
                    OnPropertyChanged(nameof(ProcessObject));
            }
        }
        catch (Exception)
        {
            //log it
        }
    }

1 Ответ

0 голосов
/ 03 мая 2018

Лучше всего опубликовать минимальный, полный, проверяемый пример , чтобы помочь вам. Это невозможно отладить или проверить как написано.

Я бы предположил, что у вас есть какой-то обработчик, который запускается вызовом OnPropertyChanged(nameof(ProcessObject));. Этот обработчик, вероятно, удаляет и, возможно, повторно добавляет объект из перечисляемого. Чтобы проверить, вы можете отсоединить обработчик или удалить вызов и посмотреть, происходит ли исключение.

...