在使用BeginInvoke动态添加ListView项目时,“调用线程必须是STA,因为许多UI组件需要这样做。”

3

我正在尝试从BackgroundWorker调用一个方法,该方法将用户控件添加到ListView

private void AddItems(List<FileItem> fileItems) {
    System.Threading.Thread.CurrentThread.SetApartmentState(System.Threading.ApartmentState.STA);
    Dispatcher.BeginInvoke(new Action(() => files.ItemsSource = fileItems));
}

用户控件files在构造函数中成功地从fileItems获取数据,但它抛出了The calling thread must be STA, because many UI components require this.异常。我已经尝试逐个向所有父方法添加[STAThread]属性,但仍然会抛出异常。我应该在哪里添加此属性?
更新:
请注意,Dispatcher.BeginInvoke(new Action(() => files.Items.Clear()));执行正确。

1
当线程已经启动时,您不能调用SetApartmentState()。您不能随意应用[STAThread],它只适用于Main()入口点。请使用正确的调度程序,可能是Application.Current.Dispatcher。您应该使用BackgroundWorker.ReportProgress或RunWorkerCompleted。 - Hans Passant
@HansPassant 请看我的更新。我尝试了你在回答user2864740时提到的方法,但仍然抛出相同的异常。 - Aishwarya Shiva
2个回答

1
这个Dispatcher是指与BGW线程相关联的调度程序,而不是WPF/UI线程。如果当前线程没有关联任何调度程序/上下文,则默认情况下将创建一个新的调度程序/上下文;在此情况下,这完全没有用处。
如果从启动BGW的UI线程提供调度程序实例(Dispatcher.CurrentInstance),那么它“应该工作”。同样,正如Hans所指出的,正确的(WPF/UI)调度程序对象应该通过与应用程序相关联的调度程序访问。
此外,在ReportProgress方法中可以提供任意对象;这允许将信息发送回父级。然后可以在自动运行于正确的WPF/UI线程上的事件处理程序中处理UI组件的处理。(对于'工作完成'处理也是如此。)
标准的WPF项目不需要设置任何STA线程选项/属性。

我是这样做的 worker.ReportProgress(90, fileItems);,并启用了 WorkerReportsProgress=true。同时,在 ProgressChanged 事件中调用了 files.ItemsSource = fileItems。但仍然无法正常工作。我做得对吗? - Aishwarya Shiva
"不工作" = ?(在任何情况下,如果设置所有项目而不是进行代表“进度”的增量更改,则可能应该在worker-complete时完成。) - user2864740
抱歉没有说得更具体。但我的意思是它仍然显示相同的异常。 - Aishwarya Shiva
那很奇怪。那我就不知道了。可以尝试的一件事是,如果源是可枚举的,则强制实现源,例如 worker.ReportProgress(90, fileItems.ToList())(虽然由于它不是真正的“进度”,最好将其作为 BGW 的结果返回并在工作完成处理程序中处理..) - user2864740

0
直接在您的列表视图控件上调用BiginInvoke,如下所示:

files.BeginInvoke(new Action(() => files.ItemsSource = fileItems));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接