问题描述
我正在出于教育目的创建Windows窗体应用程序,它的基本思想是拥有一个下载管理器,该管理器会将文件从默认的Downloads文件夹移动到带有文件扩展名的文件夹。我创建了MyFileWatcher类,该类基本上监视Downloads文件夹中是否有新文件,代码如下:
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);
}
}
问题是,当_fileWatcher_Created事件调用通知窗体时,什么都没有显示(即使我可以在任务栏上看到创建了窗口的窗口),我也不明白为什么,原因是如果我将showAlert函数分配给按钮的click事件,它将显示通知正确。
如果需要,这是“通知”表单的外观:
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;
}
}
解决方法
对于那些遇到相同问题的人,正如Jimi所说的,在这种情况下的主要问题是UI和FileSystemWatcher在不同的线程上工作,因此当我尝试从MyFileWatcher调用表单时,它并没有显示表单是由不同的线程制成的,我该如何解决?好吧,我在Form中设置FileSystemWatcher的SynchronizingObject(所有功劳归于Jimi),如下所示:fw._fileSystemWatcher.SynchronizingObject = this;
其中fw
是FileSystemWatcher对象,该对象在程序类的创建过程中被传递给表单(注意:重要的是传递以形成用于获取通知的对象(在这种情况下)。
此外,创建文件并不意味着可以移动文件(就像Jimi所说的那样:)。通常,文件在下载过程中处于临时扩展名(tmp,crdownload或什至其他),因此您还需要检查文件更改,以确保您没有移动没有价值的临时文件,此外,随着文件的创建并多次更改了通知表单,甚至以为实际上创建一个文件后就需要触发它。那我该如何解决呢?好吧,我不知道它是否是最好的解决方案,但是我创建了一个新的文本文档,其中包含我要移动的所有扩展名类型,所以现在我要检查下载文件夹中文本文档中的扩展名,以及是否有一个匹配文件被移动,并且由于我不再寻找临时文件类型了,FileSystemWatcher实际上现在给我一个通知。 (而且您随时可以根据需要手动在文本文档中添加新文件类型,但我打算将该功能集成到应用中)
希望这对某人有帮助...