दिलचस्प पोस्ट
जावास्क्रिप्ट में स्कोप चेन कैसे बताओ कि क्या UIViewController का दृश्य दृश्यमान है एसटीडी :: एमएमपीपी का व्यवहार ऑब्जेक्ट के लिए अनिर्धारित क्यों नहीं होगा, जो ट्रिविली को कॉपी करने योग्य नहीं हैं? IQueryable, सूची, IEnumerator के बीच अंतर? टाइमर और गेम लूप का उपयोग करना एंड्रॉइड साझाप्रेचरेंस सुरक्षा LibGDX (जावा) में समन्वय प्रणाली को बदलना "रिक्त या शून्य मान" की जांच करने का सर्वोत्तम तरीका स्रोत कोड से res / values ​​/ dimension.xml से लोड आयाम मूल्य सीएसएस में पूर्णस्क्रीन संवेदनशील पृष्ठभूमि छवि CSS में एक div के "BOTTOM" में एक लेबल को कैसे संरेखित करें? दो जीआईटी शाखाओं के सामान्य पूर्वज खोजें कक्षा के साथ प्रथम तत्व के लिए सीएसएस चयनकर्ता जावा-थ्रेड डंप पाने के लिए मार -3 करें केवल प्रत्येक कारक स्तर के लिए न्यूनतम मान रखें

WinForms या WPF के लिए UI को वापस इवेंट भेजने के लिए सिंक्रनाइज़ेशन कॉन्टैक्स का उपयोग करना

मैं अपने डीएलएल से वापस UI धागे में मार्शल इवेंट्स को एक सिंक्रनाइज़ेशन कॉन्टैक्स का उपयोग कर रहा हूं जो बहु-थ्रेडेड पृष्ठभूमि कार्यों के बहुत सारे करता है।

मुझे पता है कि सिंगलटन पैटर्न पसंदीदा नहीं है, लेकिन जब आप फू के अभिभावक ऑब्जेक्ट बनाते हैं तो मैं इसका उपयोग यूआई के सिंक्रनाइज़ेशन कंटेंटेक्स्ट के एक संदर्भ को स्टोर करने के लिए कर रहा हूं।

public class Foo { public event EventHandler FooDoDoneEvent; public void DoFoo() { //stuff OnFooDoDone(); } private void OnFooDoDone() { if (FooDoDoneEvent != null) { if (TheUISync.Instance.UISync != SynchronizationContext.Current) { TheUISync.Instance.UISync.Post(delegate { OnFooDoDone(); }, null); } else { FooDoDoneEvent(this, new EventArgs()); } } } } 

यह WPF में बिल्कुल भी काम नहीं करता था, TheUISync इंस्टेंस UI सिंक (जो मुख्य विंडो से फ़ीड है) वर्तमान सिंक्रनाइज़ेशन कॉन्टैक्स। खिड़कियों के रूप में जब मैं एक ही काम करता हूं वे एक आह्वान के बाद मैच करेंगे और हम सही धागा पर वापस आएंगे।

मेरा फिक्स, जो मुझे नफरत है, दिखता है

 public class Foo { public event EventHandler FooDoDoneEvent; public void DoFoo() { //stuff OnFooDoDone(false); } private void OnFooDoDone(bool invoked) { if (FooDoDoneEvent != null) { if ((TheUISync.Instance.UISync != SynchronizationContext.Current) && (!invoked)) { TheUISync.Instance.UISync.Post(delegate { OnFooDoDone(true); }, null); } else { FooDoDoneEvent(this, new EventArgs()); } } } } 

इसलिए मुझे उम्मीद है कि इस नमूना का पालन करने के लिए पर्याप्त समझदारी होती है।

Solutions Collecting From Web of "WinForms या WPF के लिए UI को वापस इवेंट भेजने के लिए सिंक्रनाइज़ेशन कॉन्टैक्स का उपयोग करना"

तत्काल समस्या

आपकी तत्काल समस्या यह है कि SynchronizationContext.Current स्वचालित रूप से WPF के लिए सेट नहीं है इसे सेट करने के लिए आपको अपने यूयूआईएसआईएनसी कोड में ऐसा कुछ करने की आवश्यकता होगी जब डब्लूपीएफ के तहत चलते रहें:

 var context = new DispatcherSynchronizationContext( Application.Current.Dispatcher); SynchronizationContext.SetSynchronizationContext(context); UISync = context; 

एक गहरी समस्या

SynchronizationContext COM + समर्थन के साथ बंधा हुआ है और इसे थ्रेड्स को पार करने के लिए डिज़ाइन किया गया है। WPF में आपके पास एक डिस्पैचर नहीं हो सकता है जो एकाधिक थ्रेड्स फैलाता है, इसलिए एक SynchronizationContext वास्तव में थ्रेड्स को पार नहीं कर सकता है। कई ऐसे परिदृश्य हैं जिनमें एक SynchronizationContext एक नया थ्रेड पर स्विच कर सकता है – विशेषकर कुछ भी जो ExecutionContext.Run() कॉल करता है। इसलिए यदि आप WinForms और WPF दोनों क्लाइंटों को ईवेंट प्रदान करने के लिए SynchronizationContext का प्रयोग कर रहे हैं, तो आपको यह जानना होगा कि कुछ परिदृश्य टूट जाएंगे, उदाहरण के लिए वेब सेवा के लिए एक वेब अनुरोध या उसी प्रक्रिया में होस्ट साइट एक समस्या होगी।

सिंक्रनाइज़ेशन कॉन्टैक्स की जरूरत के आसपास कैसे जाना

इसके कारण मैं सुझाव देता हूं कि WPF के Dispatcher तंत्र को केवल इस उद्देश्य के लिए, यहां तक ​​कि WinForms कोड के साथ भी। आपने एक "TheUISync" सिंगलटन क्लास बनाया है जो सिंक्रनाइज़ेशन को स्टोर करता है, इसलिए स्पष्ट रूप से आपके पास आवेदन के शीर्ष स्तर में रूकने का कोई तरीका है। हालांकि आप ऐसा कर रहे हैं, आप कोड जोड़ सकते हैं जो आपके WinForms एप्लिकेशन में कुछ WPF सामग्री जोड़ता है ताकि Dispatcher काम करेगा, फिर मैं नीचे दिए गए नए Dispatcher तंत्र का उपयोग करें।

सिंक्रनाइज़ेशन कंटबॉक्स के बजाय डिस्पैचर का उपयोग करना

WPF के Dispatcher तंत्र वास्तव में एक अलग SynchronizationContext ऑब्जेक्ट की आवश्यकता को समाप्त कर देता है। जब तक आप कुछ इंटरॉप परिदृश्यों को COM + ऑब्जेक्ट या WinForms UI के साथ साझा करना कोड नहीं करते हैं, तो आपका सबसे अच्छा समाधान SynchronizationContext Dispatcher बजाय Dispatcher का उपयोग करना है।

ऐसा लगता है:

 public class Foo { public event EventHandler FooDoDoneEvent; public void DoFoo() { //stuff OnFooDoDone(); } private void OnFooDoDone() { if(FooDoDoneEvent!=null) Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Normal, new Action(() => { FooDoDoneEvent(this, new EventArgs()); })); } } 

नोट करें कि अब आपको एक TheUISync ऑब्जेक्ट की आवश्यकता नहीं है – WPF आपके लिए उस विस्तार को प्रबंधित करता है

यदि आप पुराने delegate सिंटैक्स के साथ अधिक सहज हैं तो आप इसके बजाय इस तरह से ऐसा कर सकते हैं:

  Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Normal, new Action(delegate { FooDoDoneEvent(this, new EventArgs()); })); 

तय करने के लिए कोई असंबंधित बग

यह भी ध्यान दें कि यहां आपके मूल कोड में एक बग है जिसे दोहराया गया है। समस्या यह है कि FooDoneEvent को OnFooDoDone नामक समय के बीच में अशक्त करने के लिए सेट किया जा सकता है और जब BeginInvoke (या मूल कोड में Post ) प्रतिनिधि को कॉल करता है तय प्रतिनिधि के अंदर एक दूसरा परीक्षण है:

  if(FooDoDoneEvent!=null) Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Normal, new Action(() => { if(FooDoDoneEvent!=null) FooDoDoneEvent(this, new EventArgs()); })); 

वर्तमान के मुकाबले तुलना करने के बजाय, इसे इसके बारे में चिंता क्यों न करें; तो यह केवल "कोई संदर्भ" मामले को संभालने का मामला नहीं है:

 static void RaiseOnUIThread(EventHandler handler, object sender) { if (handler != null) { SynchronizationContext ctx = SynchronizationContext.Current; if (ctx == null) { handler(sender, EventArgs.Empty); } else { ctx.Post(delegate { handler(sender, EventArgs.Empty); }, null); } } }