2009-09-18 23 views
9

Sau khi hiển thị tệp XPS trong DocumentViewer WPF và đóng cá thể DocumentViewer, tệp XPS bị khóa và tôi không thể xóa nó. Tôi cần phải giải phóng khóa trên tệp XPS để tôi có thể xóa nó, viết một tệp khác có cùng tên và hiển thị tùy chọn tệp XPS mới đó trong một cá thể DocumentViewer mới. Tôi cần phải làm điều này trong cùng một trường hợp ứng dụng - mà không cần phải đóng ứng dụng (đây là một kịch bản Xem trước bản in).Làm cách nào để lấy DocumentViewer của WPF để giải phóng khóa tệp của nó trên Tài liệu XPS nguồn?

Nói cách khác, làm cách nào tôi nhận được mã sau để chạy mà không ném ngoại lệ vào "File.Delete (tempXpsFile);" tuyên bố?

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

Đóng ứng dụng không giải phóng khóa tệp, như đã đề cập trong WPF DocumentViewer doesn't release the XPS file, nhưng đó không phải là tùy chọn trong trường hợp này.

Trả lời

14

Bạn cần đóng System.IO.Packaging.Package mà từ đó XpsDocument được gán cho trình xem được mở. Hơn nữa, nếu bạn muốn có thể mở lại cùng một tệp trong cùng một phiên ứng dụng, bạn sẽ phải loại bỏ Gói khỏi PackageStore. Đóng gói sẽ giải phóng khóa tệp và cho phép bạn xóa tệp, nhưng bạn sẽ không thể mở lại cùng một tệp đó (hoặc chính xác hơn, bất kỳ tệp nào tại cùng một vị trí đó có cùng tên ngay cả khi tệp đó có nội dung khác nhau) cho đến khi bạn xóa Gói khỏi PackageStore.

Trong ngữ cảnh của mã trong câu hỏi, hãy chèn phần sau đây sau bản xem trước đầu tiênWindow.ShowDialog(); trước 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); 

Vì vậy, các đoạn mã cố định thể hiện trong câu hỏi trở thành:

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

Vâng, tôi biết tôi không mở XpsDocument với một gói - NET đã làm nó "cho" tôi đằng sau cảnh và quên để làm sạch sau khi chính nó.

+0

Điều này bắt gặp tôi, tôi có một người xem tải xuống một tài liệu, một khi nó đã được thiết lập tài liệu nó sẽ thất bại ngay cả sau khi áp dụng những thay đổi này.Khi tôi đang tải tài liệu, tôi đã xử lý tài liệu gốc sẽ khiến bản phát hành thất bại khi tôi tải lại tài liệu. –

4

Không chắc chắn phiên bản của .Net câu hỏi này ban đầu được yêu cầu liên quan đến, hoặc liệu điều này có thể đã thay đổi giữa 3.x và 4.x hay không, nhưng từ một số điều tra chống lại .Net 4.0 nó trông giống như giải pháp có thể khá đơn giản hơn thế này.

XpsDocument triển khai IDisposable, cho biết cần phải Vứt bỏ() sau khi sử dụng. Các nếp nhăn là IDisposable.Dispose() được thực hiện như vậy mà nó ẩn nên bạn không thể gọi nó trực tiếp. Bạn cần phải gọi Close() để thay thế. Sử dụng dotPeek để phân tích XpsDocument.Dispose():

  • XpsDocument.Close() gọi XpsDocument.Dispose()
  • XpsDocument.Dispose() gọi XpsManager.Close()
  • XpsManager.Close() cuộc gọi XpsManager.RemovePackageReference()
  • XpsManager.RemovePackageReference() gọi PackageStore.RemovePackage() và Package.Close()

Vì vậy, trừ khi tôi đang thiếu cái gì, chỉ Close() ing các XpsDocument (mà bạn' được cho là d o anyway) nên đạt được kết quả tương tự mà không cần phải đào sâu vào các công cụ quản lý gói nội bộ mà XpsDocument cần xử lý.

+0

Đây được cho là cách tiếp cận đơn giản nhất! –

Các vấn đề liên quan