سؤال

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

الاتصال lock(obj) يعد أمرًا سهلاً بدرجة كافية من خلال سلسلة البحث الخاصة بي، ولكن بعد الاطلاع على الوثائق وإلقاء نظرة سريعة على كود PropertyDescriptorGridEntry في Reflector، يبدو أنني لا أستطيع العثور على مكان مماثل لاستخدام System.Threading.Monitor.Enter()/Exit() استدعاء الكائن المعني على PropertyGrid.كنت أتمنى أن تكون هناك أحداث BeginEdit وEndEdit من شأنها أن تجعل هذا الأمر بسيطًا بما فيه الكفاية، ولكن يبدو أنني لا أستطيع العثور على أي شيء من هذا القبيل.أفضل عدم قفل الكائن بأكمله أثناء عرضه في PropertyGrid لأن ذلك سيؤدي بوضوح إلى حظر سلسلة البحث الخاصة بي حتى يتم تحديد كائن آخر.

أنا جديد بعض الشيء في نموذج الترابط الخاص بـ Windows Forms، لذا آمل أن يكون هناك بعض الإجابات الواضحة التي تجاهلتها للتو.أي مساعدة؟

يحرر: من المحتمل أن يكون استنساخ الكائنات بشكل متزامن قبل تشغيل البحث بشكل غير متزامن غير فعال بدرجة كافية لدرجة أنني قد أقوم بتشغيل البحث نفسه بشكل متزامن - فالهدف من التشغيل بشكل غير متزامن هو بالطبع السماح للمستخدمين بمواصلة العمل أثناء تنفيذ البحث.يحتاج البحث إلى التوسع بشكل جيد، حيث أن مجموعة البيانات التي أتصفحها ستنتهي في نهاية المطاف بأن تكون كبيرة بشكل تعسفي، مما يجعل الاستنساخ المتزامن يبدو وكأنه سيؤدي إلى مشكلة سهولة الاستخدام التي أحاول تجنبها.

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

المحلول

أعتقد أنه سيتعين عليك القيام بالكثير من العمل من أجل هذا.

أولاً، سيتعين عليك إنشاء تطبيق لـ ICustomTypeDescriptor والذي سيبني تنفيذه على أي نوع TypeDescriptor الذي ستحصل عليه عادةً لهذا النوع.

بعد ذلك، في تطبيقات الطرق التي تكشف واصفات الأعضاء الذين تريد قفلهم، يمكنك توفير فئات فرعية مشتقة من تلك الواصفات وتجاوز الطرق المناسبة لالتفاف القفل حولها.

لذلك بالنسبة للخاصية، يمكنك تطبيق GetProperties لإرجاع الفئات الفرعية المحددة الخاصة بك من PropertyDescriptor.ستتجاوز هذه الفئات الفرعية أساليب GetValue وSetValue (وغيرها) وتستخدم قفلًا عند الوصول إلى تلك المتغيرات.

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

نصائح أخرى

وهذا في الواقع لن يكون آمنًا.يمكنك تنظيم أجزاء من كود البحث إلى سلسلة واجهة المستخدم، ولكن هذا سيؤدي إلى إبطاء الأمور، وربما يؤدي إلى هزيمة نقطة الترابط...

ما مدى السرعة التي يجب أن يكون بها البحث؟هل يمكنك العمل ضد استنساخ؟إلخ

هل يمكنك استنساخ البيانات قبل عرضها، وجعل سلسلة البحث الخاصة بك تعمل على الاستنساخ؟إذا كنت تريد أن "يرى" موضوع البحث التغييرات، فيمكنك الرد على الأحداث الموجودة على PropertyGrid وربما جعل خاضع للسيطرة تغييرات على الاستنساخ بطريقة أو بأخرى.(ربما يكون من الأسهل استخدام البيانات "القديمة" فقط.)

أعلم أن استنساخ البيانات يبدو غير فعال إلى حد كبير، ولكن من المؤكد أن الترابط يكون أسهل عندما يعمل كل مؤشر ترابط على بيانات مستقلة تمامًا (أو تتم قراءة جميع سلاسل الرسائل فقط).

قد أكون مخطئًا، لكن يبدو لي أنك قادم من النهاية الخاطئة.

هناك مشكلتان متميزتان تحتاج إلى معالجتهما.

أولاً، التأكد من أنه لا يتم الوصول إلى PropertyGrid إلا من خلال مؤشر ترابط واجهة المستخدم.إذا تم الوصول إلى أي من أساليبه (بما في ذلك خاصية getter/setters) من سلاسل رسائل أخرى، فسوف تعاني من الألم بطرق غامضة.الاستثناءات هي InvokeRequired() و Invoke, ، بالطبع.

ثانيًا، التأكد من إمكانية تشغيل سلسلة البحث بشكل صحيح.

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

المشكلة الثانية أسهل - طالما أن سلسلة البحث الخاصة بك تقرأ فقط من الكائنات الأساسية، فيجب أن يعمل كل شيء بشكل جيد.نعم، قد يرى مؤشر ترابط البحث الخاص بك عن غير قصد بعض البيانات المحدثة جزئيًا، ولكن هل هذه مشكلة حقًا؟

زوجان من الأفكار النهائية ...

  • لا تقم بتنفيذ بحثك للتكرار من خلال PropertyGrid نفسها؛احصل على قائمة بالكائنات مقدمًا (لا يلزم أن تكون مستنسخة) واعمل على حلها بدلاً من ذلك.

  • هل فكرت في استخدام المعالجة الخاملة لإجراء البحث؟ال Application يطلق الكائن حدثًا في كل مرة ينفد فيها التطبيق الرسائل المطلوب معالجتها - يمكنك ربط هذا وتنفيذ خطوة واحدة من بحثك في كل مرة يتم فيها تشغيل الحدث.نوع من خيوط الرجل الفقير، ولكن مع عدم وجود أي من مشاكل Mutex/Lock/semaphone.لقد استخدمت هذا لتأثير جيد للغاية في الماضي.

تحديث:إذا كنت أتذكر بشكل صحيح، فإن PropertyGrid تحترم IEditableObject واجهة، الدعوة BeginEdit بمجرد البدء في تعديل صف، و EndEdit عند الانتقال إلى صف مختلف.يمكنك الاستفادة من هذا لمنع سلسلة البحث الخاصة بك من رؤية تغييرات غير كاملة.

تحديث 2:بعد المتابعة، اكتشفت ما كنت تعرفه بالفعل - وهو PropertyGrid لا احترام واجهة IEditableObject.

لدي اقتراح آخر - على الرغم من أنه قد يكون عملاً أكثر مما تريد استثماره.

في الوقت الذي تم فيه تقديم مساحة الاسم System.Transactions في .NET 2.0، رأيت مقالًا حول استخدام المعاملة المحيطة لتوفير عزل مؤشر الترابط للكائنات.الفكرة هي أن خصائص كائنك تحتوي على مساحة تخزين مزدوجة.أولاً، لديك القيمة الملتزمة، المرئية لجميع سلاسل الرسائل، ولديك متغير مؤشر ترابط محلي يستخدم لتخزين القيم غير الملتزم بها على أساس كل مؤشر ترابط.عندما يتم تعديل خاصية ما، يتم إدراج الكائن في أي معاملة محيطة عن طريق تخزين القيمة الجديدة في مؤشر الترابط المحلي.عند تنفيذ المعاملة أو التراجع عنها، يتم تخزين قيمة مؤشر الترابط أو تجاهلها.

لسوء الحظ، لا يمكنني العثور على المقالة الأصلية، على الرغم من أنه يبدو أن CSLA توفر هذا الدعم.أتمنى أن يساعدك هذا.

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