Como faço para obter DocumentViewer do WPF para liberar seu bloqueio de arquivo da fonte XPS Document?

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

Pergunta

Depois de mostrar um arquivo XPS no WPF DocumentViewer, e fechando a instância DocumentViewer, o arquivo XPS está bloqueado e não pode excluí-lo. Eu preciso para liberar o bloqueio no arquivo XPS para que eu possa excluí-lo, escrever outro com o mesmo nome e, opcionalmente, mostrar que o novo arquivo XPS em uma nova instância DocumentViewer. Eu preciso fazer isso na mesma instância app -. Sem ter que fechar o aplicativo (este é um cenário visualização de impressão)

Em outras palavras, como é que eu recebo o seguinte código para executar sem lançar uma exceção no "File.Delete (tempXpsFile);" declaração?

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

Fechando o aplicativo faz liberar o bloqueio de arquivo, conforme mencionado na WPF DocumentViewer doesn 't libera o arquivo XPS , mas isso não é uma opção neste cenário.

Foi útil?

Solução

Você precisa fechar o System.IO.Packaging.Package partir do qual o XpsDocument designado para o espectador foi aberto. Além disso, se você quer ser capaz de abrir o mesmo arquivo novamente na mesma sessão aplicativo, você terá que remover o pacote do PackageStore. Fechando o pacote irá liberar o bloqueio de arquivo e permitir que você excluir o arquivo, mas você não vai, então, ser capaz de voltar a abrir o mesmo arquivo (ou, mais precisamente, qualquer arquivo no mesmo local com o mesmo nome, mesmo que tenha conteúdo diferente) até retirar o pacote do PackageStore.

No contexto do código em questão, inserir a seguinte depois de o primeiro previewWindow.ShowDialog (); antes do 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);

Assim, o segmento de código fixo apresentado na questão torna-se:

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

Sim, eu sei que eu não abrir o XpsDocument com um Package - NET fez isso "para" me nos bastidores e se esquece de limpar depois de si

.

Outras dicas

Não tenho certeza qual a versão do .Net esta questão foi pedido inicialmente com respeito a, ou se esta poderia ter mudado entre 3.xe 4.x, mas de alguma investigação contra .Net 4.0 parece que a solução pode ser um pouco mais simples do que isso.

XpsDocument implementar IDisposable, indicando que ele precisa ser Dispose () 'd após o uso. A ruga é que IDisposable.Dispose () é implementado de tal forma que é escondido para que você não pode chamá-lo diretamente. Você precisa chamar Close () em vez disso. Usando dotPeek analisar XpsDocument.Dispose ():

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

Assim, a menos que eu estou faltando alguma coisa, apenas Close () ing o XpsDocument (que você deveria fazer de qualquer maneira) deve alcançar o mesmo resultado sem ter que cavar o material de gerenciamento de pacotes interna que XpsDocument deve ser manipulação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top