[SOLVED] [C#] File System Watcher - Detecting Changes To Opened Files Upon Exit

x BlueRobot

Administrator
Staff member
Joined
May 7, 2013
Posts
10,400
I've created a very simple test program, to play around and attempt to try new things to add to my main project at the moment (FileComparsion), at the moment I'm able to detect any changes made to the text box upon exit. However, the message box also appears when I've opened a file and haven't made any changes to that file.

I've read that the File Watcher component may be able to help, but how do I get the component to raise an event about the changes upon exiting the program?

Here's the code:

Code:
private void Form1_FormClosing(object sender, CancelEventArgs e)
        {
            richTextBox1.Tag = richTextBox1.Text;

            if (richTextBox1.Text != richTextBox1.Tag)
{

                if (MessageBox.Show("Do you wish to save any changes?", "Test", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                {
                    e.Cancel = true;

[...] Standard Save Dialog Box

File Watcher Component Code (literally the same as code on MSDN):

Code:
System.IO.FileSystemWatcher myWatcher = new System.IO.FileSystemWatcher();

                myWatcher.Path = "C:\\";
                myWatcher.Filter = "*.*";
                myWatcher.IncludeSubdirectories = true;
                myWatcher.EnableRaisingEvents = true;
                myWatcher.NotifyFilter = System.IO.NotifyFilters.Size;
 
You are checking these files how? Take a look at some of the events for the FileSystemWatcher: FileSystemWatcher Events (System.IO)

Although without opening my IDE, I recall that there was a Modified event as well for textbox based controls for Windows Forms. Perhaps if any pending changes are unsaved you could keep track using a boolean based on this event being fired? I don't get what you're trying to do though.

Check the file for any changes or the richtextbox? You could achieve any of the assumptions I could make about what you're doing, in many many ways, I just don't understand which 'set' of solutions to give to you yet.

I would not implicitly compare the Tag (a System.Object) to a String though, even though this is valid because everything either directly or indirectly inherits from System.Object, but I would also not do this because this means you have to store 2 entire full text strings in memory. Why not compute a hash (MD5/SHA1?) and use that to see if the overall text is modified? :huh:

Keep up the good work though, at least I can post in this section more often now, being that you're taking a good effort to learn C#. :thumbsup2: I don't mind helping out.
 
Last edited:
Notepad - Added Text To Text Box.JPG

The first screenshot, is when I've added text to a empty text box, notice the message box? I'm able to do that with my current program.

Notepad - Added Changes To Rich Text Box.JPG

The second picture, is when I've added text to a opened text file, when I exit the program, it asks if I would like to save the changes upon exiting. This is what I would to achieve with my program. However, if I haven't made any changes to that text file, then it doesn't give me any message box asking if I would like to save any changes.

With File System Watcher, I was wanting to use the Changed Event, to detect any changes to the file size, since from reading this might be able to help. However, you can't add a event to an event? As in for it to work, wouldn't the Changed Event have to raised upon exiting the program?
 
Okay, so then the FileSystemWatcher is definitely not what you want at all. It can't see anything past the file which is on your filesystem, so for it to see any change, the file would have already had to have been saved, and in which case it wouldn't make sense to show whether modifications are pending a save, because they are already shown within the file. What you want to do is check to see whether the text in the control, is different from what is in the file.

You can do this with the Control's Modified event. In the event method, you can change a public boolean property that keeps track of whether modifications to the text, are pending a save, to update the file on disk.

Some psuedocode of what I'm talking about:
Code:
#Property/Boolean -> keeps track of whether modifications are pending to be saved to disk.

Modified event method:
{
    - If modified, change boolean for pending save.
}

Save method:
{
    - Update the boolean to false after saving data to file, because changes are saved.
}

And after loading a file into the control, I haven't tested, but the Modified property may fire, so you could have some sort of mechanism that prohibits the boolean from changing to True (for modifications that are pending a save to disk), when you load a new file into the Text.
 
Last edited:
Code:
public void button1_Click(object sender, EventArgs e)
        {
            string Opened_File = "";

            openFD.InitialDirectory = "Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)";
            openFD.Title = "Open a File";
            openFD.FileName = "";
            openFD.Filter = "Text Files (*.txt)|*.txt|Batch Files (*.bat)|*.bat|HTML Files (*.html)|*.html";

            if (openFD.ShowDialog() != DialogResult.Cancel)
            {

                Opened_File = openFD.FileName; 
                richTextBox1.LoadFile(Opened_File, RichTextBoxStreamType.PlainText);
            }
        }

        public void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            string originalText = Opened_File;

            if (originalText != richTextBox1.Text)
            {
                richTextBox1.Modified = true;

            }
        }

Isn't the opened file stored in the variable called Opened_File? It gives the error Opened_File does not exist in this current context.
 
Is this the Event? TextBoxBase.ModifiedChanged Event (System.Windows.Forms)

TextBoxBase.Modified Property (System.Windows.Forms)

How would I go about storing the contents of a file into a variable, and then comparing it?

Yes, that's the property and the event I'm talking about. Why do you want to store it into a variable to compare anything?

1) The string is already in the Text property of that TextBox
2) If the modified property has changed, why do you need to compare to see if the text has changed (again)?

Code:
public void button1_Click(object sender, EventArgs e)
        {
            string Opened_File = "";

            openFD.InitialDirectory = "Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)";
            openFD.Title = "Open a File";
            openFD.FileName = "";
            openFD.Filter = "Text Files (*.txt)|*.txt|Batch Files (*.bat)|*.bat|HTML Files (*.html)|*.html";

            if (openFD.ShowDialog() != DialogResult.Cancel)
            {

                Opened_File = openFD.FileName; 
                richTextBox1.LoadFile(Opened_File, RichTextBoxStreamType.PlainText);
            }
        }

        public void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            string originalText = Opened_File;

            if (originalText != richTextBox1.Text)
            {
                richTextBox1.Modified = true;

            }
        }

Isn't the opened file stored in the variable called Opened_File? It gives the error Opened_File does not exist in this current context.

It doesn't, that error is right, learn about scope. You declared Opened_File within the button1_Click void {}... And therefore it only exists within that scope. Anything outside of that scope will not be able to see that variable because it is destroyed by the time button1_Click ends. richTextBox1_TextChanged is an entirely new scope. Scope in C#, you can think of as layers, defined by { and }. Try this:
Code:
{
    int x = 10;
    x = 20;
}
x = 30; // will not work.

x is in the scope of the first { and the last }. Anything outside of that is not in it's scope.
 
Code:
public void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            if (richTextBox1.Modified == true)
            
            {
                
                string Saved_File = " ";

                    saveFD.InitialDirectory = "Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)";
                    saveFD.Title = "Save a File";
                    saveFD.FileName = "";
                    saveFD.Filter = "Text Files (*.txt)|*.txt|Batch Files (*.bat)|*.bat|HTML Files (*.html)|*.html";

                    if (saveFD.ShowDialog() != DialogResult.Cancel)
                    {

                        Saved_File = saveFD.FileName;
                        richTextBox1.SaveFile(Saved_File, RichTextBoxStreamType.PlainText);

                    }
                
                    richTextBox1.Modified = false;

                    }


                    }

At the moment, as soon as, the Modified property becomes True then the Save dialog box is launched. The Modifed property becomes False after the changes have been saved.

How do I stop the Event from firing until I've decided to exit the application?
 
Code:
public void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            if (richTextBox1.Modified == true)
            
            {
                
                string Saved_File = " ";

                    saveFD.InitialDirectory = "Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)";
                    saveFD.Title = "Save a File";
                    saveFD.FileName = "";
                    saveFD.Filter = "Text Files (*.txt)|*.txt|Batch Files (*.bat)|*.bat|HTML Files (*.html)|*.html";

                    if (saveFD.ShowDialog() != DialogResult.Cancel)
                    {

                        Saved_File = saveFD.FileName;
                        richTextBox1.SaveFile(Saved_File, RichTextBoxStreamType.PlainText);

                    }
                
                    richTextBox1.Modified = false;

                    }


                    }

At the moment, as soon as, the Modified property becomes True then the Save dialog box is launched. The Modifed property becomes False after the changes have been saved.

How do I stop the Event from firing until I've decided to exit the application?

Simple, only use the FormClosing event to decide whether the save dialog box shows. If it shows or not, should be decided based on whether the Modified property is true or false. You shouldn't even need to manage the ModifiedChanged event, because it will fire regardless of whether or not you have a method that handles that event; the Modified property will still be changed based on whether the control's text is modified.

You have the savefiledialog showing based on a condition inside the richTextBox1_TextChanged method. You don't want to use the TextChanged event for this, you want the main form's FormClosing event here... :)

If this was a multi-tabbed notepad like Notepad++ for instance, then closing the form or a tab, you would want to check for modifications, but since this is a simple program, you shouldn't need to worry about that.

Cheers
Ace
 
Last edited:
So, have like an if statement within the FormClosing Event for the Modified property? :)

Thanks for your help so far, sorry if I'm sometimes too 'slow' getting the code right, debugging BSODs is more my kind of thing but programming is the thing which got me interested in the more technical and advanced concepts of computers :cool3:

I'll write and test some code in the morning, and then post it here :)
 
So, have like an if statement within the FormClosing Event for the Modified property? :)

Thanks for your help so far, sorry if I'm sometimes too 'slow' getting the code right, debugging BSODs is more my kind of thing but programming is the thing which got me interested in the more technical and advanced concepts of computers :cool3:

I'll write and test some code in the morning, and then post it here :)

Good luck :) I'm sure you'll get it this time if you take a few minutes to think about how it should work.
 
Code:
private void Form1_FormClosing(object sender, CancelEventArgs e)
        {
            if (richTextBox1.Modified == true)
                        
            {
                if (MessageBox.Show("Do you wish to save any changes? All unsaved changes will be lost.", "Test", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                

                            string Saved_File = "";

                            saveFD.InitialDirectory = "Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)";
                            saveFD.Title = "Save a File";
                            saveFD.FileName = "";
                            saveFD.Filter = "Text Files (*.txt)|*.txt|Batch Files (*.bat)|*.bat|HTML Files (*.html)|*.html";

                            if (saveFD.ShowDialog() != DialogResult.Cancel)
                            {

                                Saved_File = saveFD.FileName;
                                richTextBox1.SaveFile(Saved_File, RichTextBoxStreamType.PlainText);

                            }


                            [COLOR=#ff0000]richTextBox1.Modified = false;[/COLOR] <-- This line is rather pointless now? The application closes if the selects to save the file or not.
                }

                        }

Okay, so I've removed the Tag property and replaced it with the Modified property, which should make the code more efficient because I'm not creating one big string variable. I need to change my main project too now.

Code:
richTextBox1.Tag = richTextBox1.Text;

When I exit the application, but haven't made any changes to a opened file, the message box is still prompted for saving any changes to the file. I could live with it like this, but it would be nice to know how to monitor changes to a opened file and not the rich textbox like Notepad does.
 
Code:
private void Form1_FormClosing(object sender, CancelEventArgs e)
        {
            if (richTextBox1.Modified == true)
                        
            {
                if (MessageBox.Show("Do you wish to save any changes? All unsaved changes will be lost.", "Test", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                

                            string Saved_File = "";

                            saveFD.InitialDirectory = "Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)";
                            saveFD.Title = "Save a File";
                            saveFD.FileName = "";
                            saveFD.Filter = "Text Files (*.txt)|*.txt|Batch Files (*.bat)|*.bat|HTML Files (*.html)|*.html";

                            if (saveFD.ShowDialog() != DialogResult.Cancel)
                            {

                                Saved_File = saveFD.FileName;
                                richTextBox1.SaveFile(Saved_File, RichTextBoxStreamType.PlainText);

                            }


                            [COLOR=#ff0000]richTextBox1.Modified = false;[/COLOR] <-- This line is rather pointless now? The application closes if the selects to save the file or not.
                }

                        }

Okay, so I've removed the Tag property and replaced it with the Modified property, which should make the code more efficient because I'm not creating one big string variable. I need to change my main project too now.

Code:
richTextBox1.Tag = richTextBox1.Text;

When I exit the application, but haven't made any changes to a opened file, the message box is still prompted for saving any changes to the file. I could live with it like this, but it would be nice to know how to monitor changes to a opened file and not the rich textbox like Notepad does.

But why? Think about that for a second. If you're monitoring an opened file for changes, if the contents of that file on disk change, that would definitely mean that the file has been saved already with new data. If this occurs, what sense would there be to let the user know that they need to save? You wouldn't be monitoring that file at all, you would be monitoring the text within that editor to see whether that text deviates from what is in the saved file on disk. This is why you want to monitor the editor, not the file...

It might just be your wording here, but it's slightly inaccurate the way you're describing it to me lol.

I think what is happening though, based on what you're saying is that opening a file to the editor fires the ModifiedChanged property, which changes that Modified property in turn. This is because the ModifiedChanged event is configured to monitor textual changes to that control. Loading a new file changes that text from "" to whatever is in the text file. To get around this I would do something like this in your LoadFile() method (or whatever you have for a method that handles opening files to the editor):

Pseudocode:
Code:
LoadFile()
{
    // load file...
    // (now we know our file is loaded) so ->
    // Modified = false;
}

This way for loading files, that modified property will always 'start' with a false value on that property, and set to true, only when data is changed AFTER the file is loaded.

:beerchug2:
 

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top