【问题标题】:How to consume a FixedDocument from a background thread?如何从后台线程使用 FixedDocument?
【发布时间】:2019-03-03 13:58:49
【问题描述】:

当一切都在同一个线程上时,以下代码可以正常工作。但是,当在后台线程上制作 FixedDocument 时,将 PrintPreview 移动到 UI 线程时,我得到:

"调用线程无法访问该对象,因为不同的 线程拥有它。”

问题线是:

writer.Write(fixeddocument.DocumentPaginator);

我无法获得 Dispatcher.invoke/begininvoke -- 或其他任何东西来解决这个问题。

那么如何将另一个线程中的 FixedDocument 带到 UI 线程中呢?

(请注意,FixedDocument 需要几分钟才能生成,因此必须在后台线程上创建。是的,我已经用 Google 搜索了好几个小时,但没有找到任何解决方案。如果有,我错过了)。

我一直在想,我必须将 PrintPreview 与 FixedDocument 保持在同一个线程中——我希望不会。

// Print Preview
public static void PrintPreview(FixedDocument fixeddocument, CancellationToken ct)
{
    // Was cancellation already requested? 
    if (ct.IsCancellationRequested)
          ct.ThrowIfCancellationRequested();

    MemoryStream ms = new MemoryStream();

    using (Package p = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite))
    {
        Uri u = new Uri("pack://TemporaryPackageUri.xps");
        PackageStore.AddPackage(u, p);

        XpsDocument doc = new XpsDocument(p, CompressionOption.Maximum, u.AbsoluteUri);

        XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);

        writer.Write(fixeddocument.DocumentPaginator);

        FixedDocumentSequence fixedDocumentSequence = doc.GetFixedDocumentSequence();

        var previewWindow = new PrintPreview(fixedDocumentSequence);

        Action closeAction = () => previewWindow.Close();

        ct.Register(() =>
              previewWindow.Dispatcher.Invoke(closeAction) 
        );

       previewWindow.ShowDialog();  

        PackageStore.RemovePackage(u);
        doc.Close();
    }
}

【问题讨论】:

    标签: c# wpf multithreading


    【解决方案1】:

    这显然是您方法中的static 修饰符。改成实例方法可以方便Dispatcher

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
        }
    
        // Print Preview
        public void PrintPreview(FixedDocument fixeddocument, CancellationToken ct)
        {
            // Was cancellation already requested? 
            if (ct.IsCancellationRequested)
                ct.ThrowIfCancellationRequested();
    
    
            MemoryStream ms = new MemoryStream();
    
            using (Package p = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite))
            {
                Uri u = new Uri("pack://TemporaryPackageUri.xps");
                PackageStore.AddPackage(u, p);
    
                XpsDocument doc = new XpsDocument(p, CompressionOption.Maximum, u.AbsoluteUri);
    
                XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
    
                //writer.Write(fixeddocument.DocumentPaginator);
                Dispatcher.Invoke(new Action<DocumentPaginator>(writer.Write), fixeddocument.DocumentPaginator);
    
                FixedDocumentSequence fixedDocumentSequence = doc.GetFixedDocumentSequence();
    
                var previewWindow = new PrintPreview(fixedDocumentSequence);
    
                Action closeAction = () => previewWindow.Close();
    
                ct.Register(() =>
                      previewWindow.Dispatcher.Invoke(closeAction)
                );
    
                previewWindow.ShowDialog();
    
                PackageStore.RemovePackage(u);
                doc.Close();
            }
        }
    }
    

    【讨论】:

    • Dispatcher.Invoke 未编译。使用 Dispatcher.CurrentDispatcher.Invoke 会导致“调用目标抛出异常”。现在怎么办?谢谢。
    • @AlanWayne,尝试将PrintPreview 放在System.Windows.Window 类中。我想你已经删除了 static 修饰符。
    • @BodDust 是的...我对此进行了重构,以将 PrintPreview 带回主线程并删除了静态修饰符。我不确定“将 PrintPreview 放在 System.Windows.Window 中”是什么意思。例子??
    • 谢谢。但是我没有看到使用 MainWindow 类创建一个空窗口只是为了创建第二个 PrintPreview 窗口的意义? (即,PrintPreview 是一个使用 DocumentViewer 作为主要元素来显示 fixedDocumentSequence 的窗口)...除非您打算将 DoceumentViewer 移动到 MainWindow 并让它从后台线程中获取 fixeddocument 作为其内容???即使将 PrintPreview 保留在主 UI 线程中,当固定文档来自另一个线程“调用的目标已引发异常”时,也会出现问题。
    • @AlanWayne,这就是一个例子。我不是说要创建一个空窗口。您可能想定义一个WindowBase 并将PrintPreview 放在该类中。那么对PrintPreview 的任何调用都应该从继承自WindowBase 的类中完成。除了从拥有它的线程以外的线程访问FixedDocument 的问题之外,您还需要检查创建FixedDocument 的线程是否是STA 线程。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-26
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多