2009-09-18 8 views
9

Po wyświetleniu pliku XPS w przeglądarce dokumentów WPF i zamknięciu instancji DocumentViewer plik XPS jest zablokowany i nie można go usunąć. Muszę zwolnić blokadę pliku XPS, aby móc go usunąć, napisać inny o tej samej nazwie i opcjonalnie wyświetlić ten nowy plik XPS w nowej instancji DocumentViewer. Muszę to zrobić w tej samej aplikacji - bez zamykania aplikacji (jest to scenariusz podglądu wydruku).Jak uzyskać przeglądarkę dokumentów WPF, aby zwolnić blokadę pliku w źródłowym dokumencie XPS?

Innymi słowy, w jaki sposób można uzyskać poniższy kod, bez wyrzucania wyjątku w "File.Delete (tempXpsFile);" komunikat?

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

Zamykanie aplikacji zwalnia blokadę pliku, jak wspomniano w WPF DocumentViewer doesn't release the XPS file, ale to nie jest opcją w tym scenariuszu.

Odpowiedz

14

Należy zamknąć plik System.IO.Packaging.Package, z którego został otwarty dokument XpsDocument dla przeglądarki. Ponadto, jeśli chcesz mieć możliwość ponownego otwarcia tego samego pliku w ramach tej samej sesji aplikacji, będziesz musiał usunąć pakiet z PackageStore. Zamknięcie pakietu spowoduje zwolnienie blokady pliku i pozwoli na usunięcie pliku, ale nie będzie można ponownie otworzyć tego samego pliku (lub, dokładniej, dowolnego pliku w tej samej lokalizacji o tej samej nazwie, nawet jeśli ma on inna zawartość) do momentu usunięcia Pakietu z PackageStore.

W kontekście kodu w pytaniu, wstaw następujące po pierwszym previewWindow.ShowDialog(); przed 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); 

Więc segment stały kod przedstawiony w pytaniu staje:

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

Tak, wiem, że nie otworzyć XpsDocument z pakietem - NET to zrobił „za” Za mną sceny i zapomina o sprzątaniu po sobie.

+0

Ten jeden przykuł mnie, mam widza, który pobiera dokument, kiedy ustawił dokument, który zawiedzie nawet po zastosowaniu tych zmian.Kiedy ładowałem dokument, wyrzucałem oryginalny dokument, który spowodowałby niepowodzenie wydania, gdy poszłam przeładować dokument. –

4

Nie jestem pewien, która wersja .Net to pytanie było pierwotnie zadawane w odniesieniu do, lub czy mogło to zmienić się między 3.x a 4.x, ale z jakiegoś dochodzenia przeciwko .Net 4.0 wygląda na to, że rozwiązanie może być nieco prostsze niż to.

Narzędzie XpsDocument IDisposable, wskazujące, że musi to być Dispose() 'd po użyciu. Zmarszczka polega na tym, że IDisposable.Dispose() jest zaimplementowana tak, że jest ukryta, więc nie możesz jej wywołać bezpośrednio. Musisz zamiast tego wywołać Close(). Korzystanie dotPeek analizować XpsDocument.Dispose():

  • XpsDocument.Close() wywołuje XpsDocument.Dispose()
  • XpsDocument.Dispose() wywołuje XpsManager.Close()
  • XpsManager.Close() wywołuje XpsManager.RemovePackageReference()
  • XpsManager.RemovePackageReference() wywołuje PackageStore.RemovePackage() i() Package.Close

Więc jeśli ja czegoś brakuje, po prostu Close() ing z XpsDocument (które” powinienem d o tak) powinien osiągnąć ten sam wynik bez konieczności zagłębiania się w wewnętrzne zarządzanie pakietami, które powinien obsługiwać XpsDocument.

+0

Jest to prawdopodobnie najprostsze podejście! –

Powiązane problemy