FileSystemWatcher - 从 ObservableCollection 添加和删除,C#
FileSystemWatcher - add and delete from ObservableCollection, C#
首先,我的代码:
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 个基于三个不同可观察集合的数据网格。
如果文件夹中添加了很多文件(或删除了很多文件),它会不时丢失一个文件并出现错误:
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 线程以外的任何其他地方访问集合。
您也可以尝试同步访问集合,e.q。使用 lock
或使用 thread-safe 集合。这个 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
}
}
首先,我的代码:
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 个基于三个不同可观察集合的数据网格。 如果文件夹中添加了很多文件(或删除了很多文件),它会不时丢失一个文件并出现错误:
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 线程以外的任何其他地方访问集合。
您也可以尝试同步访问集合,e.q。使用 lock
或使用 thread-safe 集合。这个 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
}
}