FileSystemWatcher - 从ObservableCollection,C#添加和删除

时间:2016-01-12 13:06:21

标签: c# wpf filesystemwatcher

首先,我的代码:

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); } }

有关如何捕获丢失文件的任何线索?

1 个答案:

答案 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 workObservableCollection

根据@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
    }
}