में Async घटक से आग घटना। मैं .NET 2.0 में एक गैर-दृश्य घटक बना रहा हूं। यह घटक एक असीमित सॉकेट (BeginReceive, EndReceive आदि) का उपयोग करता है। रनटाइम द्वारा बनाए गए वर्कर थ्रेड के संदर्भ में असीमित कॉलबैक को कॉल किया जाता है। घटक उपयोगकर्ता को मल्टीथ्रेडिंग के बारे में चिंता करने की ज़रूरत नहीं है (यह मुख्य लक्ष्य है, जो मैं चाहता हूं)यूआई थ्रेड
घटक उपयोगकर्ता किसी भी धागे में मेरा गैर-दृश्य घटक बना सकता है (UI थ्रेड सरल के लिए केवल एक सामान्य धागा है अनुप्रयोगों। अधिक गंभीर अनुप्रयोग एक मनमानी कार्यकर्ता थ्रेड के भीतर घटक बना सकते हैं)। घटक ट्रिगर घटनाएं जैसे "सत्र कनेक्ट" या "डेटा उपलब्ध"।
समस्या: असिंक कॉलबैक और उसमें उठाई गई घटनाओं के कारण ईवेंट हैंडलर कार्यकर्ता थ्रेड संदर्भ में निष्पादित किया गया है। मैं एक इंटरमीडिएट परत का उपयोग करना चाहता हूं जो को ईवेंट हैंडलर को थ्रेड के संदर्भ में निष्पादित करने के लिए मजबूर करता है जिसने घटक को पहली जगह बनाया था।
उदाहरण कोड (हैंडलिंग आदि अपवाद से छीन लिया ...)
/// <summary>
/// Occurs when the connection is ended
/// </summary>
/// <param name="ar">The IAsyncResult to read the information from</param>
private void EndConnect(IAsyncResult ar)
{
// pass connection status with event
this.Socket.EndConnect(ar);
this.Stream = new NetworkStream(this.Socket);
// -- FIRE CONNECTED EVENT HERE --
// Setup Receive Callback
this.Receive();
}
/// <summary>
/// Occurs when data receive is done; when 0 bytes were received we can assume the connection was closed so we should disconnect
/// </summary>
/// <param name="ar">The IAsyncResult that was used by BeginRead</param>
private void EndReceive(IAsyncResult ar)
{
int nBytes;
nBytes = this.Stream.EndRead(ar);
if (nBytes > 0)
{
// -- FIRE RECEIVED DATA EVENT HERE --
// Setup next Receive Callback
if (this.Connected)
this.Receive();
}
else
{
this.Disconnect();
}
}
Async की प्रकृति के कारण
कुर्सियां मेरी घटक का उपयोग सभी अनुप्रयोगों से अटे पड़े हैं "अगर (this.InvokeRequired) {... "और मैं चाहता हूं कि उपयोगकर्ता ड्रॉप-इन के प्रकार के रूप में मेरे घटक चिंता-मुक्त का उपयोग करने में सक्षम हो।
तो मैं उपयोगकर्ता को InvokeRequired (या, अलग-अलग रखता हूं, मैं उसी धागे में उठाए गए घटनाओं को कैसे लागू करता हूं, जिसने घटना को पहली जगह शुरू की थी) की जांच किए बिना घटनाओं को बढ़ाने के बारे में कैसे जाना होगा?
मैंने AsyncOperation, BackgroundWorkers, सिंक्रनाइज़िंग ऑब्जेक्ट्स, AsyncCallbacks और अन्य सामानों के टन के बारे में सामान पढ़ा है, लेकिन यह सब मेरे सिर स्पिन बनाता है।
मैं यह, निश्चित रूप से अनाड़ी, "समाधान" के साथ आया था, लेकिन यह कुछ स्थितियों में विफल (जब मेरे घटक उदाहरण के लिए एक स्थिर वर्ग के माध्यम से एक WinForms परियोजना से कहा जाता है)
/// <summary>
/// Raises an event, ensuring BeginInvoke is called for controls that require invoke
/// </summary>
/// <param name="eventDelegate"></param>
/// <param name="args"></param>
/// <remarks>http://www.eggheadcafe.com/articles/20060727.asp</remarks>
protected void RaiseEvent(Delegate eventDelegate, object[] args)
{
if (eventDelegate != null)
{
try
{
Control ed = eventDelegate.Target as Control;
if ((ed != null) && (ed.InvokeRequired))
ed.Invoke(eventDelegate, args);
else
eventDelegate.DynamicInvoke(args);
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType());
Console.WriteLine(ex.Message);
//Swallow
}
}
}
किसी भी लगता है मदद की सराहना की जाएगी। अग्रिम में धन्यवाद!
संपादित करें: this thread के अनुसार मेरे सबसे अच्छे शर्त SyncrhonizationContext.Post उपयोग करने के लिए होगा, लेकिन मैं अपने स्थिति के लिए इसे लागू करने के लिए नहीं देख सकता।
वास्तव में नहीं; मेरे घटक का उपयोग करते समय लोगों के लिए जटिल होने का यह तरीका है। सभी कार्य घटक का संदर्भ लेते हैं और कोड का उपयोग करते हैं जैसे: // आईपी, पोर्ट इत्यादि के साथ MyComponent प्रारंभ करें और फिर: MyComponent.SendString ("यह अच्छा है"); MyComponent घटनाओं को बढ़ाता है; चाहे वे जीयूआई या गैर-जीयूआई परियोजना द्वारा संभाले जाएं, इससे कोई फर्क नहीं पड़ता और मैं नहीं चाहता कि उपयोगकर्ता InvokeRequired की जांच के लिए ज़िम्मेदार हो। – ComponentBuilder