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

有什么线索可以找到丢失的文件吗?

FileSystemWatcher-添加和删除ObservableCollection,C#

您有明显的种族条件:

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