当前位置:  开发笔记 > 编程语言 > 正文

如何让WPF的DocumentViewer在源XPS文档上释放其文件锁?

如何解决《如何让WPF的DocumentViewer在源XPS文档上释放其文件锁?》经验,为你挑选了2个好方法。

在WPF DocumentViewer中显示XPS文件并关闭DocumentViewer实例后,XPS文件被锁定,我无法删除它.我需要释放XPS文件上的锁,以便我可以删除它,编写另一个具有相同名称的文件,并可选择在新的DocumentViewer实例中显示新的XPS文件.我需要在同一个应用程序实例中执行此操作 - 无需关闭应用程序(这是打印预览方案).

换句话说,如何在不在"File.Delete(tempXpsFile);"处抛出异常的情况下运行以下代码?声明?

var tempXpsFile = @"c:\path\to\Temporary.xps";

var previewWindow = new Window();
var docViewer = new DocumentViewer();
previewWindow.Content = docViewer;

GenerateXpsFile(tempXpsFile);

var xpsDocument = new XpsDocument(tempXpsFile);

previewWindow.ShowDialog();

File.Delete(tempXpsFile);  //this will throw an exception due to a file lock on tempXpsFile

GenerateXpsFile(tempXpsFile); //assume this generates a different file
//otherwise the scenario doesn't make sense as we could just skip the above delete
//and this statement and re-use the same file

previewWindow = new Window();
docViewer = new DocumentViewer();
previewWindow.Content = docViewer;

previewWindow.ShowDialog();

关闭应用程序会释放文件锁定,如WPF中所述,DocumentViewer不会释放XPS文件,但在此方案中这不是一个选项.



1> Tim Erickson..:

您需要关闭System.IO.Packaging.Package,从中打开分配给查看器的XpsDocument.此外,如果您希望能够在同一应用程序会话中再次打开同一文件,则必须从PackageStore中删除Package.关闭包将释放文件锁并允许您删除该文件,但是您将无法重新打开该文件(或者更准确地说,即使它具有相同名称的同一位置的任何文件)从PackageStore中删除Package之前的不同内容.

在问题代码的上下文中,在第一个previewWindow.ShowDialog()之后插入以下内容; 在File.Delete之前(tempXpsFile);

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

//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();

//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);

因此,问题中提供的固定代码段变为:

var tempXpsFile = @"c:\path\to\Temporary.xps";

var previewWindow = new Window();
var docViewer = new DocumentViewer();
previewWindow.Content = docViewer;

GenerateXpsFile(tempXpsFile);

var xpsDocument = new XpsDocument(tempXpsFile);

previewWindow.ShowDialog();

//BEGIN NEW CODE
var myXpsUri = xpsDocument.Uri; //should point to the same file as tempXpsFile
var theXpsPackage = System.IO.Packaging.PackageStore.GetPackage(myXpsUri);
theXpsPackage.Close();
System.IO.Packaging.PackageStore.RemovePackage(myXpsUri);
//END NEW CODE

File.Delete(tempXpsFile);  //this will succeed now

GenerateXpsFile(tempXpsFile);

previewWindow = new Window();
docViewer = new DocumentViewer();
previewWindow.Content = docViewer;

previewWindow.ShowDialog();

是的,我知道我没有用一个包打开XpsDocument - .NET在幕后"为"我做了它并且忘了自己清理.



2> rationull..:

不确定.Net最初询问的是什么版本的这个问题,或者这个问题是否可能在3.x和4.x之间发生了变化,但是根据对.Net 4.0的一些调查,看起来解决方案可能相当多比这更简单.

XpsDocument实现了IDisposable,表明它在使用后需要是Dispose().皱纹是IDisposable.Dispose()被实现,以便它被隐藏,所以你不能直接调用它.你需要调用Close().使用dotPeek分析XpsDocument.Dispose():

XpsDocument.Close()调用XpsDocument.Dispose()

XpsDocument.Dispose()调用XpsManager.Close()

XpsManager.Close()调用XpsManager.RemovePackageReference()

XpsManager.RemovePackageReference()调用PackageStore.RemovePackage()和Package.Close()

因此,除非我遗漏了某些东西,否则只需关闭()你应该做的XpsDocument就应该达到相同的结果,而不必深入研究XpsDocument应该处理的内部包管理内容.

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有