Я использую 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
}
}