Как получить DocumentViewer WPF, чтобы освободить блокировку файла в исходном документе XPS?
после показа файла XPS в WPF DocumentViewer и закрытия экземпляра DocumentViewer файл XPS заблокирован, и я не могу его удалить. Мне нужно освободить блокировку файла XPS, чтобы я мог удалить его, написать другой с тем же именем и, возможно, отобразить этот новый файл XPS в новом экземпляре DocumentViewer. Мне нужно сделать это в том же экземпляре приложения - без необходимости закрывать приложение (это сценарий предварительного просмотра).
другими словами, как бы я получить следующий код для запуска без исключения в "файл".Удалить(tempXpsFile);" заявление?
var tempXpsFile = @"c:pathtoTemporary.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, но это не вариант в этом случае.
2 ответов
вам нужно закрыть систему.ИО.Упаковка.Пакет, из которого был открыт XpsDocument, назначенный средству просмотра. Кроме того, если вы хотите снова открыть тот же файл в том же сеансе приложения, вам придется удалить пакет из PackageStore. Закрытие пакета освободит блокировку файла и позволит вам удалить файл, но вы не сможете повторно открыть тот же файл (или, точнее, любой файл в том же месте с тем же именем, даже если он имеет другое содержимое), пока вы не удалите пакет из PackageStore.
в контексте кода в вопрос, вставить после первого previewWindow.ShowDialog (); перед файлом.Удалить(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 сделал это "для" меня за кулисами и забывает убирать за собой.
Не уверен, какая версия .Net этот вопрос был первоначально задан в отношении, или, возможно, это изменилось между 3.x и 4.x, но из некоторых исследований против .Net 4.0 похоже, что решение может быть довольно простым, чем это.
XpsDocument реализует IDisposable, указывая, что он должен быть Dispose()'d после использования. Морщина в том, что IDisposable.Dispose () реализован таким образом, что он скрыт, поэтому вы не можете вызвать его напрямую. Вам нужно позвонить Close() вместо. Использование dotPeek для анализа XpsDocument.Dispose ():
- XpsDocument.Close() вызывает XpsDocument.Dispose ()
- XpsDocument.Dispose () вызывает XpsManager.Close ()
- XpsManager.Close () вызывает XpsManager.RemovePackageReference ()
- XpsManager.RemovePackageReference () вызывает PackageStore.RemovePackage () и упаковка.Close ()
поэтому, если я чего-то не упускаю, просто закройте () в XpsDocument (который вы должны сделать в любом случае) должен достичь того же результата без необходимости копаться во внутреннем материале управления пакетами, который должен обрабатывать XpsDocument.