2009-09-18 5 views
9

Dopo aver mostrato un file XPS nel DocumentViewer di WPF e chiuso l'istanza di DocumentViewer, il file XPS è bloccato e non riesco a cancellarlo. Devo rilasciare il blocco sul file XPS in modo da poterlo eliminare, scrivere un altro con lo stesso nome e, facoltativamente, visualizzare il nuovo file XPS in una nuova istanza di DocumentViewer. Devo farlo nella stessa istanza dell'app, senza dover chiudere l'app (questo è uno scenario di Anteprima di stampa).Come posso ottenere che DocumentViewer di WPF rilasci il blocco dei file sul documento XPS di origine?

In altre parole, come posso ottenere il seguente codice da eseguire senza generare un'eccezione in "File.Delete (tempXpsFile);" affermazione?

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

chiusura dell'app fa rilasciare il blocco di file, come detto in WPF DocumentViewer doesn't release the XPS file, ma che non è un'opzione in questo scenario.

risposta

14

È necessario chiudere il System.IO.Packaging.Package da cui è stato aperto XpsDocument assegnato al visualizzatore. Inoltre, se si desidera essere in grado di aprire nuovamente lo stesso file all'interno della stessa sessione dell'applicazione, sarà necessario rimuovere il pacchetto dal PackageStore. La chiusura del pacchetto rilascerà il blocco del file e consentirà di eliminare il file, ma non sarà quindi possibile riaprire lo stesso file (o, più precisamente, qualsiasi file nella stessa posizione con lo stesso nome, anche se ha contenuto diverso) fino a quando non si rimuove il pacchetto dal PackageStore.

Nel contesto del codice nella domanda, inserire quanto segue dopo la prima previewWindow.ShowDialog(); prima di 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); 

Così il segmento di codice fisso presentato nella questione diventa:

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

Sì, lo so non ho aperto il XpsDocument con un pacchetto - NET ha fatto "per" me dietro la scene e dimentica di ripulire se stesso.

+0

Questo mi ha catturato, ho un visualizzatore che scarica un documento, una volta impostato il documento non avrebbe funzionato neanche dopo aver applicato queste modifiche.Quando stavo caricando il documento stavo smaltendo il documento originale che avrebbe causato il fallimento del rilascio quando sono andato a ricaricare il documento. –

4

Non sicuro quale versione di .Net questa domanda è stata originariamente richiesta in merito, o se questo potrebbe essere cambiato tra 3.xe 4.x, ma da qualche indagine contro .Net 4.0 sembra che la soluzione potrebbe essere un po 'più semplice di questo

XpsDocument implementare IDisposable, indicando che deve essere Dispose() dopo l'uso. La ruga è che IDisposable.Dispose() è implementato in modo tale che sia nascosto in modo da non poterlo chiamare direttamente. Devi invece chiamare Close(). Utilizzando dotPeek per analizzare XpsDocument.Dispose():

  • XpsDocument.Close() chiama XpsDocument.Dispose()
  • XpsDocument.Dispose() chiama XpsManager.Close chiamate()
  • XpsManager.Close() XpsManager.RemovePackageReference()
  • XpsManager.RemovePackageReference() chiama PackageStore.RemovePackage() e Package.Close()

Quindi, a meno che mi manca qualcosa, è sufficiente chiudere() ing l'XpsDocument (che si' re supposto di d o comunque) dovrebbe ottenere lo stesso risultato senza dover scavare nella roba di gestione dei pacchetti interna che deve essere gestita da XpsDocument.

+0

Questo è probabilmente l'approccio più semplice! –

Problemi correlati