El evento FileSystemWatcher Changed se genera dos veces

Tengo una aplicación en la que estoy buscando un archivo de texto y si hay algún cambio en el archivo, estoy usando el OnChanged eventos OnChanged para manejar el evento. Estoy usando NotifyFilters.LastWriteTime pero aún así el evento es despedido dos veces. Aquí está el código.

 public void Initialize() { FileSystemWatcher _fileWatcher = new FileSystemWatcher(); _fileWatcher.Path = "C:\\Folder"; _fileWatcher.NotifyFilter = NotifyFilters.LastWrite; _fileWatcher.Filter = "Version.txt"; _fileWatcher.Changed += new FileSystemEventHandler(OnChanged); _fileWatcher.EnableRaisingEvents = true; } private void OnChanged(object source, FileSystemEventArgs e) { ....... } 

En mi caso, el OnChanged se llama dos veces, cuando cambio el archivo de texto version.txt y lo version.txt .

Me temo que este es un error / característica bien conocida de la clase FileSystemWatcher . Esto es de la documentación de la clase:

Puede observar en ciertas situaciones que un solo evento de creación genera múltiples eventos Creado que maneja su componente. Por ejemplo, si usa un componente FileSystemWatcher para supervisar la creación de nuevos archivos en un directorio y luego probarlo con el Bloc de notas para crear un archivo, puede ver dos eventos creados generados aunque solo se haya creado un solo archivo. Esto se debe a que el Bloc de notas realiza varias acciones del sistema de archivos durante el proceso de escritura. El Bloc de notas escribe en el disco en lotes que crean el contenido del archivo y luego los atributos del archivo. Otras aplicaciones pueden funcionar de la misma manera. Como FileSystemWatcher supervisa las actividades del sistema operativo, se recogerán todos los eventos que estas aplicaciones disparen.

Ahora, este fragmento de texto trata sobre el evento Created , pero lo mismo se aplica a otros eventos de archivo también. En algunas aplicaciones es posible que pueda evitar esto utilizando la propiedad NotifyFilter , pero mi experiencia es que a veces también tiene que hacer algunos filtros de duplicado manual (hacks).

Hace un tiempo reservé una página marcada con algunos consejos de FileSystemWatcher . Quizás quieras revisarlo.

He “corregido” ese problema usando la siguiente estrategia en mi delegado:

 // fsw_ is the FileSystemWatcher instance used by my application. private void OnDirectoryChanged(...) { try { fsw_.EnableRaisingEvents = false; /* do my stuff once asynchronously */ } finally { fsw_.EnableRaisingEvents = true; } } 

Cualquier evento OnChanged duplicado de FileSystemWatcher puede detectarse y descartarse al verificar la marca de tiempo File.GetLastWriteTime en el archivo en cuestión. Al igual que:

 DateTime lastRead = DateTime.MinValue; void OnChanged(object source, FileSystemEventArgs a) { DateTime lastWriteTime = File.GetLastWriteTime(uri); if (lastWriteTime != lastRead) { doStuff(); lastRead = lastWriteTime; } // else discard the (duplicated) OnChanged event } 

Aquí está mi solución que me ayudó a detener el evento que se planteó dos veces:

 watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size; 

Aquí he establecido la propiedad NotifyFilter con solo nombre de archivo y tamaño.
watcher es mi objeto de FileSystemWatcher. Espero que esto ayude

Mi caso es que tengo una máquina virtual con un servidor Linux. Estoy desarrollando archivos en el host de Windows. Cuando cambio algo en una carpeta en el host, quiero que se carguen todos los cambios sincronizados en el servidor virtual a través de Ftp. Así es como elimino el evento de cambio duplicado cuando escribo en un archivo (que marca la carpeta que contiene el archivo que se modificará también):

 private Hashtable fileWriteTime = new Hashtable(); private void fsw_sync_Changed(object source, FileSystemEventArgs e) { string path = e.FullPath.ToString(); string currentLastWriteTime = File.GetLastWriteTime( e.FullPath ).ToString(); // if there is no path info stored yet // or stored path has different time of write then the one now is inspected if ( !fileWriteTime.ContainsKey(path) || fileWriteTime[path].ToString() != currentLastWriteTime ) { //then we do the main thing log( "A CHANGE has occured with " + path ); //lastly we update the last write time in the hashtable fileWriteTime[path] = currentLastWriteTime; } } 

Principalmente, creo una tabla hash para almacenar la información de tiempo de escritura del archivo. Entonces, si la tabla hash tiene la ruta de archivo modificada y su valor de tiempo es el mismo que el cambio actual del archivo notificado, entonces sé que es el duplicado del evento y lo ignoro.

Aquí está mi enfoque:

 // Consider having a List named _changedFiles private void OnChanged(object source, FileSystemEventArgs e) { lock (_changedFiles) { if (_changedFiles.Contains(e.FullPath)) { return; } _changedFiles.Add(e.FullPath); } // do your stuff System.Timers.Timer timer = new Timer(1000) { AutoReset = false }; timer.Elapsed += (timerElapsedSender, timerElapsedArgs) => { lock (_changedFiles) { _changedFiles.Remove(e.FullPath); } }; timer.Start(); } 

Esta es la solución que utilicé para resolver este problema en un proyecto en el que estaba enviando el archivo como archivo adjunto en un correo. Evitará fácilmente el evento dos veces disparado incluso con un intervalo de temporizador más pequeño, pero en mi caso 1000 estuvo bien, ya que estaba más contento con los pocos cambios faltantes que con inundar el buzón con> 1 mensaje por segundo. Al menos funciona bien en caso de que se cambien varios archivos al mismo tiempo.

Otra solución que he pensado sería reemplazar la lista con un diccionario de archivos de mapeo a su MD5 respectivo, por lo que no tendría que elegir un intervalo arbitrario ya que no tendría que eliminar la entrada sino actualizar su valor, y cancela tus cosas si no ha cambiado. Tiene la desventaja de tener un diccionario creciendo en la memoria a medida que se monitorean los archivos y comiendo más y más memoria, pero he leído en algún lado que la cantidad de archivos monitoreados depende del buffer interno del FSW, así que tal vez no sea tan crítico. No sé cómo el tiempo de cómputo MD5 afectaría el rendimiento de tu código tampoco, cuidado = \

Pruebe con este código:

 class WatchPlotDirectory { bool let = false; FileSystemWatcher watcher; string path = "C:/Users/jamie/OneDrive/Pictures/Screenshots"; public WatchPlotDirectory() { watcher = new FileSystemWatcher(); watcher.Path = path; watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; watcher.Filter = "*.*"; watcher.Changed += new FileSystemEventHandler(OnChanged); watcher.Renamed += new RenamedEventHandler(OnRenamed); watcher.EnableRaisingEvents = true; } void OnChanged(object sender, FileSystemEventArgs e) { if (let==false) { string mgs = string.Format("File {0} | {1}", e.FullPath, e.ChangeType); Console.WriteLine("onchange: " + mgs); let = true; } else { let = false; } } void OnRenamed(object sender, RenamedEventArgs e) { string log = string.Format("{0} | Renamed from {1}", e.FullPath, e.OldName); Console.WriteLine("onrenamed: " + log); } public void setPath(string path) { this.path = path; } } 

Sé que este es un problema antiguo, pero tenía el mismo problema y ninguna de las soluciones anteriores realmente solucionó el problema al que me enfrentaba. Creé un diccionario que mapea el nombre del archivo con LastWriteTime. Por lo tanto, si el archivo no está en el diccionario, se continuará con el proceso de verificación para ver cuándo fue la última vez que se modificó y si es diferente de lo que está en el diccionario ejecutar el código.

  Dictionary dateTimeDictionary = new Dictionary(); private void OnChanged(object source, FileSystemEventArgs e) { if (!dateTimeDictionary.ContainsKey(e.FullPath) || (dateTimeDictionary.ContainsKey(e.FullPath) && System.IO.File.GetLastWriteTime(e.FullPath) != dateTimeDictionary[e.FullPath])) { dateTimeDictionary[e.FullPath] = System.IO.File.GetLastWriteTime(e.FullPath); //your code here } } 

Aquí hay una nueva solución que puedes probar. Funciona bien para mi En el controlador de eventos para el evento modificado, elimine el controlador mediante progtwigción del mensaje de salida, si lo desea, agregue el controlador de nuevo. ejemplo:

 public void fileSystemWatcher1_Changed( object sender, System.IO.FileSystemEventArgs e ) { fileSystemWatcher1.Changed -= new System.IO.FileSystemEventHandler( fileSystemWatcher1_Changed ); MessageBox.Show( "File has been uploaded to destination", "Success!" ); fileSystemWatcher1.Changed += new System.IO.FileSystemEventHandler( fileSystemWatcher1_Changed ); } 

Un posible ‘truco’ sería estrangular los eventos usando Reactive Extensions, por ejemplo:

 var watcher = new FileSystemWatcher("./"); Observable.FromEventPattern(watcher, "Changed") .Throttle(new TimeSpan(500000)) .Subscribe(HandleChangeEvent); watcher.EnableRaisingEvents = true; 

En este caso estoy acelerando a 50 ms, en mi sistema era suficiente, pero los valores más altos deberían ser más seguros. (Y como dije, sigue siendo un ‘truco’).

La razón principal fue que la última vez que se accedió al primer evento fue la hora actual (escritura del archivo o tiempo modificado). luego el segundo evento fue el último tiempo de acceso original del archivo. Lo soluciono bajo el código.

  var lastRead = DateTime.MinValue; Watcher = new FileSystemWatcher(...) { NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite, Filter = "*.dll", IncludeSubdirectories = false, }; Watcher.Changed += (senderObject, ea) => { var now = DateTime.Now; var lastWriteTime = File.GetLastWriteTime(ea.FullPath); if (now == lastWriteTime) { return; } if (lastWriteTime != lastRead) { // do something... lastRead = lastWriteTime; } }; Watcher.EnableRaisingEvents = true; 

Pasé una cantidad significativa de tiempo usando FileSystemWatcher, y algunos de los enfoques aquí no funcionarán. Me gustó mucho el enfoque de deshabilitar eventos, pero desafortunadamente, no funciona si hay> 1 archivo que se descarta, el segundo archivo se perderá la mayoría si no todas las veces. Entonces uso el siguiente enfoque:

 private void EventCallback(object sender, FileSystemEventArgs e) { var fileName = e.FullPath; if (!File.Exists(fileName)) { // We've dealt with the file, this is just supressing further events. return; } // File exists, so move it to a working directory. File.Move(fileName, [working directory]); // Kick-off whatever processing is required. } 

Tengo una solución muy rápida y simple aquí, me funciona, y no importa si el evento se desencadenará una o dos veces o más ocasionalmente, compruébalo:

 private int fireCount = 0; private void inputFileWatcher_Changed(object sender, FileSystemEventArgs e) { fireCount++; if (fireCount == 1) { MessageBox.Show("Fired only once!!"); dowork(); } else { fireCount = 0; } } } 

Este código funcionó para mí.

  private void OnChanged(object source, FileSystemEventArgs e) { string fullFilePath = e.FullPath.ToString(); string fullURL = buildTheUrlFromStudyXML(fullFilePath); System.Diagnostics.Process.Start("iexplore", fullURL); Timer timer = new Timer(); ((FileSystemWatcher)source).Changed -= new FileSystemEventHandler(OnChanged); timer.Interval = 1000; timer.Elapsed += new ElapsedEventHandler(t_Elapsed); timer.Start(); } private void t_Elapsed(object sender, ElapsedEventArgs e) { ((Timer)sender).Stop(); theWatcher.Changed += new FileSystemEventHandler(OnChanged); } 

mayormente para mi futuro 🙂

Escribí un contenedor usando Rx:

  public class WatcherWrapper : IDisposable { private readonly FileSystemWatcher _fileWatcher; private readonly Subject _infoSubject; private Subject _eventSubject; public WatcherWrapper(string path, string nameFilter = "*.*", NotifyFilters? notifyFilters = null) { _fileWatcher = new FileSystemWatcher(path, nameFilter); if (notifyFilters != null) { _fileWatcher.NotifyFilter = notifyFilters.Value; } _infoSubject = new Subject(); _eventSubject = new Subject(); Observable.FromEventPattern(_fileWatcher, "Changed").Select(e => e.EventArgs) .Subscribe(_infoSubject.OnNext); Observable.FromEventPattern(_fileWatcher, "Created").Select(e => e.EventArgs) .Subscribe(_infoSubject.OnNext); Observable.FromEventPattern(_fileWatcher, "Deleted").Select(e => e.EventArgs) .Subscribe(_infoSubject.OnNext); Observable.FromEventPattern(_fileWatcher, "Renamed").Select(e => e.EventArgs) .Subscribe(_infoSubject.OnNext); // this takes care of double events and still works with changing the name of the same file after a while _infoSubject.Buffer(TimeSpan.FromMilliseconds(20)) .Select(x => x.GroupBy(z => z.FullPath).Select(z => z.LastOrDefault()).Subscribe( infos => { if (infos != null) foreach (var info in infos) { { _eventSubject.OnNext(info); } } }); _fileWatcher.EnableRaisingEvents = true; } public IObservable FileEvents => _eventSubject; public void Dispose() { _fileWatcher?.Dispose(); _eventSubject.Dispose(); _infoSubject.Dispose(); } } 

Uso:

 var watcher = new WatcherWrapper(_path, "*.info"); // all more complicated and scenario specific filtering of events can be done here watcher.FileEvents.Where(x => x.ChangeType != WatcherChangeTypes.Deleted).Subscribe(x => //do stuff) 

He cambiado la manera en que controlo los archivos en los directorios. En lugar de usar el FileSystemWatcher, sondeo las ubicaciones en otro hilo y luego miro el LastWriteTime del archivo.

 DateTime lastWriteTime = File.GetLastWriteTime(someFilePath); 

Al usar esta información y mantener un índice de una ruta de archivo y su última hora de grabación, puedo determinar los archivos que han cambiado o que se han creado en una ubicación en particular. Esto me quita las rarezas de FileSystemWatcher. El principal inconveniente es que necesita una estructura de datos para almacenar LastWriteTime y la referencia al archivo, pero es confiable y fácil de implementar.

Podría tratar de abrirlo para escribir, y si tiene éxito, entonces podría asumir que la otra aplicación está hecha con el archivo.

 private void OnChanged(object source, FileSystemEventArgs e) { try { using (var fs = File.OpenWrite(e.FullPath)) { } //do your stuff } catch (Exception) { //no write access, other app not done } } 

Solo abrirlo para escribir parece no generar el evento modificado. Por lo tanto, debería ser seguro.

Perdón por la excavación de la tumba, pero he estado luchando con este problema por un tiempo y finalmente se me ocurrió una forma de manejar estos múltiples eventos despedidos. Me gustaría agradecer a todos en este hilo, ya que lo he usado en muchas referencias cuando lucho contra este problema.

Aquí está mi código completo. Utiliza un diccionario para rastrear la fecha y la hora de la última escritura del archivo. Compara ese valor, y si es el mismo, suprime los eventos. A continuación, establece el valor después de iniciar el nuevo hilo.

 using System.Threading; // used for backgroundworker using System.Diagnostics; // used for file information private static IDictionary fileModifiedTable = new Dictionary(); // used to keep track of our changed events private void fswFileWatch_Changed( object sender, FileSystemEventArgs e ) { try { //check if we already have this value in our dictionary. if ( fileModifiedTable.TryGetValue( e.FullPath, out sEmpty ) ) { //compare timestamps if ( fileModifiedTable[ e.FullPath ] != File.GetLastWriteTime( e.FullPath ).ToString() ) { //lock the table lock ( fileModifiedTable ) { //make sure our file is still valid if ( File.Exists( e.FullPath ) ) { // create a new background worker to do our task while the main thread stays awake. Also give it do work and work completed handlers BackgroundWorker newThreadWork = new BackgroundWorker(); newThreadWork.DoWork += new DoWorkEventHandler( bgwNewThread_DoWork ); newThreadWork.RunWorkerCompleted += new RunWorkerCompletedEventHandler( bgwNewThread_RunWorkerCompleted ); // capture the path string eventFilePath = e.FullPath; List arguments = new List(); // add arguments to pass to the background worker arguments.Add( eventFilePath ); arguments.Add( newEvent.File_Modified ); // start the new thread with the arguments newThreadWork.RunWorkerAsync( arguments ); fileModifiedTable[ e.FullPath ] = File.GetLastWriteTime( e.FullPath ).ToString(); //update the modified table with the new timestamp of the file. FILE_MODIFIED_FLAG.WaitOne(); // wait for the modified thread to complete before firing the next thread in the event multiple threads are being worked on. } } } } } catch ( IOException IOExcept ) { //catch any errors postError( IOExcept, "fswFileWatch_Changed" ); } } 

He creado un repository de Git con una clase que amplía FileSystemWatcher para activar los eventos solo cuando se realiza la copia. Descarta todos los eventos modificados excepto el último y solo lo sube cuando el archivo está disponible para lectura.

Descargue FileSystemSafeWatcher y agréguelo a su proyecto.

A continuación, utilícelo como un FileSystemWatcher normal y supervise cuándo se desencadenan los eventos.

 var fsw = new FileSystemSafeWatcher(file); fsw.EnableRaisingEvents = true; // Add event handlers here fsw.Created += fsw_Created; 

Pude hacer esto agregando una función que busca duplicados en una matriz de búfer.

A continuación, realice la acción después de que la matriz no haya sido modificada durante X veces usando un temporizador: – Restablezca el temporizador cada vez que se escriba algo en el búfer – Realice una acción al marcar

Esto también capta otro tipo de duplicación. Si modifica un archivo dentro de una carpeta, la carpeta también arroja un evento Change.

 Function is_duplicate(str1 As String) As Boolean If lb_actions_list.Items.Count = 0 Then Return False Else Dim compStr As String = lb_actions_list.Items(lb_actions_list.Items.Count - 1).ToString compStr = compStr.Substring(compStr.IndexOf("-") + 1).Trim If compStr <> str1 AndAlso compStr.parentDir <> str1 & "\" Then Return False Else Return True End If End If End Function Public Module extentions  Public Function parentDir(ByVal aString As String) As String Return aString.Substring(0, CInt(InStrRev(aString, "\", aString.Length - 1))) End Function End Module 
 FileReadTime = DateTime.Now; private void File_Changed(object sender, FileSystemEventArgs e) { var lastWriteTime = File.GetLastWriteTime(e.FullPath); if (lastWriteTime.Subtract(FileReadTime).Ticks > 0) { // code FileReadTime = DateTime.Now; } } 

Esta solución funcionó para mí en la aplicación de producción:

Ambiente:

VB.Net Framework 4.5.2

Establecer propiedades de objeto manualmente: NotifyFilter = Tamaño

Luego usa este código:

 Public Class main Dim CalledOnce = False Private Sub FileSystemWatcher1_Changed(sender As Object, e As IO.FileSystemEventArgs) Handles FileSystemWatcher1.Changed If (CalledOnce = False) Then CalledOnce = True If (e.ChangeType = 4) Then ' Do task... CalledOnce = False End If End Sub End Sub 

¡Prueba esto!

 string temp=""; public void Initialize() { FileSystemWatcher _fileWatcher = new FileSystemWatcher(); _fileWatcher.Path = "C:\\Folder"; _fileWatcher.NotifyFilter = NotifyFilters.LastWrite; _fileWatcher.Filter = "Version.txt"; _fileWatcher.Changed += new FileSystemEventHandler(OnChanged); _fileWatcher.EnableRaisingEvents = true; } private void OnChanged(object source, FileSystemEventArgs e) { ....... if(temp=="") { //do thing you want. temp = e.name //name of text file. }else if(temp !="" && temp != e.name) { //do thing you want. temp = e.name //name of text file. }else { //second fire ignored. } } 

Tuve que combinar varias ideas de las publicaciones anteriores y agregar control de locking de archivos para que funcione para mí:

 FileSystemWatcher fileSystemWatcher; private void DirectoryWatcher_Start() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher { Path = @"c:\mypath", NotifyFilter = NotifyFilters.LastWrite, Filter = "*.*", EnableRaisingEvents = true }; fileSystemWatcher.Changed += new FileSystemEventHandler(DirectoryWatcher_OnChanged); } private static void WaitUntilFileIsUnlocked(String fullPath, Action callback, FileAccess fileAccess = FileAccess.Read, Int32 timeoutMS = 10000) { Int32 waitMS = 250; Int32 currentMS = 0; FileInfo file = new FileInfo(fullPath); FileStream stream = null; do { try { stream = file.Open(FileMode.Open, fileAccess, FileShare.None); stream.Close(); callback(fullPath); return; } catch (IOException) { } finally { if (stream != null) stream.Dispose(); } Thread.Sleep(waitMS); currentMS += waitMS; } while (currentMS < timeoutMS); } private static Dictionary DirectoryWatcher_fileLastWriteTimeCache = new Dictionary(); private void DirectoryWatcher_OnChanged(Object source, FileSystemEventArgs ev) { try { lock (DirectoryWatcher_fileLastWriteTimeCache) { DateTime lastWriteTime = File.GetLastWriteTime(ev.FullPath); if (DirectoryWatcher_fileLastWriteTimeCache.ContainsKey(ev.FullPath)) { if (DirectoryWatcher_fileLastWriteTimeCache[ev.FullPath].AddMilliseconds(500) >= lastWriteTime) return; // file was already handled } DirectoryWatcher_fileLastWriteTimeCache[ev.FullPath] = lastWriteTime; } Task.Run(() => WaitUntilFileIsUnlocked(ev.FullPath, fullPath => { // do the job with fullPath... })); } catch (Exception e) { // handle exception } } 

Event if not asked, it is a shame there are no ready solution samples for F#. To fix this here is my recipe, just because I can and F# is a wonderful .NET language.

Duplicated events are filtered out using FSharp.Control.Reactive package, which is just a F# wrapper for reactive extensions. All that can be targeted to full framework or netstandard2.0 :

 let createWatcher path filter () = new FileSystemWatcher( Path = path, Filter = filter, EnableRaisingEvents = true, SynchronizingObject = null // not needed for console applications ) let createSources (fsWatcher: FileSystemWatcher) = // use here needed events only. // convert `Error` and `Renamed` events to be merded [| fsWatcher.Changed :> IObservable<_> fsWatcher.Deleted :> IObservable<_> fsWatcher.Created :> IObservable<_> //fsWatcher.Renamed |> Observable.map renamedToNeeded //fsWatcher.Error |> Observable.map errorToNeeded |] |> Observable.mergeArray let handle (e: FileSystemEventArgs) = printfn "handle %A event '%s' '%s' " e.ChangeType e.Name e.FullPath let watch path filter throttleTime = // disposes watcher if observer subscription is disposed Observable.using (createWatcher path filter) createSources // filter out multiple equal events |> Observable.distinctUntilChanged // filter out multiple Changed |> Observable.throttle throttleTime |> Observable.subscribe handle [] let main _args = let path = @"C:\Temp\WatchDir" let filter = "*.zip" let throttleTime = TimeSpan.FromSeconds 10. use _subscription = watch path filter throttleTime System.Console.ReadKey() |> ignore 0 // return an integer exit code 

I approached the double create issue like this, which ignores the first event:

 Private WithEvents fsw As New System.IO.FileSystemWatcher Private complete As New List(Of String) Private Sub fsw_Created(ByVal sender As Object, _ ByVal e As System.IO.FileSystemEventArgs) Handles fsw.Created If Not complete.Contains(e.FullPath) Then complete.Add(e.FullPath) Else complete.Remove(e.FullPath) Dim th As New Threading.Thread(AddressOf hprocess) th.Start(e) End If End Sub 

Alot of these answers are shocking, really. Heres some code from my XanderUI Control library that fixes this.

 private void OnChanged(object sender, FilesystemEventArgs e) { if (FSWatcher.IncludeSubdirectories == true) { if (File.Exists(e.FullPath)) { DO YOUR FILE CHANGE STUFF HERE... } } else DO YOUR DIRECTORY CHANGE STUFF HERE... } 

if you register to the OnChanged event, then by deleting the monitored file before changing it might work, as long as you only need to monitor the OnChange event..

Make it simple define one global variable var1 = true .

 Private Sub FileWatchman_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles FileWatchman.Changed If var1 = true your logic goes here var1 = false Else var1 = true End If End Sub 

Well, here is my solution how to raise an event only once:

 FileSystemWatcheк watcher = new FileSystemWatcher(); //'path' - path to the file that has been modified. watcher.Changed += (s, e) => FileChanged(path); 

here is implementation of FileChanged

 //count is our counter to triger when we can raise and when not. private int count = 0; private void FileChanged(string path) { if (count % 2 == 0) { //code here } count ++; }