2009-09-18 6 views
9

После отображения XPS-файла в WPF DocumentViewer и закрытия экземпляра DocumentViewer файл XPS заблокирован, и я не могу его удалить. Мне нужно освободить блокировку в файле XPS, чтобы я мог ее удалить, написать еще одно имя с таким же именем и, возможно, отобразить этот новый файл XPS в новом экземпляре DocumentViewer. Мне нужно сделать это в одном экземпляре приложения - без закрытия приложения (это сценарий предварительного просмотра).Как мне заставить DocumentViewer WPF освободить блокировку файла в исходном документе 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 doesn't release the XPS file, но это не вариант в этом случае.

ответ

14

Вам необходимо закрыть пакет System.IO.Packaging.Package, из которого был открыт XpsDocument, назначенный зрителю. Кроме того, если вы хотите снова открыть один и тот же файл в одном сеансе приложения, вам придется удалить пакет из PackageStore. Закрытие пакета освободит блокировку файла и позволит вам удалить файл, но вы не сможете повторно открыть тот же файл (или, точнее, любой файл в том же месте с тем же именем, даже если он имеет различный контент), пока вы не удалите пакет из PackageStore.

В контексте кода в вопросе вставьте следующее после первого предварительного просмотраWindow.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 сделал это «для» меня позади сцены и забывает очистить после себя.

+0

Этот человек поймал меня, у меня есть средство просмотра, которое загружает документ, после того, как он установил документ, он сработает даже после применения этих изменений.Когда я загружал документ, я удалял исходный документ, который привел бы к ошибке выхода, когда я перегрузил документ. –

4

Не знаете, в какой версии .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() и Package.Close()

Так что, если я что-то, как раз Close() ING в XpsDocument (отсутствует, который вы» Предполагается, что d o в любом случае) должен достичь того же результата без необходимости вникать во внутренние элементы управления пакетами, которые должен обрабатывать XpsDocument.

+0

Это, возможно, самый простой подход! –

 Смежные вопросы

  • Нет связанных вопросов^_^