why is this C# code producing output twice - c#

Hi I am fairly new to C# and am testing a simple openFileDialog program. The code I currently wrote seems to be doing its job, however, the output is produced twice. Any help would be appreciated.
My code:
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
}
private void OnChanged(object source, FileSystemEventArgs e)
{
MessageBox.Show("copying done");
StreamReader inStream = new StreamReader(destFile);
string line;
string[] lineSplit;
bool errorFound = false;
while ((line = inStream.ReadLine()) != null)
{
lineSplit = line.Split(' ');
for (int i = 0; i < lineSplit.Length; i++)
{
if (lineSplit[i] == textBox2.Text)
{
errorFound = true;
MessageBox.Show("Error found in " + e.Name);
MessageBox.Show("Exiting");
break;
}
}
}
inStream.Close();
}
The output:
Copying Done
File: ..Changed
Copying Done
File: ..Changed
Just wondering why does it print twice?

Because it invokes OnChanged both on watcher.Created and watcher.Changed

You've attached to the same handler multiple times:
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
So if the Changed and Created events run, for example, you'll get the same output twice.
What you probably want to do is create separate methods for each event. I don't know what watcher is, but here's a general idea:
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnCreated);
watcher.Deleted += new FileSystemEventHandler(OnDeleted);
private void OnCreated(object source, FileSystemEventArgs e)
{
// do something when the watcher is created
}
private void OnDeleted(object source, FileSystemEventArgs e)
{
// do something when the watcher is deleted
}

What you need to bear in mind, is that a single IO action can trigger multiple different FileSystemWatcher events.
Common file system operations might raise more than one event. For example, when a file is moved from one directory to another, several OnChanged and some OnCreated and OnDeleted events might be raised.
MSDN
Most likely, what is happening here is that a File Creation is triggering both a Create event, and a Change event (I believe windows tends to create an initial file (triggering create) then writes to it (triggering a change)). However that depends on exactly the actions you are performing.

This is how I fixed it, don't know if it was the best way, but it works!
private static void OnChanged(object source, FileSystemEventArgs e)
{
//set EnableRaisingEvents = false at the start of the method.
FileSystemWatcher t = source as FileSystemWatcher;
t.EnableRaisingEvents = false;
//do stuff that you want in the method, in my case checking for words.
....
....
//Set EnableRaisintEvents true again
t.EnableRaisingEvents = true;
}
This little fix makes sure the event only gets raised once per change, instead of twice.

Related

Update ComboBox list in Realtime [duplicate]

Is there some mechanism by which I can be notified (in C#) when a file is modified on the disc?
You can use the FileSystemWatcher class.
public void CreateFileWatcher(string path)
{
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = path;
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
// Only watch text files.
watcher.Filter = "*.txt";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// Begin watching.
watcher.EnableRaisingEvents = true;
}
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
}
private static void OnRenamed(object source, RenamedEventArgs e)
{
// Specify what is done when a file is renamed.
Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
}
That would be System.IO.FileSystemWatcher.
Use the FileSystemWatcher. You can filter for modification events only.

FileSystemWatcher Events Not Firing

My FileSystemWatcher isn't throwing any events. I've looked at these similar questions, none seem to be an answer for my problem:
*Edit: My goal is to capture when an XLS file is copied to or created in a directory.
Filesystemwatcher doesn't trigger event
FileSystemWatcher - event not firing the second time
FileSystemWatcher Changed event doesn't fire
FileSystemWatcher - only the change event once firing once?
Monitor class:
public class Monitor
{
FileSystemWatcher watcher = new FileSystemWatcher();
readonly string bookedPath = #"\\SomeServer\SomeFolder\";
public delegate void FileDroppedEvent(string FullPath);
public event FileDroppedEvent FileDropped;
public delegate void ErrorEvent(Exception ex);
public event ErrorEvent Error;
public Monitor()
{
watcher.Path = bookedPath;
watcher.Filter = "*.xls";
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Changed += new FileSystemEventHandler(watcher_Changed);
watcher.Error += new ErrorEventHandler(watcher_Error);
}
void watcher_Error(object sender, ErrorEventArgs e)
{
Error(e.GetException());
}
void watcher_Changed(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Created) return;
FileDropped(e.FullPath);
}
public void Start()
{
watcher.EnableRaisingEvents = true;
}
public void Stop()
{
watcher.EnableRaisingEvents = false;
}
}
Simple form with Listbox:
public partial class Form1 : Form
{
Monitor monitor = new Monitor();
public Form1()
{
InitializeComponent();
FormClosing += new FormClosingEventHandler(Form1_FormClosing);
Load += new EventHandler(Form1_Load);
monitor.FileDropped += new Monitor.FileDroppedEvent(monitor_FileDropped);
monitor.Error += new Monitor.ErrorEvent(monitor_Error);
}
void Form1_Load(object sender, EventArgs e)
{
monitor.Start();
}
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
monitor.Stop();
}
void monitor_Error(Exception ex)
{
listBox1.Items.Add(ex.Message);
}
void monitor_FileDropped(string FullPath)
{
listBox1.Items.Add(FullPath);
}
}
What am I doing wrong?
Try this out. Works for me for a very similar task.
watcher.NotifyFilter = NotifyFilters.FileName;
watcher.Created += new FileSystemEventHandler(handler);
watcher.Renamed += new RenamedEventHandler(handler);
This may be because the file metadata hasn't been updated yet. This may happen if you are continuously writing to the file.
Have you tried the following:
watcher.Path = directory name;
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.xls";
watcher.Changed += OnDirectoryChange;
watcher.Error += OnError;
watcher.EnableRaisingEvents = true;
// Watch only files not subdirectories.
watcher.IncludeSubdirectories = false;
Your issue is with the filters as well as your events I believe. NotifyFilters.LastAccess will only trigger when a file is opened. Try using:
NotifyFilters.LastWrite | NotifyFilters.CreationTime
This will watch for written/created files. Next, hook up to the Created delegate to handle newly created files:
watcher.Created += YourDelegateToHandleCreatedFiles
The way FileSystemWatcher works is to first use the NotifyFilters to limit the event triggers. Then, you use the actual events to do the work. By hooking into the Created event you'll only do work when a file is created.

When changed event fire in FileWatcher

I'm using FileWatcher to monitor an xml file to track of changes. I just want to fire some method when the contents of the file is changed, file is re-named or even deleted.
Subscribing to Changed event is enough for this?
Do I need to subscribe to other events as well?
In order to monitor all actions you want, you must listen to all event: create, change, delete, update.
Here's the sample:
public void init() {
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = "path/to/file";
watcher.NotifyFilter = NotifyFilters.LastAccess
| NotifyFilters.LastWrite | NotifyFilters.FileName
| NotifyFilters.DirectoryName;
// Only watch text files.
watcher.Filter = "*.txt";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// Begin watching.
watcher.EnableRaisingEvents = true;
}
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e) {
// Specify what is done when a file is changed, created, or deleted.
}
private static void OnRenamed(object source, RenamedEventArgs e) {
// Specify what is done when a file is renamed.
}

How to add controls when an event is fired in WinForm?

i like to add controls inside the form1 where a event handler for
watcher.Changed += new FileSystemEventHandler(OnChanged); is defined , is it possible to add control for example list box to the form1 but need to be added inside the event handler where it is defined
/*event added*/
private void btn_start_Click(object sender, EventArgs e)
{
string[] args = {this.txtfolder.Text};
if (args.Length != 1)
{
// Display the proper way to call the program.
Console.WriteLine("Usage: Invalid Operation");
return;
}
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = args[0];
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
// Only watch text files.
watcher.Filter = this.txtfilter.Text;//"*.txt";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
// watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
//Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
// Form1 F ;
// ListBox lst = new ListBox();
//lst.Items.Add("File: " + e.FullPath + " " + e.ChangeType.ToString());
//f.lsttracker.Items.Add("File: " + e.FullPath + " " + e.ChangeType.ToString());
// F.controls.Add(lst);
This is what your looking for. From what you commented out, you probably didn't set the location and size, thus adding the control probably wasn't working. But you should really make sure to regulate this and make sure you are only adding controls exactly when you want to and no more.
private static void OnChanged(object source, FileSystemEventArgs e)
{
ListBox toAdd = new ListBox();
toAdd.Location = new Point(20,20);
toAdd.Size = new Size(200,200);
this.Controls.Add(toAdd);
}
If you want to store the controls you added, try something like this:
private List<Control> AddedItems = new List<Controls>();
private int OffsetY = 0;
private static void OnChanged(object source, FileSystemEventArgs e)
{
ListBox toAdd = new ListBox();
if(AddedItem.Last().Point.Y == OffsetY) // just an example of reusing previously added items.
{
toAdd.Location = new Point(20, OffsetY);
toAdd.Size = new Size(200,200);
AddedItems.Add(toAdd);
this.Controls.Add(toAdd);
}
OffsetY += 200;
}
EDIT: In reply to what you mentioned in the comment below.
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
private void btn_start_Click(object sender, EventArgs e)
{
string FolderPath = this.txtfolder.Text;
string Filter = this.txtfilter.Text;
if(!Directory.Exists(FolderPath))
{
Console.WriteLine("Not a valid directory"); //checks directory is valid
return;
}
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = FolderPath;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
// Only watch filter files.
watcher.Filter = Filter;
watcher.IncludeSubdirectories = true; //monitor subdirectories?
watcher.EnableRaisingEvents = true; //allows for changed events to be fired.
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
}
//Delegate to get back to UI thread since OnChanged fires on non-UI thread.
private delegate void updateListbox(string context);
private void OnChanged(object source, FileSystemEventArgs e)
{
this.Invoke(new updateListbox(UpdateListbox), "File: " + e.Name);
this.Invoke(new updateListbox(UpdateListbox), ">>Action: " + e.ChangeType);
this.Invoke(new updateListbox(UpdateListbox), ">>Path: " + e.FullPath);
}
public void UpdateListbox(string context)
{
lsttracker.Items.Add(context);
}

Program exits when FileSystemWatcher.Changed event is raised (C#)

So, I'm trying to make a file changed notifier, and I need to make it so the text in a textbox updates whenever the contents of the file are changed. This is what I have so far:
string path = "C:/Users/Max/Dropbox/Public/IM.txt";
StringBuilder b = new StringBuilder();
private void Window_Loaded(object sender, EventArgs e)
{
TB.Text = File.ReadAllText(path);
b.Append(TB.Text);
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = path.Remove(path.Length - 6, 6);
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.txt";
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
TB.SelectionStart = TB.Text.Length;
TB.ScrollToCaret();
}
private void OnChanged(object source, FileSystemEventArgs e)
{
TB.Text = File.ReadAllText(path);
}
This seems to raise the event correctly, but as soon as it touches the code in the OnChanged event, the program exits, no errors or anything, just closes. I have tried to stop it from closing, I have even tried putting e.Cancel under the formclosing event, but nothing seems to work. Any ideas? I can provide more info if needed.
Have you tried wrapping the code in try catch
private void OnChanged(object source, FileSystemEventArgs e)
{
try
{
TB.Text = File.ReadAllText(path);
}catch(Exception e)
{
//Show exception in messagebox or log to file.
}
}
Try this in your Changed method
if (TB.InvokeRequired)
{
TB.Invoke(new MethodInvoker(delegate { TB.Text = File.ReadAllText(path); }));
}

Categories