2016-01-12 4 views
1

прежде всего, мой код:FileSystemWatcher - добавлять и удалять из 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 DataGrid на основе трех различных наблюдаемых коллекций. если добавить много файлов (или удалить много файлов) из папки, он пропускает файл, время от времени с ошибкой:

Collection was modified; enumeration operation may not execute

Любые подсказки, как поймать недостающие файлы?

+1

Это сообщение означает, что вы изменяете свою коллекцию итераторов во время итерации. Возможно, вам нужно создать копию своей коллекции и скопировать добавленные файлы в новую коллекцию (тот же процесс с удаленными файлами). – Jose

+0

В каком случае возникает исключение строки? – Sinatr

+0

stacktrace говорит в этой строке: machineOrderAdded = viewModel.MachineOrdersActive.FirstOrDefault (x => x.Filename == e.Name); –

ответ

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

И так далее для всех случаев, избежать доступа к коллекции из любой другой, но поток пользовательского интерфейса ,

Вы также можете попробовать синхронизировать доступ к коллекции, e.q. используя lock или используя поточно-безопасную коллекцию. Это will not work с ObservableCollection.

Согласно комментарию @HansPassant, вы можете просто вызвать FileSystemWatcher событий непосредственно в поток пользовательского интерфейса и сделать все 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 
    } 
} 
+0

Я действительно не понимаю. Dispatcher.InvokeAsync (() не существует как-то .. и все, что у меня есть, является наблюдаемым цветом –

+2

Это [существует в net4.5 +] (https://msdn.microsoft.com/en-us/library/system.windows .threading.dispatcher.invokeasync (v = vs.110) .aspx), тогда используйте «BeginInvoke». – Sinatr

 Смежные вопросы

  • Нет связанных вопросов^_^