2015-03-09 10 views
8

कहा जाता है मैं सी # में घटनाओं की सदस्यता लेने के लिए WeakEventManager<TEventSource, TEventArgs> कक्षा का उपयोग कर रहा हूं। इवेंट सदस्यता ठीक काम करती है, हालांकि से WeakEventManager<TEventSource, TEventArgs>.RemoveHandler पर कॉल करना हमेशा हैंडलर को नहीं हटाता है - जब ईवेंट आग लगने पर हैंडलर अभी भी निष्पादित होता है तो अधिकांश (लेकिन सभी नहीं)।WeakEventManager RemoveHandler हमेशा काम नहीं करता है जब एसिंक्रोनस

यह निम्नलिखित उदाहरण में दिखाया गया है।

public class EventSource 
{ 
    public event EventHandler Fired = delegate { }; 

    public void FireEvent() 
    { 
     Fired(this, EventArgs.Empty); 
    } 
} 

class Program 
{ 
    private static bool added, removed, handled; 

    static void Main(string[] args) 
    { 
     for (int i = 1; i <= 100; i++) 
     { 
      added = removed = handled = false; 

      var source = new EventSource(); 

      AddHandlerAsync(source).Wait(); 

      RemoveHandlerAsync(source).Wait(); 

      source.FireEvent(); 

      if (removed && handled) Console.WriteLine("Event handled after removal!"); 
      else     Console.WriteLine("----------------------------"); 
     } 

     Console.ReadKey(); 
    } 

    private async static Task AddHandlerAsync(EventSource source) 
    { 
     await Task.Run(() => 
     { 
      System.Windows.WeakEventManager<EventSource, EventArgs>.AddHandler(source, "Fired", HandleEvent); 
      added = true; 
     }); 
    } 

    private async static Task RemoveHandlerAsync(EventSource source) 
    { 
     await Task.Run(() => 
     { 
      System.Windows.WeakEventManager<EventSource, EventArgs>.RemoveHandler(source, "Fired", HandleEvent); 
      removed = true; 
     }); 
    } 

    private static void HandleEvent(object sender, EventArgs e) 
    { 
     handled = true; 
    } 
} 

हैंडलर हर समय हटा दिया जाता है, हालांकि ज्यादातर मामलों में ईवेंट अभी भी संभाला जाता है।

क्या मैं इन विधियों को किस तरह से बुला रहा हूं? क्या इन तरीकों को असीमित रूप से बुलाया जा रहा है? क्या कोई वैकल्पिक दृष्टिकोण है जो काम करेगा?

अग्रिम में आपकी सहायता के लिए बहुत धन्यवाद।

उत्तर

6

यह क्योंकि WeakEventManager एक वर्तमान WeakEventTable जो वर्तमान धागा (source) के लिए प्रारंभ में जमा हो जाती है:

[ThreadStatic] 
private static WeakEventTable _currentTable; // one table per thread 

और तुम थ्रेड पूल कार्य sheduler जो डिफ़ॉल्ट sheduler है का उपयोग करें। यह कभी-कभी एक ही धागे पर AddHandler और RemoveHandler पर कॉल करता है। लेकिन कभी-कभी यह RemoveHandler को एक अलग थ्रेड पर आमंत्रित करता है और आपके पास अनुरोध किए बिना EventSource है।

नोट: एक प्रकार DispatcherObject से विरासत तो इस प्रकार की घटनाओं की धागा है जिसमें वे बनाई गई हैं पर निर्भर करता है। यदि DispatcherObject सिंगलटन है तो यह प्रति थ्रेड एक बनाया गया है।

तो यदि आप DispatcherObject देखते हैं तो इसके तरीकों को केवल उस थ्रेड से कॉल करें जिसमें इसे बनाया गया था। अन्यथा, आपको समस्याएं होंगी।

+0

धन्यवाद, यह बताता है कि मैं यह व्यवहार क्यों देख रहा हूं। मैं जिस तरह से कॉल कर रहा हूं उसे जोड़ूं/निकालें हैंडलर को कैसे बदलूं ताकि हैंडलर को उसी धागे पर हटा दिया जा सके? – mickeyt

+0

'AddHandler' और' RemoveHandler' विधियों 'का आह्वान करने के लिए 'Application.Current.Dispatcher' का उपयोग करें। –

+0

इस उदाहरण में कोई 'अनुप्रयोग। वर्तमान' नहीं है। हालांकि 'DispatcherObject' के बारे में टिप के लिए धन्यवाद - बहुत उपयोगी! – mickeyt

संबंधित मुद्दे