我正在处理报告系统,将通过DocumentPage
创建一系列DocumentPaginator
。这些文档包括一些 WPF组件,这些文件将被实例化,以便在以后发送到XpsDocumentWriter
(然后将其发送到实际打印机)时,分页器包含正确的内容。 / p>
我现在的问题是DocumentPage
个实例需要很长时间才能创建(足以让Windows将应用程序标记为已冻结),所以我尝试在后台线程中创建它们,这是有问题的,因为WPF期望从GUI线程设置它们的属性。我还希望显示一个进度条,指示到目前为止已创建了多少页。因此,看起来我试图在GUI上并行发生两件事情。
问题很难解释,我真的不确定如何解决它。简而言之:
DocumentPag
e。
如果没有合适的方法可以做到这一点,我们非常欢迎其他解决方案和方法。
答案 0 :(得分:1)
只要线程是STA,您就应该能够在后台线程中运行paginator。
设置完线程后,请在运行之前尝试此操作。
thread.SetApartmentState(ApartmentState.STA);
如果你真的必须在GUI线程上,那么请查看Freezable类,因为你可能必须将对象从后台线程移动到GUI线程。
答案 1 :(得分:0)
如果需要UI线程的部分相对较小,则可以使用Dispatcher执行这些操作,而不会阻止UI。这有与此相关的开销,但它可能允许大量计算在后台进行,并将UI线程上的工作与其他UI任务交错。您也可以使用Dispatcher更新进度条。
答案 2 :(得分:0)
我的猜测是创建的所有内容都在您的Visual中。如果是这样,有一个简单的解决方案:在调用DocumentPaginator.GetPage()之前,不要创建实际的DocumentPage对象及其关联的Visual。
只要使用您的文档的代码一次只请求一个或两个页面,就不会出现性能瓶颈。
如果您要打印到打印机或文件,一切都可以在后台线程上完成,但如果您在屏幕上显示,则无论如何都只需要一次显示几个DocumentPages。在任何一种情况下,您都不会获得任何UI锁定。
最糟糕的情况是应用程序以缩略图视图显示页面。在这种情况下,我会:
如果由于单独项目的数量而在实现单个页面时存在性能问题,则可以在中使用内的相同通用方法,无论页面上的ItemsControl具有大量项目。< / p>
还有一点需要注意:XPS打印系统一次不会处理多个DocumentPage,所以如果您知道这是您的客户端,您实际上可以通过适当的修改一遍又一遍地返回相同的DocumentPage。
答案 3 :(得分:0)
进一步阐述Ray Burns的回答:难道你不能在后台线程的类中完成数据处理,然后在处理完成后将DocumentPage的属性数据绑定到这个类吗?
答案 4 :(得分: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完成时,进度对话框可以关闭。
'Action'是用于创建所有UI元素的方法。它监视取消标志的上下文,并在设置标志时停止生成UI元素。它完成时设置完整的标志。
我不记得我必须将Thread't'设置为STA线程并将IsBackground设置为true的确切原因,但我很确定如果没有它们将无法工作。