Come posso ottenere DocumentViewer di WPF per rilasciare il blocco dei file sul documento XPS di origine?

StackOverflow https://stackoverflow.com/questions/1442607

Domanda

Dopo aver mostrato un file XPS in DocumentViewer WPF e aver chiuso l'istanza di DocumentViewer, il file XPS è bloccato e non posso eliminarlo. Devo rilasciare il blocco sul file XPS in modo da poterlo eliminare, scriverne un altro con lo stesso nome e, facoltativamente, visualizzare quel 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).

In altre parole, come ottengo l'esecuzione del codice seguente 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();

La chiusura dell'app rilascia il blocco dei file, come menzionato in WPF DocumentViewer non funziona rilasciare il file XPS , ma questa non è un'opzione in questo scenario.

È stato utile?

Soluzione

Devi chiudere System.IO.Packaging.Package da cui è stato aperto XpsDocument assegnato al visualizzatore. Inoltre, se si desidera poter riaprire 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 rimuovi il pacchetto dal PackageStore.

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

Quindi il segmento di codice fisso presentato nella domanda 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 che non ho aperto XpsDocument con un pacchetto - .NET lo ha fatto " per " dietro le quinte e dimentica di ripulire dopo se stesso.

Altri suggerimenti

Non sono sicuro di quale versione di .Net sia stata originariamente posta questa domanda o se questa potrebbe essere cambiata tra 3.xe 4.x, ma da alcune indagini su .Net 4.0 sembra che la soluzione potrebbe essere un po 'più semplice di così.

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

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

Quindi, a meno che non mi manchi qualcosa, Close () ing XpsDocument (che dovresti comunque fare) dovrebbe ottenere lo stesso risultato senza dover scavare nelle cose di gestione dei pacchetti interni che XpsDocument dovrebbe gestire.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top