WPF DocumentViewer不会释放XPS文件

时间:2008-11-12 04:20:28

标签: .net wpf xps documentviewer

我正在开发一个打开并显示XPS文档的WPF应用程序。当应用程序关闭时,规范是应用程序应该删除打开的XPS文档以进行清理。但是,在打开某个XPS文档时,应用程序会在尝试删除该文件时抛出该文件仍在使用的异常。这有点奇怪,因为它只在打开特定的XPS文档时才会发生,并且只有在您超出第一页时才会发生。

我使用的一些代码如下所示:

打开XPS文档:

DocumentViewer m_documentViewer = new DocumentViewer();
XpsDocument m_xpsDocument = new XpsDocument(xpsfilename, fileaccess);
m_documentViewer.Document = m_xpsDocument.GetFixedDocumentSequence();
m_xpsDocument.Close();

用于导航XPS文档:

m_documentViewer.FirstPage();
m_documentViewer.LastPage();
m_documentViewer.PreviousPage();
m_documentViewer.NextPage();

关闭DocumentViewer对象并删除文件:

m_documentViewer.Document = null;
m_documentViewer = null;
File.Delete(xpsfilename);

这一切都非常基础,它适用于我们测试的其他文档。但是对于特定的XPS文档,会弹出一个异常,说明要删除的文件仍在使用中。

我的代码中是否有错误或遗漏?

谢谢!

6 个答案:

答案 0 :(得分:6)

您需要关闭分配给查看器的XpsDocument的System.IO.Packaging.Package。此外,如果您希望能够在同一个应用程序会话中再次打开同一个文件,则必须从PackageStore中删除该包。

尝试

var myXpsFile = @"c:\path\to\My XPS File.xps";
var myXpsDocument = new XpsDocument(myXpsFile);
MyDocumentViewer.Document = myXpsDocument;

//open MyDocumentViwer's Window and then close it
//NOTE: at this point your DocumentViewer still has a lock on your XPS file
//even if you Close() it
//but we need to do something else instead

//Get the Uri from which the system opened the XpsPackage and so your XpsDocument
var myXpsUri = myXpsDocument.Uri; //should point to the same file as myXpsFile

//Get the XpsPackage itself
var theXpsPackage = System.IO.Packaging.PackageStore.GetPackage(myXpsUri);

//THIS IS THE KEY!!!! close it and make it let go of it's file locks
theXpsPackage.Close();

File.Delete(myXpsFile); //this should work now

//if you don't remove the package from the PackageStore, you won't be able to
//re-open the same file again later (due to System.IO.Packaging's Package store/caching
//rather than because of any file locks)
System.IO.Packaging.PackageStore.RemovePackage(myXpsUri);

是的,我知道你可能没有用一个包打开XpsDocument,甚至可能都不知道是什么 - 或者关心 - 但.NET在幕后“为你”做了这件事并且忘了自己清理。

答案 1 :(得分:2)

将xpsDocument设为成员,然后不要对其调用close():)

答案 2 :(得分:0)

http://blogs.msdn.com/junfeng/archive/2008/04/21/use-htrace-to-debug-handle-leak.aspx

您可以使用WinDbg

找出谁拥有句柄和非托管堆栈

编辑:当然,您还可以通过SOS扩展程序(http://msdn.microsoft.com/en-us/library/bb190764.aspx)获取托管堆栈跟踪并进行搜索

答案 3 :(得分:0)

感谢您的回复!

这有点低级别但是当我用完想法时我会记住它。 无论如何,我发现了一些关于这个bug的更多信息。导致异常的特定文档中插入了图像。当我删除图像时,不会发生异常。这可能是一个DocumentViewer错误,但我还在努力......

答案 4 :(得分:0)

不,到目前为止仍然没有。

为了枚举,我尝试了以下失败的方法:

  1. 在删除文件之前,在窗口的“已关闭”事件中将所有内容设置为null。这包括DocumentViewer.Document属性和DocumentViewer对象。

  2. 使用ShowDialog()打开窗口并在之后将其设置为null。将删除文件移动到打开窗口的System.Windows.Application对象的“Exit”事件。仍然会抛出正在使用该文件的异常。

  3. DocumentViewer bug ???

答案 5 :(得分:0)

我怀疑你遇到了同样的问题 http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework/topic59281.aspx

听起来像是DocumentViewer中的一个错误,它应该在关闭时处理嵌套的BitmapDecoders,或者使用不同的位图缓存选项加载图像。