2009-09-18 10 views
9

Después de mostrar un archivo XPS en WPF DocumentViewer y cerrar la instancia de DocumentViewer, el archivo XPS está bloqueado y no puedo eliminarlo. Necesito liberar el bloqueo en el archivo XPS para poder eliminarlo, escribir otro con el mismo nombre y, opcionalmente, mostrar ese nuevo archivo XPS en una nueva instancia de DocumentViewer. Necesito hacer esto en la misma instancia de la aplicación, sin tener que cerrar la aplicación (este es un escenario de Vista previa de impresión).¿Cómo hago para que el DocumentViewer de WPF libere su bloqueo de archivos en el documento XPS de origen?

En otras palabras, ¿cómo obtendría el siguiente código para ejecutar sin lanzar una excepción en el "File.Delete (tempXpsFile);" ¿declaración?

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

Cierre de la aplicación hace liberar el bloqueo de archivo, como se menciona en WPF DocumentViewer doesn't release the XPS file, pero eso no es una opción en este escenario.

Respuesta

14

Debe cerrar System.IO.Packaging.Package desde el que se abrió el XpsDocument asignado al visor. Además, si desea poder volver a abrir el mismo archivo dentro de la misma sesión de la aplicación, deberá eliminar el Paquete de la Tienda de paquetes. Al cerrar el paquete se liberará el bloqueo del archivo y se le permitirá eliminar el archivo, pero no podrá volver a abrir ese mismo archivo (o, más precisamente, cualquier archivo en la misma ubicación con el mismo nombre, incluso si tiene contenido diferente) hasta que elimine el paquete de la tienda de paquetes.

En el contexto del código de la pregunta, inserte lo siguiente después de la primera previewWindow.ShowDialog(); antes de 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); 

Así que el segmento de código fijo se presenta en la pregunta se convierte en:

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í, sé que no abrió la XpsDocument con un paquete - .NET lo hizo "para" yo detrás de la escenas y se olvida de limpiar después de sí mismo.

+0

Este me llamó, tengo un visor que descarga un documento, una vez que estaba configurando el documento, fallaría incluso después de aplicar estos cambios.Cuando estaba cargando el documento, estaba desechando el documento original, lo que haría que la versión fallara cuando fui a volver a cargar el documento. –

4

No estoy seguro de qué versión de .Net se preguntó originalmente con respecto a, o si esto podría haber cambiado entre 3.x y 4.x, pero de alguna investigación en contra de .Net 4.0 parece que la solución podría ser bastante más simple que esto.

XpsDocument implementar IDisposable, lo que indica que tiene que ser Dispose() 'd after use. La desventaja es que IDisposable.Dispose() se implementa de tal manera que está oculto, por lo que no puede llamarlo directamente. Necesitas llamar a Close() en su lugar. Usando dotPeek para analizar XpsDocument.Dispose():

  • XpsDocument.Close() llama a XpsDocument.Dispose()
  • XpsDocument.Dispose() llama (XpsManager.Close)
  • XpsManager.Close() llamadas XpsManager.RemovePackageReference()
  • XpsManager.RemovePackageReference() llama PackageStore.RemovePackage() y Package.Close()

Así que a menos que me falta algo, sólo Cerrar() ing la XpsDocument (que se' se supone que d o de todos modos) debería lograr el mismo resultado sin tener que profundizar en las cosas internas de administración de paquetes que XpsDocument debería manejar.

+0

¡Podría decirse que este es el enfoque más simple! –

Cuestiones relacionadas