繁体   English   中英

在后台线程中创建WPF组件

[英]Creating WPF components in background thread

进出口报告系统的工作,一系列DocumentPage是通过创建DocumentPaginator 这些文档包括许多要实例化的WPF组件 ,因此分页器在以后发送到XpsDocumentWriter (然后又发送到实际打印机)时包括正确的内容。

我现在的问题是,创建DocumentPage实例要花很长时间(Windows足以将应用程序标记为冻结),所以我尝试在后台线程中创建它们,这是有问题的,因为WPF希望从中设置它们的属性。 GUI线程。 我还希望显示一个进度条,指示到目前为止已创建了多少个页面。 因此,似乎Im试图在GUI上并行发生两件事。

这个问题很难解释,我真的不确定如何解决。 简而言之:

  • 创建一系列DocumentPag e。
    • 这些包括WPF组件
    • 这些将在后台线程上创建,或使用其他技巧使应用程序不冻结。
  • 创建每个页面后,应更新WPF ProgressBar

如果没有做到这一点的体面方法,则非常欢迎使用替代解决方案和方法。

只要线程是STA,您就应该能够在后台线程中运行分页器。

设置线程后,请在运行线程之前尝试此操作。

thread.SetApartmentState(ApartmentState.STA);

如果确实必须使用GUI线程,请检出Freezable类,因为您可能必须将对象从后台线程移至GUI线程。

在这个游戏上,游戏有点晚了,但是我只是为此解决了一个办法,所以我想分享一下。 为了显示UI元素,必须在将显示它们的UI线程上创建它们。 由于长时间运行的任务在UI线程上,因此它将阻止进度条的更新。 为了解决这个问题,我在新的UI线程上创建了进度条,并在主UI线程上创建了页面。

        Thread t = new Thread(() =>
            {
                ProgressDialog pd = new ProgressDialog(context);
                pd.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
                pd.Show();
                System.Windows.Threading.Dispatcher.Run();
            });
        t.SetApartmentState(ApartmentState.STA);
        t.IsBackground = true;
        t.Start();

        Action();   //we need to execute the action on the main thread so that UI elements created by the action can later be displayed in the main UI

“ ProgressDialog”是我自己的WPF窗口,用于显示进度信息。

“上下文”保存我的进度对话框的进度数据。 它包括一个canceled属性,以便我可以中止在主线程上运行的操作。 它还包括complete属性,因此在Action完成后可以关闭进度对话框。

“操作”是用于创建所有UI元素的方法。 它监视取消标志的上下文,如果设置了标志,则停止生成UI元素。 完成时设置完成标志。

我不记得我必须将Thread't'设置为STA线程并将IsBackground设置为true的确切原因,但是我很确定如果没有它们,它将无法正常工作。

如果需要UI线程的部分相对较小,则可以使用Dispatcher来执行那些操作,而不会阻塞UI。 与此相关的开销很大,但它可能允许大部分计算在后台进行,并且会使UI线程上的工作与其他UI任务交错。 您也可以使用分派器更新进度条。

我的猜测是,创建所有耗时的内容都在Visual中。 如果是这样,那么有一个简单的解决方案:在调用DocumentPaginator.GetPage()之前,不要创建实际的DocumentPage对象及其关联的Visuals。

只要占用您文档的代码一次只请求一页或两页,就不会出现性能瓶颈。

如果要打印到打印机或文件,则可以在后台线程上完成所有操作,但是如果要在屏幕上显示,则无论如何一次只需要显示几个DocumentPages。 无论哪种情况,您都不会获得任何UI锁定。

最坏的情况是应用程序以缩略图显示页面。 在这种情况下,我将:

  1. 缩略图视图会将其ItemsSource绑定到“ RealizedPages”集合,该集合最初填充有伪页面
  2. 每当测量伪页面时,它都会在DispatcherPriority.Background上将调度程序操作排队,以调用DocumentPaginator.GetPage(),然后用实际页面替换RealizedPages集合中的伪页面。

如果由于单个项目的数量而导致即使在实现单个页面时也存在性能问题,则可以页面上具有大量项目的ItemsControl中使用这种相同的通用方法。

还有一点要注意:XPS打印系统一次不会处理一个以上的DocumentPage,因此,如果您知道那是您的客户,则实际上可以通过适当的修改一遍又一遍地返回相同的DocumentPage。

更详细地说明Ray Burns的答案:您是否可以在后台线程的类中完成数据处理,然后在处理完成后将DocumentPage的属性数据绑定到此类?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM