1

我正在开发一个报告系统,DocumentPage将通过DocumentPaginator. 这些文档包括许多要实例化的WPF 组件XpsDocumentWriter,因此分页器在稍后发送到(又发送到实际打印机)时包含正确的内容。

我现在的问题是DocumentPage创建实例需要相当长的时间(足以让 Windows 将应用程序标记为已冻结)所以我尝试在后台线程中创建它们,这是有问题的,因为 WPF 期望它们的属性从图形用户界面线程。我还想显示一个进度条,指示到目前为止已经创建了多少页。因此,看起来我试图让两件事在 GUI 上并行发生。

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

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

如果没有合适的方法来做到这一点,那么替代解决方案和方法将非常受欢迎。

4

5 回答 5

1

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

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

thread.SetApartmentState(ApartmentState.STA);

如果您真的必须在 GUI 线程上,请查看Freezable类,因为您可能必须将对象从后台线程移动到 GUI 线程。

于 2010-06-10T20:54:22.480 回答
0

Elaborating further on Ray Burns' answer: Couldn't you have your dataprocessing done in a class on a background thread and then databind the DocumentPage's properties to this class when the processing is done?

于 2010-08-06T12:27:26.860 回答
0

这个游戏有点晚了,但我刚刚找到了一个解决方案,所以我想我会分享。为了显示 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 窗口,用于显示进度信息。

'context' 保存我的进度对话框的进度数据。它包括一个取消的属性,以便我可以中止在主线程上运行的操作。它还包括一个完整的属性,以便在操作完成时可以关闭进度对话框。

'Action' 是用于创建所有 UI 元素的方法。它监视取消标志的上下文,如果设置了该标志,它将停止生成 UI 元素。它在完成时设置完成标志。

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

于 2013-12-09T18:22:59.593 回答
0

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

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

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

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

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

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

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

于 2010-06-12T00:59:23.703 回答
0

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

于 2010-06-10T21:10:43.497 回答