none
Monitor when two files are loaded on the same instance using FileSystemWatcher RRS feed

  • Question

  • The following method is called when a file is open:

    private void Load(string fileName) { // Only watch seq files. this.watcher.Path = Path.GetDirectoryName(fileName); // Watch for changes in LastAccess and LastWrite times, and // the renaming of files or directories. this.watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; this.watcher.Filter = Path.GetFileName(fileName); // Begin watching. this.watcher.EnableRaisingEvents = true; // Add event handlers. this.watcher.Changed += this.OnChanged; // code for opening file asynchronously } private void OnChanged(object source, FileSystemEventArgs e) { App.Current.Dispatcher.Invoke(() => { MessageBoxResult result = CustomMessageBox.ShowYesNoCancel( "The file has been modified by another instance.", "More instances are opened!", "Overwrite", "Reload", "Save as", MessageBoxImage.Exclamation); if (result == MessageBoxResult.Yes) { // Overwrite } if (result == MessageBoxResult.Cancel) { // Save as; }

     if (result == MessageBoxResult.No)
                {
                    // reload file and lose changes
    
                }
            });
            var t = new System.Timers.Timer();
            ((FileSystemWatcher)source).Changed -= new FileSystemEventHandler(this.OnChanged);
            t.Interval = 1000;
            t.Elapsed += new ElapsedEventHandler(Elapsed);
            t.Start();
        }
    
        private static void Elapsed(object sender, ElapsedEventArgs e)
        {
            ((System.Timers.Timer)sender).Stop();
        }          

    private static void Elapsed(object sender, ElapsedEventArgs e) { ((System.Timers.Timer)sender).Stop(); }

    1.I'm very disappointed that I get my MessageBox only when the file from one instances is saved but I like to have my message when I load the file on the second instance. Main problem is that the user opened the application twice and now is possible to modified in both instances. For saving I'm using this method:

    public override void WriteStartObject(XmlDictionaryWriter writer, object graph);

    Is this NotifyFilters.LastAccess working? For me just NotifyFilters.LastWrite seems to work...

    1. The other small problem is that after I save the changes to my file on one instances the messageBox appear twice(as if I do not have enough problems).


    • Edited by Quitty15 Monday, February 25, 2019 12:54 PM
    Monday, February 25, 2019 12:52 PM

All replies

  • These are bouncing off the corresponding file system attributes and are therefore tied to whether the file system uses them. Last access time updates were disabled around the Vista timeframe so you won't get notified for them anymore unless you explicitly turned on this feature in NTFS. But this would have a detrimental impact on your file system performance.

    FSW is only for modifications. To get notified when a file is "opened" by another process you have to use a file system filter. Of course these cannot be written in managed code.

    I think I already addressed #2 in your previous post. FSW raises an event for each change it sees. That may or may not correlate to the # of saves an app did. A single WriteFileEx call can trigger multiple change notifications. When using the FSW you have to handle multiple events for the same file. Furthermore you have to handle the fact that the remote process may still have the file open for write access which means you cannot even access it. Most people push the notification to a background worker thread that processes the file change notification at a future point, along with retry and duplicate change detection. It isn't trivial. I've blogged about it years ago. BonnieB blogged about it recently as well IIRC.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, February 25, 2019 3:00 PM
    Moderator
  • Hello,

    Thank you for your reply. After I read a lot of topics I realized that this difficult to use watcher on opened operation, I modified a little bit the requirement.

    But now I’m dealing with a different issue.  I expect to trigger the watcher only when I save a file that is opened twice in in the same application (our application). My issue is that this watcher is trigger even if a have just one instance of my application opened.  How can I make the difference between saving (modifying) one file from one application opened or saving the same file from the same application?

    I try using a collection, I try making this.watcher.EnableRaisingEvents = true or  this.watcher.EnableRaisingEvents = false in different part of the program but nothing seems to solve my issue.

    Here is my snippet code:

    private void Load(string fileName)

            {

                // Only watch seq files.

                this.watcher.Path = Path.GetDirectoryName(fileName);

                // Watch for changes in LastWrite times

                this.watcher.NotifyFilter = NotifyFilters.LastWrite;

                this.watcher.Filter = "*.zzz";

                // Add event handlers.

                this.watcher.Changed += this.OnChanged;

                // Begin watching.

                this.watcher.EnableRaisingEvents = true;

    //opened file

    }

    // Define the event handlers.

            private void OnChanged(object source, FileSystemEventArgs e)

            {

                App.Current.Dispatcher.Invoke(() =>

                {

                    MessageBoxResult result = CustomMessageBox.ShowYesNoCancel(

                        "The file has been modified by another instance.",

                        "More app instances are opened!",

                        "Overwrite",

                        "Reload",

                        "Save as",

                        MessageBoxImage.Exclamation);

                    if (result == MessageBoxResult.Yes)

                    {

                        // Overwrite

                        this.SaveSequence();

                    }

                    if (result == MessageBoxResult.Cancel)

                    {

                        // Save as;

                                        }

                    if (result == MessageBoxResult.No)

                    {

                        // reload file and lose changes

                       

                    }

                });

                // end watching.

                this.watcher.EnableRaisingEvents = false;

            }

    internal bool Save()

            {

    /// some code

     this.File.Write(this.FilePath); //here is the moment when my watcher is trigger

    /// rest of the code

                        }

    Friday, April 19, 2019 6:39 AM
  • FSW doesn't care (or provide any info about) who made the change so you're not going to be able to determine what you're asking for via FSW. That isn't what it is there for and I'm not even sure why you'd care. "Opening/modifying/closing" a file tends to be so fast that who did it wouldn't matter.

    The only way to know that your app has "opened" a file is to track each of your calls to open a file somewhere. You'd then have to compare that to the file being changed in FSW. But note there are no guarantees that your app is changing the file irrelevant of whether you have added a file to this "open" list or not. Imagine you opened a file 10 hours ago, made a change and saved it. Now FSW fires an event for that same file. Since your app has already closed the file then it probably isn't your app doing it. 

    I'm not really sure why you're trying to accomplish what you're asking for. Can you more precisely explain why it is important that you know whether a file sent as part of a FSW event is because of your app or another app?


    Michael Taylor http://www.michaeltaylorp3.net

    Friday, April 19, 2019 1:49 PM
    Moderator