2009-07-19 18 views
5

समस्या: मेरे पास एक दस्तावेज़ श्रेणी है जिसमें ऑब्जेक्ट्स की एक सूची है। ये ऑब्जेक्ट SolutionExpired, DisplayExpired इत्यादि जैसी घटनाओं को बढ़ाते हैं। दस्तावेज़ को इसका जवाब देने की आवश्यकता है।एक ईवेंट में सभी ईवेंट हैंडलर को हटाकर

दस्तावेज़ कभी-कभी ऑब्जेक्ट्स का आदान-प्रदान कर सकते हैं, लेकिन एक ऑब्जेक्ट कभी भी एक से अधिक दस्तावेज़ों का 'भाग' नहीं होना चाहिए।

मेरी दस्तावेज़ श्रेणी में विधियों का एक समूह है जो ईवेंट हैंडलर के रूप में कार्य करता है। जब भी कोई ऑब्जेक्ट दस्तावेज़ में प्रवेश करता है, तो मैं ईवेंट सेट अप करने के लिए AddHandler का उपयोग करता हूं, और जब भी दस्तावेज़ से ऑब्जेक्ट हटा दिया जाता है तो मैं क्षति को पूर्ववत करने के लिए RemoveHandler का उपयोग करता हूं। हालांकि, ऐसे मामले हैं जहां यह सुनिश्चित करना मुश्किल है कि सभी कदम ठीक से उठाए गए हैं और मैं इस प्रकार दुष्ट घटना हैंडलर के साथ समाप्त हो सकता हूं।

लंबी कहानी छोटी; मैं उन सभी हैंडलर को कैसे हटा सकता हूं जो एक विशिष्ट विधि को इंगित कर रहे हैं? ध्यान दें, मेरे पास संभावित घटना स्रोतों की एक सूची नहीं है, इन्हें कहीं भी संग्रहीत किया जा सकता है।

कुछ की तरह:

RemoveHandler *.SolutionExpired, AddressOf DefObj_SolutionExpired 
+0

संभावित डुप्लिकेट [सभी ईवेंट हैंडलर को नियंत्रण से कैसे हटाएं] (http://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control) – ChrisF

+0

संभव डुप्लिकेट [सभी ईवेंट हैंडलर को नियंत्रण से कैसे हटाएं] (https://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control) –

उत्तर

5

आप Delegate.RemoveAll() का उपयोग कर सकते हैं। (भाग में आपकी रुचि है button2_Click में है)

public void Form_Load(object sender, EventArgs e) 
{ 
    button1.Click += new EventHandler(button1_Click); 
    button1.Click += new EventHandler(button1_Click); 
    button2.Click += new EventHandler(button2_Click); 
    TestEvent += new EventHandler(Form_TestEvent); 
} 
event EventHandler TestEvent; 
void OnTestEvent(EventArgs e) 
{ 
    if (TestEvent != null) 
     TestEvent(this, e); 
} 
void Form_TestEvent(object sender, EventArgs e) 
{ 
    MessageBox.Show("TestEvent fired"); 
} 
void button2_Click(object sender, EventArgs e) 
{ 
    Delegate d = TestEvent as Delegate; 
    TestEvent = Delegate.RemoveAll(d, d) as EventHandler; 
} 
void button1_Click(object sender, EventArgs e) 
{ 
    OnTestEvent(EventArgs.Empty); 
} 

आप को ध्यान देना चाहिए कि यह प्रतिनिधियों आप इसे करने के लिए पारित की सामग्री को बदल नहीं है, यह एक परिवर्तित प्रतिनिधि देता है। नतीजतन, आप फॉर्म से किसी फॉर्म पर गिराए गए बटन पर ईवेंट को बदलने में सक्षम नहीं होंगे, क्योंकि button1.Click केवल += या -= पर उपयोग किया जा सकता है, = पर नहीं। यह संकलन नहीं:

button1.Click = Delegate.RemoveAll(d, d) as EventHandler; 

इसके अलावा, यह सुनिश्चित करें कि आप जहां भी इस लागू कर रहे हैं आप दौड़ की स्थिति की क्षमता के लिए बाहर देख रहे हैं हो सकता है।यदि आप किसी अन्य थ्रेड द्वारा बुलाए जाने वाले किसी ईवेंट से हैंडलर को हटा रहे हैं तो आप कुछ वाकई अजीब व्यवहार के साथ समाप्त हो सकते हैं!

+4

मुझे यह नहीं पता कि यह कैसे स्वीकार्य है, ओपी की स्थिति को हैंडलर को किसी ऐसे ईवेंट से हटाने की आवश्यकता है जहां उसके पास निजी स्तर की पहुंच न हो। मेरा कुछ छूट रहा है! –

+1

यह भी सी # है जबकि ओपी का सवाल vb.net के बारे में था। जबकि दोनों के पास बहुत अधिक ओवरलैप है, इवेंट सिंटैक्स वह है जहां वे काफी भिन्न होते हैं – user81993

1
public class TheAnswer 
{ 
    public event EventHandler MyEvent = delegate { }; 

    public void RemoveFromMyEvent(string methodName) 
    { 
     foreach (var handler in MyEvent.GetInvocationList()) 
     { 
      if (handler.Method.Name == methodName) 
      { 
       MyEvent -= (EventHandler)handler; 
      } 
     } 
    } 
} 

संपादित करें 2: मेरी गलतफहमी के लिए क्षमा याचना - मुझे लगता है कि आप अपने मूल पोस्ट में घटना स्रोतों के लिए उपयोग नहीं होने के बारे में बहुत स्पष्ट थे।

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

मुझे लगता है कि ज्यादातर मामलों में प्रदर्शन और मेमोरी प्रभाव नगण्य होंगे: जब तक कि आप हजारों छोटी वस्तुओं से निपट नहीं रहे हैं और अक्सर दस्तावेज़ों के बीच उनका आदान-प्रदान करते हैं, प्रत्येक कुंजी/मूल्य जोड़ी और प्रदर्शन हिट की स्मृति ओवरहेड प्रत्येक लुकअप ऑपरेशन के लिए काफी छोटा होना चाहिए।

एक विकल्प के रूप में: यदि आप (दस्तावेज़ ईवेंट हैंडलरों में) का पता लगा सकते हैं कि ईवेंट का प्रेषक दस्तावेज़ के लिए अब प्रासंगिक नहीं है, तो आप वहां ईवेंट को अलग कर सकते हैं।

ये ऐसे विचारों की तरह प्रतीत होते हैं जो आप पहले ही अस्वीकार कर चुके हैं - लेकिन शायद नहीं!

+0

बेन, पोस्टिंग के लिए धन्यवाद इस। मुझे डर है कि यह मुझे बहुत समझ नहीं रहा है (या उस मामले के लिए वीबी कंपाइलर)। क्या आप मूल सी # पोस्ट कर सकते हैं? –

+1

मुझे पता था कि मुझे मूल सी # संस्करण ऊपर छोड़ देना चाहिए था। :-) –

+0

धन्यवाद बेन, मैं देखता हूं कि आप यहां क्या कर रहे हैं, लेकिन अगर मैं गलत नहीं हूं तो यह कार्य मानता है कि मेरे पास घटना का एक संदर्भ है जो घटनाओं को उठा रहा है। ये ऑब्जेक्ट्स क्षितिज पर गायब हो जाने के बाद से कहीं और हो सकती हैं। मुझे लगता है कि यह संभवतः ऐसा करना संभव नहीं है क्योंकि हैंडलर प्रतिनिधियों को कक्षा में परिभाषित किया गया है जो घटनाओं को उठाता है, न कि हैंडलर को परिभाषित करने वाली कक्षा। –

1

Delegate.RemoveAll का उपयोग करें (यदि प्रतिनिधि उदाहरण निजी है तो प्रतिबिंब का उपयोग कर सकते हैं)।

+0

क्योंकि मुझे इसके लिए स्रोत का उदाहरण होना चाहिए। मुझे लगता है ... अब मुझे ऑब्जेक्ट बढ़ाने वाली घटना, केवल हैंडलर तक पहुंच नहीं है। –

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