في WinForms، لماذا لا يمكنك تحديث عناصر تحكم واجهة المستخدم من سلاسل رسائل أخرى؟

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

  •  08-06-2019
  •  | 
  •  

سؤال

أنا متأكد من أن هناك سببًا جيدًا (أو على الأقل لائقًا) لذلك.ما هذا؟

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

المحلول

لأنه من الممكن أن ينتهي بك الأمر بسهولة إلى طريق مسدود (من بين مشكلات أخرى).

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

في اللغات الأخرى مثل C++، أنت حر في محاولة القيام بذلك (بدون طرح استثناء كما هو الحال في WinForms)، ولكن التطبيق الخاص بك قد يتجمد ويتوقف عن الاستجابة في حالة حدوث حالة توقف تام.

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

myControl.BeginInvoke(myControl.UpdateFunction);

وهذا يعادل إجراء PostMessage C++/MFC من مؤشر ترابط عامل

نصائح أخرى

أعتقد أن هذا سؤال رائع - وأعتقد أن هناك حاجة إلى إجابة أفضل.

من المؤكد أن السبب الوحيد هو أن هناك شيئًا ما في إطار في مكان ما لا يمتلك مؤشر ترابط للغاية.

هذا "الشيء" هو تقريبًا كل عضو مثيل في كل عنصر تحكم فردي في System.Windows.Forms.

وثائق MSDN للعديد من عناصر التحكم في System.Windows.Forms، إن لم يكن جميعها، على سبيل المثال "أي أعضاء ثابتين عموميين (مشتركين في Visual Basic) من هذا النوع يعتبرون آمنين لمؤشر الترابط.لا يُضمن أن يكون أي عضو مثيل آمنًا لسلسلة المحادثات."

وهذا يعني أن أعضاء المثيل مثل TextBox.Text {get; set;} غير صحيح إعادة الدخول.

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

[يحرر]

على الرغم من أن هذا السؤال يسأل فقط "لماذا" فإليكم رابط لمقالة تشرح "كيف":

كيف:إجراء مكالمات آمنة لمؤشر الترابط إلى عناصر تحكم نماذج Windows على MSDN

http://msdn.microsoft.com/en-us/library/ms171728.aspx

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


السبب الحقيقي له علاقة أكبر بظروف السباق ويعود إلى زمن Win32 القديم.لا أستطيع شرح التفاصيل هنا، الكلمات الرئيسية هي مضخات الرسائل وأحداث WM_PAINT والاختلافات الدقيقة بين "SEND" و"POST".


يمكن العثور على مزيد من المعلومات هنا هنا و هنا.

بالعودة إلى الإصدار 1.0/1.1، لم يتم طرح أي استثناء أثناء تصحيح الأخطاء، وما حصلت عليه بدلاً من ذلك هو سيناريو تعليق وقت التشغيل المتقطع.لطيف - جيد!:) لذلك مع 2.0 جعلوا هذا السيناريو يرمون استثناء وبحق في ذلك.

من المحتمل أن يكون السبب الفعلي لذلك (كما ذكر آدم هايلي) نوعًا ما من مشكلة التزامن/القفل.لاحظ أن واجهة برمجة تطبيقات .NET العادية (مثل TextBox.Text = "Hello";) تلتف حول أوامر الإرسال (التي تتطلب إجراءً فوريًا) والتي يمكن أن تؤدي إلى حدوث مشكلات إذا تم تنفيذها على مؤشر ترابط منفصل عن الذي يقوم بإجراء التحديث.استخدام Invoc/BeginInvoc يستخدم POST بدلاً من ذلك والذي يضع الإجراء في قائمة الانتظار.

مزيد من المعلومات حول الإرسال والنشر هنا.

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

يحرر:

بلغات أخرى مثل C ++ ، فأنت حر في محاولة القيام بذلك (دون أن يتم إلقاء استثناء كما هو الحال في Winforms) ، لكنك ستنتهي في النهاية إلى تعلم الطريق الصعبة!

آه، نعم...لقد قمت بالتبديل بين C/C++ وC#، وبالتالي كنت أكثر عمومية مما كان ينبغي لي، آسف...إنه على حق، أنت يستطيع قم بذلك في C/C++، لكنه سيعود إليك!

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

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

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

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