I'm creating a windows forms app for educational purposes, it's base idea is to have a download manager which will move files from default Downloads folder to the folder with a name of files extension. I created class MyFileWatcher which basically watches Downloads folder for new files, code looks like this:
public class MyFileWatcher
{
private readonly FileSystemWatcher _fileSystemWatcher;
public MyFileWatcher()
{
_fileSystemWatcher = new FileSystemWatcher(resources.sourcePath);
_fileSystemWatcher.Created += (sender, e) => _fileWatcher_Created(sender, e);
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void _fileWatcher_Created(object sender, FileSystemEventArgs e)
{
//calls class FileManager's function MoveFiles (here is base logic of how and where files should move)
CustomServiceContainer.GetService<IFileManager>().MoveFiles(resources.sourcePath, resources.targetPath);
//this is the problem
Notification_form ntf = new Notification_form();
ntf.showAlert(eventType);
}
}
The problem is, when _fileWatcher_Created event calls notification form nothing gets displayed(even thought I can see on taskbar the window is created) and I can't get why, cause if I assign showAlert function to button's on click event it displays notification correctly.
If needed this is what Notification form looks like:
public partial class Notification_form : Form
{
private int x { get; set; }
private int y { get; set; }
public Notification_form()
{
InitializeComponent();
}
public enum enmAction { wait, start, close }
private Notification_form.enmAction action;
public void showAlert(string msg)
{
this.Opacity = 0.0;
this.StartPosition = FormStartPosition.Manual;
string fName;
for (int i = 1; i < 10; i++)
{
fName = "alert" + i.ToString();
Notification_form frm = (Notification_form)Application.OpenForms[fName];
if (frm == null)
{
this.Name = fName;
this.x = Screen.PrimaryScreen.WorkingArea.Width - this.Width + 15;
this.y = Screen.PrimaryScreen.WorkingArea.Height - this.Height * i;
this.Location = new Point(this.x, this.y);
break;
}
}
this.x = Screen.PrimaryScreen.WorkingArea.Width - base.Width - 5;
this.lblTitle.Text = msg;
this.Show();
this.action = enmAction.start;
this.timer1.Interval = 1;
this.timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
switch (this.action)
{
case enmAction.wait:
timer1.Interval = 5000;
action = enmAction.close;
break;
case Notification_form.enmAction.start:
this.timer1.Interval = 1;
this.Opacity += 0.1;
if (this.x < this.Location.X)
{
this.Left--;
}
else
{
if (this.Opacity == 1.0)
{
action = Notification_form.enmAction.wait;
}
}
break;
case enmAction.close:
timer1.Interval = 1;
this.Opacity -= 0.1;
this.Left -= 3;
if (base.Opacity == 0.0)
{
base.Close();
}
break;
}
}
private void btnCloseNtf_Click(object sender, EventArgs e)
{
timer1.Interval = 1;
action = enmAction.close;
}
}
For those who will come across the same problem, as Jimi said the main problem in this case was that UI and FileSystemWatcher work on different threads, so when I tried to call form from MyFileWatcher it didn't display form as the call was made from different thread, how did I fix it? well I set SynchronizingObject of FileSystemWatcher in Form(all credits go to Jimi) like this: fw._fileSystemWatcher.SynchronizingObject = this;
where fw
is FileSystemWatcher object which is passed to form durring its creation from Program class (Note: it's important to pass to form the same object that you'll use for getting notifications, in this case).
Moreover, creation of file doesn't mean that file can be moved(as Jimi said, again :)). Generally files are in temporary extension during its download(tmp, crdownload or maybe even other) so you need to check for file change as well to make sure that you are not moving temporary file with no value, and besides that, as file gets created and changed the notification form was called multiple times even thought I needed it to fire once as one file was created in reality. So how would I fix that? well I don't know if its the best solution but I created a new text document which has all the extension types that i want to move, so now I'm checking downloads folder for the extensions that are in my text document and if we have a match the file gets moved and as I'm not looking for temporary file types anymore the FileSystemWatcher actually gives me one Notification now. (and you can always add new file types in text document manually if needed, but I'm planning to integrate that function in the app)
Hope this helps somebody, some day...