首先,我的代码:
View exactView = findExactChild(childView, e.getX(), e.getY())
这里我有3个基于三个不同可观察集合的dataGrid。 如果添加了很多文件(或删除了很多文件)的文件夹,它会不时错过一个文件并出现错误:
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); } }
有关如何捕获丢失文件的任何线索?
答案 0 :(得分:3)
你有明显的竞争条件:
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线程以外的任何地方访问集合。
您还可以尝试同步对集合的访问,e.q。使用lock
或使用线程安全集合。这个will not work与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
}
}