基于计时器抛出的更新集合'集合被修改;枚举操作可能无法执行。

时间:2018-05-03 14:12:44

标签: c# wpf collections system.reactive

我正在使用Reactive Extensions和ReactiveUI定期更新Process个对象的集合。

当选中复选框时,将填充绑定到DataGrid的属性Processes,并设置一个计时器以每200ms更新所有进程。退出的进程将被删除。

执行foreach时有时会抛出Collection was modified; enumeration operation may not execute.异常。我不明白,因为我在迭代时没有删除或添加对象(仅设置ProcessModel的属性)

定时器是否等到一切都完成后才再次开火?

视图模型

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 :(得分:-1)

最好发布minimal, complete, verifiable example来帮助您。这不可能像编写的那样进行调试或测试。

作为一种猜测,我认为你有一些由OnPropertyChanged(nameof(ProcessObject));调用触发的处理程序。此处理程序可能会从可枚举中删除并可能重新添加该对象。要进行测试,您可以分离处理程序,或者删除调用并查看是否仍然发生异常。