2009-09-18 13 views
9

Nachdem eine XPS-Datei im WPF DocumentViewer angezeigt und die DocumentViewer-Instanz geschlossen wurde, ist die XPS-Datei gesperrt und kann nicht gelöscht werden. Ich muss die Sperre für die XPS-Datei freigeben, damit ich sie löschen, eine weitere mit dem gleichen Namen schreiben und diese neue XPS-Datei optional in einer neuen DocumentViewer-Instanz anzeigen kann. Ich muss dies in derselben App-Instanz tun - ohne die App schließen zu müssen (dies ist ein Druckvorschau-Szenario).Wie bekomme ich den DocumentViewer von WPF, um seine Dateisperre für das Quell-XPS-Dokument freizugeben?

Mit anderen Worten, wie würde ich den folgenden Code ausführen, ohne eine Ausnahme bei "File.Delete (tempXpsFile);" Erklärung?

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

die App Schließen funktioniert die Dateisperre freizugeben, wie in WPF DocumentViewer doesn't release the XPS file erwähnt, aber das ist keine Option in diesem Szenario.

Antwort

14

Sie müssen das System.IO.Packaging.Package schließen, von dem das dem Viewer zugewiesene XpsDocument geöffnet wurde. Wenn Sie dieselbe Datei innerhalb derselben Anwendungssitzung erneut öffnen möchten, müssen Sie das Paket aus dem PackageStore entfernen. Durch das Schließen des Pakets wird die Dateisperre aufgehoben und Sie können die Datei löschen. Sie können diese Datei (oder genauer gesagt, jede Datei am selben Speicherort mit dem gleichen Namen jedoch nicht erneut öffnen, selbst wenn dies der Fall ist) anderen Inhalt), bis Sie das Paket aus dem PackageStore entfernen.

Geben Sie im Kontext des Codes in der Frage nach der ersten previewWindow.ShowDialog(); vor dem 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); 

So ist das feste Codesegment in der Frage vorgelegt wird:

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

Ja, ich weiß, dass ich nicht die XpsDocument mit einem Paket geöffnet habe - .NET tat es „für“ mich hinter dem Szenen und vergisst, sich selbst aufzuräumen.

+0

Dieser hat mich erwischt, ich habe einen Viewer, der ein Dokument herunterlädt, sobald es das Dokument eingestellt hat, würde es auch nach dem Anwenden dieser Änderungen fehlschlagen.Als ich das Dokument geladen habe, habe ich das Originaldokument entsorgt, wodurch die Freigabe fehlschlagen würde, wenn ich das Dokument neu laden wollte. –

4

Nicht sicher, welche Version von. NET diese Frage wurde ursprünglich in Bezug auf gefragt, oder ob dies zwischen 3.x und 4.x geändert haben könnte, aber aus einigen Untersuchungen gegen .Net 4.0 sieht es aus wie die Lösung möglicherweise ein bisschen einfacher sein als das.

XpsDocument-Gerät IDisposable, das anzeigt, dass es Dispose() 'd nach der Verwendung sein muss. Der Kniff ist, dass IDisposable.Dispose() so implementiert ist, dass es versteckt ist, so dass Sie es nicht direkt aufrufen können. Sie müssen stattdessen Close() aufrufen. dotPeek Mit XpsDocument.Dispose() zu analysieren:

  • XpsDocument.Close() ruft XpsDocument.Dispose()
  • XpsDocument.Dispose() ruft XpsManager.Close()
  • XpsManager.Close() Anrufe XpsManager.RemovePackageReference()
  • XpsManager.RemovePackageReference() ruft PackageStore.RemovePackage() und Package.Close()

Also, wenn ich etwas fehle, nur Close() ing die XpsDocument (die Sie‘ soll d o sowieso) sollte das gleiche Ergebnis erzielen, ohne sich in die internen Paketverwaltungsfunktionen zu vertiefen, die XpsDocument verarbeiten sollte.

+0

Dies ist wohl der einfachste Ansatz! –