FileSystemWatcher-添加和删除ObservableCollection,C#
本文关键字:ObservableCollection 删除 添加 FileSystemWatcher- | 更新日期: 2023-09-27 18:30:09
首先,我的代码:
private void OnChangedActive(object source, FileSystemEventArgs e)
{
try
{
switch (e.ChangeType)
{
case WatcherChangeTypes.Created:
if (File.Exists(e.FullPath))
{
MachineOrder machineOrderAdded;
machineOrderAdded = viewModel.MachineOrdersActive.FirstOrDefault(x => x.Filename == e.Name);
if (machineOrderAdded != null)
this.Dispatcher.BeginInvoke(new Action(() => viewModel.MachineOrdersActive.Remove(machineOrderAdded)));
machineOrderAdded = viewModel.MachineOrdersProductionpool.FirstOrDefault(x => x.Filename == e.Name);
if (machineOrderAdded != null)
this.Dispatcher.BeginInvoke(new Action(() => viewModel.MachineOrdersProductionpool.Remove(machineOrderAdded)));
machineOrderAdded = viewModel.MachineOrdersInProduction.FirstOrDefault(x => x.Filename == e.Name);
if (machineOrderAdded != null)
this.Dispatcher.BeginInvoke(new Action(() => viewModel.MachineOrdersInProduction.Remove(machineOrderAdded)));
this.Dispatcher.BeginInvoke(new Action(() => viewModel.MachineOrdersActive.Add(mainController.generateMachineOrder(e.FullPath))));
}
break;
case WatcherChangeTypes.Deleted:
MachineOrder machineOrder;
String message = "";
//ÜBERPRÜFEN, OB SIE IM AKTIVORDNER IST
machineOrder = viewModel.MachineOrdersActive.FirstOrDefault(x => x.Filename == e.Name);
if (machineOrder != null)
{
this.Dispatcher.BeginInvoke(new Action(() => viewModel.MachineOrdersActive.Remove(machineOrder)));
message = String.Format("Die Datei {0} existiert nicht mehr. Der dazugehörige Auftrag wurde von den aktiven Aufträgen entfernt.", machineOrder.Filename);
this.Dispatcher.BeginInvoke(new Action(() => setStatus(message, Level.INFO)));
Logger.getInstance().writeLogEntry(Logger.LogLevel.INFO, message, null);
break;
}
//ÜBERPRÜFEN, OB SIE IM FERTIGUNGSPOOL IST
machineOrder = viewModel.MachineOrdersProductionpool.FirstOrDefault(x => x.Filename == e.Name);
if (machineOrder != null)
{
this.Dispatcher.BeginInvoke(new Action(() => viewModel.MachineOrdersProductionpool.Remove(machineOrder)));
message = String.Format("Die Datei {0} existiert nicht mehr. Der dazugehörige Auftrag wurde aus dem Fertigungspool entfernt.", machineOrder.Filename);
this.Dispatcher.BeginInvoke(new Action(() => setStatus(message, Level.INFO)));
Logger.getInstance().writeLogEntry(Logger.LogLevel.INFO, message, null);
break;
}
//ÜBERPRÜFEN, OB SIE IM FERTIGUNGSSPEICHER IST
machineOrder = viewModel.MachineOrdersInProduction.FirstOrDefault(x => x.Filename == e.Name);
if (machineOrder != null)
{
message = String.Format("Die Datei {0} existiert nicht mehr. Der dazugehörige Auftrag wurde nicht entfernt, da er sich bereits in Produktion befindet", machineOrder.Filename);
this.Dispatcher.BeginInvoke(new Action(() => setStatus(message, Level.INFO)));
Logger.getInstance().writeLogEntry(Logger.LogLevel.INFO, message, null);
break;
}
//NACHRICHT AUSGEBEN
if (String.IsNullOrEmpty(message))
{
message = String.Format("Die Datei {0} existiert nicht mehr. Der dazugehörige Auftrag wurde nicht gefunden.", machineOrder.Filename);
this.Dispatcher.BeginInvoke(new Action(() => setStatus(message, Level.INFO)));
Logger.getInstance().writeLogEntry(Logger.LogLevel.INFO, message, null);
}
break;
default:
break;
}
}
catch (Exception ex)
{
this.Dispatcher.BeginInvoke(new Action(() => setStatus(ex.Message, Level.ERROR)));
Logger.getInstance().writeLogEntry(Logger.LogLevel.INFO, ex.Message, ex.StackTrace);
}
}
这里我有3个基于三个不同的可观察集合的dataGrid。如果一个文件夹添加了很多文件(或删除了很多文件),它会时不时地错过一个文件,并出现错误:
Collection was modified; enumeration operation may not execute
有什么线索可以找到丢失的文件吗?
您有明显的种族条件:
machineOrderAdded = viewModel.MachineOrdersActive.FirstOrDefault(x => x.Filename == e.Name);
if (machineOrderAdded != null)
this.Dispatcher.BeginInvoke(new Action(() => viewModel.MachineOrdersActive.Remove(machineOrderAdded)));
要修复它,请移动Invoke
:内的所有内容
Dispatcher.InvokeAsync(() =>
{
var machineOrderAdded = viewModel.MachineOrdersActive.FirstOrDefault(x => x.Filename == e.Name);
if(machineOrderAdded != null)
viewModel.MachineOrdersActive.Remove(machineOrderAdded);
});
依此类推,对于所有情况,请避免从UI线程以外的任何位置访问集合。
您也可以尝试同步对集合的访问,例如使用lock
或使用线程安全集合。这将不适用于ObservableCollection
。
根据@HansPassant的注释,您可以简单地将FileSystemWatcher
事件直接调用到UI线程中,并在那里执行所有switch/case
。
// using reinvoke pattern, you can invoke another method to avoid "double-checking"
void OnChangedActive(object source, FileSystemEventArgs e)
{
if (!Dispatcher.CheckAccess())
Dispatcher.InvokeAsync(() => OnChangedActive(sender, e)); // sorry for InvokeAsync :)
else
{
... // your code goes here without need to use invoke
}
}