كيف يمكنني أن أجعل DocumentViewer الخاص بـ WPF يقوم بتحرير قفل الملف الخاص به على مستند XPS المصدر؟

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

سؤال

بعد عرض ملف XPS في WPF DocumentViewer، وإغلاق مثيل DocumentViewer، يتم قفل ملف XPS ولا يمكنني حذفه.أحتاج إلى تحرير القفل على ملف XPS حتى أتمكن من حذفه، وكتابة ملف آخر بنفس الاسم، وعرض ملف XPS الجديد هذا بشكل اختياري في مثيل DocumentViewer جديد.أحتاج إلى القيام بذلك في نفس مثيل التطبيق - دون الحاجة إلى إغلاق التطبيق (هذا هو سيناريو معاينة الطباعة).

بمعنى آخر ، كيف يمكنني الحصول على الكود التالي لتشغيله دون إلقاء استثناء في "file.delete (tempxpsfile) ؛" إفادة؟

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

يؤدي إغلاق التطبيق إلى تحرير قفل الملف، كما هو مذكور في لا يقوم WPF DocumentViewer بتحرير ملف XPS, ، ولكن هذا ليس خيارا في هذا السيناريو.

هل كانت مفيدة؟

المحلول

وتحتاج إلى إغلاق System.IO.Packaging.Package الذي افتتح XpsDocument المخصصة للمشاهد. وعلاوة على ذلك، إذا كنت تريد أن تكون قادرة على فتح نفس الملف مرة أخرى في غضون الدورة تطبيق نفس، سيكون لديك لإزالة حزمة من PackageStore. إن إغلاق صفقة الافراج عن قفل الملفات ويسمح لك لحذف الملف، لكنك لن ثم تكون قادرة على إعادة فتح هذا الملف نفسه (أو بتعبير أدق، أي ملف في هذا المكان نفسه الذي يحمل الاسم نفسه حتى لو كان لديها محتوى مختلف) حتى يمكنك إزالة حزمة من PackageStore.

في إطار التعليمات البرمجية في هذه المسألة، إدراج التالية بعد أول previewWindow.ShowDialog ()؛ قبل 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);

وهكذا قطعة الرموز الثابتة الواردة في السؤال يصبح:

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

ونعم، وأنا أعلم أنني لم تفتح XpsDocument مع باقة - فعلت. NET أنه "ل" لي وراء الكواليس ونسي لتنظيف بعد نفسها

.

نصائح أخرى

لست متأكدًا من إصدار .Net الذي تم طرح هذا السؤال عنه في الأصل، أو ما إذا كان هذا قد تغير بين 3.x و4.x، ولكن من بعض التحقيقات التي أجريت على .Net 4.0، يبدو أن الحل قد يكون قليلًا جدًا أبسط من هذا.

يقوم XpsDocument بتنفيذ IDisposable، مما يشير إلى أنه يحتاج إلى Dispose()'d بعد الاستخدام.المشكلة هي أن IDisposable.Dispose() تم تنفيذه بحيث يكون مخفيًا بحيث لا يمكنك الاتصال به مباشرةً.تحتاج إلى الاتصال بـ Close() بدلاً من ذلك.استخدام dotPeek لتحليل XpsDocument.Dispose():

  • يستدعي XpsDocument.Close() XpsDocument.Dispose()
  • يستدعي XpsDocument.Dispose() XpsManager.Close()
  • يستدعي XpsManager.Close() XpsManager.RemovePackageReference()
  • يستدعي XpsManager.RemovePackageReference() PackageStore.RemovePackage() وPackage.Close()

لذلك، ما لم أفتقد شيئًا ما، فإن مجرد إغلاق ()XpsDocument (الذي من المفترض أن تفعله على أي حال) يجب أن يحقق نفس النتيجة دون الحاجة إلى البحث في عناصر إدارة الحزم الداخلية التي يجب أن يتعامل معها XpsDocument.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top