दिलचस्प पोस्ट
मैं अपने डीबी में क्लिक निर्देशांक को संचित कर रहा हूं और फिर उन्हें फिर से लोड कर रहा हूं और उन साइट पर दिखा रहा हूं जहां क्लिक हुआ, मैं यह कैसे सुनिश्चित करता हूं कि यह एक ही जगह में लोड हो रहा है? कैसे एक सदस्य समारोह सूचक के माध्यम से कॉल करने के लिए? इस (एक्सटेंशन विधि आधारित) लघुकोड का उपयोग करने के संभावित नुकसान सीएसएस: अस्पष्टता के साथ पृष्ठभूमि छवि सेट? संख्या तालिका बनाने और बनाने का सबसे अच्छा तरीका क्या है? मैं C ++ में सीएसवी फ़ाइलों को पढ़ और पार्स कैसे कर सकता हूं? PostgreSQL क्वेरी लॉग करने के लिए कैसे? मैं डिक्ट को बचाने के लिए अचार कैसे का उपयोग कर सकता हूं? मैं MySQL में एक पंक्ति जनरेटर कैसे बनाऊँ? जावास्क्रिप्ट के साथ एक तत्व का वर्ग बदलें onClick मोबाइल (टच) पर काम नहीं कर रहा है ऑफ़लाइन उपयोग के लिए Google मानचित्र डाउनलोड / कैशिंग करना धागा नियंत्रण कैसे एक x264 सी एपीआई का उपयोग कर H264 में छवियों की श्रृंखला को एक सांकेतिक शब्दों में बदलना है? । htaccess: अमान्य कमांड 'रीवरइटइंजिन', संभवतः गलत वर्तनी या परिभाषित किया गया एक मॉड्यूल जो सर्वर कॉन्फ़िगरेशन में शामिल नहीं है

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

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

वेब के समाधान से एकत्रित समाधान "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); } } }