调用线程必须是STA,因为许多UI组件在WPF中需要此错误。 在form.show()上

首先,我在网站上阅读了几个类似问题的答案,但说实话,我发现它们有点令人困惑(由于我缺乏经验而不是答案!)。 我正在使用FileSystemWatcher()类来监视正在创建/更改的文件的文件夹。 一旦事件发生,我就想在项目中加载另一个表单。 而不是加载表单我在新表单上的构造函数尝试执行时得到错误。 我只使用一个线程 – 我不是试图在不同的线程下加载表单。 我的代码如下

//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 } } 

希望你能提前帮助,非常感谢。

无论您使用多少线程都无关紧要。 只有一个规则:创建UI的任何线程都必须是STA。

如果您只有一个线程,那么这个线程必须是STA。 :-)为了使主线程成为STA,您需要在Main上使用STAThread属性:

 [STAThread] static void Main(string[] args) { // ... 

如果您只是创建一个标准的WPF应用程序,主线程已经标记了所需的属性,因此不需要更改。

请注意, FileSystemWatcher中的事件可能来自框架内部创建的其他一些线程。 (您可以通过在OnChanged设置断点来检查它。)在这种情况下,您需要将窗口创建转发到STA线程。 如果您的应用程序是WPF应用程序,它就是这样做的:

 public static void OnChanged(object source, FileSystemEventArgs e) { var d = Application.Current.Dispatcher; if (d.CheckAccess()) OnChangedInMainThread(); else d.BeginInvoke((Action)OnChangedInMainThread); } void OnChangedInMainThread() { var imagePreview = new ImagePreview(); imagePreview.Show(); } 

您正在从非UI线程调用UI内容(即FileSystemWatcher从非UI线程触发事件)。

我编写了一个扩展方法,我在我的唯一WPF项目(ugh)中使用了它:

 public static class DispatcherEx { public static void InvokeOrExecute(this Dispatcher dispatcher, Action action) { if (dispatcher.CheckAccess()) { action(); } else { dispatcher.BeginInvoke(DispatcherPriority.Normal, action); } } } 

所以现在,在使方法非静态以便您可以访问MainWindow Dispatcher之后,您可以在事件回调中执行此操作:

 public void OnChanged(object source, FileSystemEventArgs e) { this.Dispatcher.InvokeOrExecute(()=>{ var imagePreview = new ImagePreview(); imagePreview.Show(); }); } 

使用主窗口的调度程序。 通常每个应用程序只有一个UI线程,否则您可能会从WPF获得“无效的跨线程访问”exception。

文件系统观察程序在不同的线程上引发其事件,并且调度程序可用于使该代码在UI线程中运行。

在该事件处理程序中使用Dispatcher.BeginInvoke,你会没事的。 🙂