Firstly I have read several answers to similar questions on the site but to be honest I find them a bit confusing (due to my lack of experience rather than the answers!). I am using a the FileSystemWatcher() class to monitor a folder for a file being created/changed. Once the event occurs I then want to load another form in the project. Instead of loading the form I get the error when the constructor on the new form is trying to execute. I am only using one thread - I'm not attempting to load the form under a different thread. My code is as follows
//MainWindow
public static void FolderWatcher()
{
FileSystemWatcher fsWatcher = new FileSystemWatcher();
fsWatcher.Path = "C:\\dump";
fsWatcher.Filter = "*";
fsWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
fsWatcher.Created += new FileSystemEventHandler(OnChanged);
fsWatcher.EnableRaisingEvents = true;
}
public static void OnChanged(object source, FileSystemEventArgs e)
{
var imagePreview = new ImagePreview();
imagePreview.Show();
}
//SecondForm
public partial class ImagePreview : Window
{
public ImagePreview()
{
InitializeComponent(); //error occurs here
}
}
Hope you can help, many thanks in advance.
Use the dispatcher of the main window. Usually there is just one UI thread per application, otherwise you may get an "invalid cross-thread access" exception from WPF.
The file system watcher raises its events on a different thread and the dispatcher can be used to make that code run in the UI thread.
Use Dispatcher.BeginInvoke in that event handler and you'll be fine. :)
You're calling UI stuff from a non-UI thread (i.e. the
FileSystemWatcher
is firing the event from a non-UI thread).I wrote an extension method that I used in my one and only WPF project (ugh):
so now, after making the methods non-static so you have access to the MainWindow Dispatcher, you'd do this in your event callback:
It doesn't matter how many threads you are using. There is just a rule: any thread where you are creating UI must be STA.
In case you have only one thread, this very one has to be STA. :-) In order to make the main thread an STA, you need to use the
STAThread
attribute on yourMain
:If you just create a standard WPF application, the main thread is already marked with the needed attribute, so there should be no need for change.
Beware that the events from
FileSystemWatcher
may come from some other thread which is internally created by the framework. (You can check that by setting a breakpoint inOnChanged
.) In this case, you need to forward the window creation to an STA thread. In case your application is a WPF application, it's done this way: