2013-02-11 17 views
7

के अंदर अज्ञात ईवेंट हैंडलर से सदस्यता छोड़ना मेरे पास INotifyPropertyChanged लागू करने वाली किसी ऑब्जेक्ट की PropertyChanged ईवेंट की सदस्यता लेने के लिए एक एक्सटेंशन विधि है।एक स्थिर विधि (एक्सटेंशन विधि)

मुझे लगता है कि घटना सिर्फ एक बार आग लगती है। और नहीं।

यह मेरी विधि है।

public static void OnPropertyChanged<T>(this INotifyPropertyChanged target, string propertyName, Action action) 
{ 
    if (target == null) 
    { 
     return; 
    } 

    PropertyChangedEventHandler handler = (obj, e) => 
    { 

     if (propertyName == e.PropertyName) 
     { 
      action(); 
     } 

    }; 


    target.PropertyChanged -= handler; 
    target.PropertyChanged += handler; 

} 

लेकिन यह काम नहीं करता है। मैं ईवेंट हैंडलर को हटा नहीं सकता हूं इसलिए जब भी मैं इस विधि को कॉल करता हूं तो घटना आग लगती है।

मैंने एक अलग दृष्टिकोण की कोशिश की है। बेनामी विधियों का उपयोग करने के बजाय, कुछ और पारंपरिक, इस तरह:

public static void OnPropertyChanged<T>(this INotifyPropertyChanged target, string propertyName, Action action) 
{ 
    if (target == null) 
    { 
     return; 
    } 

    target.PropertyChanged -= target_PropertyChanged; 
    target.PropertyChanged += target_PropertyChanged; 

} 

static void target_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     //do stuff here 
    } 

और यह ठीक काम करता है। घटना सिर्फ एक बार आग लगती है, लेकिन मुझे एक्शन पैरामीटर की भी आवश्यकता है। मैं इस दृष्टिकोण के साथ इसका उपयोग नहीं कर सकता।

इस मुद्दे को हल करने के लिए कोई कामकाज या अलग अपमान? क्या स्थिर तरीकों के अंदर अज्ञात तरीकों के साथ कुछ अजीब है?

अग्रिम धन्यवाद।

उत्तर

3

यह ईवेंट हैंडलर के रूप में अनाम विधियों का उपयोग करने की एक सीमा है। उन्हें हटाया नहीं जा सकता क्योंकि आप एक सामान्य विधि (जो तकनीकी रूप से एक प्रतिनिधि उदाहरण स्वचालित रूप से एक विधि समूह रूपांतरण के माध्यम से बनाते हैं) क्योंकि अनाम विधियों को एक कंपाइलर से उत्पन्न कंटेनर क्लास में संकलित किया जाता है और कक्षा का एक नया उदाहरण हर बार बनाया जाता है।

एक्शन पैरामीटर को संरक्षित करने के लिए आप एक कंटेनर क्लास बना सकते हैं जिसमें आपके ईवेंट हैंडलर के लिए प्रतिनिधि होगा। कक्षा को अन्य कक्षा के अंदर निजी घोषित किया जा सकता है - या आंतरिक "आंतरिक" हो सकता है, शायद "हेल्पर्स" नामस्थान में। यह इस तरह कुछ दिखाई देगा:

class DelegateContainer 
{ 
    public DelegateContainer(Action theAction, string propName) 
    { 
     TheAction = theAction; 
     PopertyName = propName; 
    } 

    public Action TheAction { get; private set; } 
    public string PropertyName { get; private set; } 

    public void PropertyChangedHandler(object sender, PropertyChangedEventArgs e) 
    { 
     if(PropertyName == e.PropertyName) 
      TheAction(); 
    } 
} 

फिर, अपनी कक्षा में कंटेनर के संदर्भ को बनाएं और संग्रहित करें। आप एक स्थिर सदस्य currentContainer बना सकता है और उसके बाद इस तरह हैंडलर सेट:

private static DelegateContainer currentContainer; 

public static void OnPropertyChanged<T>(this INotifyPropertyChanged target, string propertyName, Action action) 
{ 
    if (target == null) 
    { 
     return; 
    } 

    if(currentContainer != null)   
     target.PropertyChanged -= currentContainer.PropertyChangedHandler; 

    currentContainer = new DelegateContainer(action, propertyName); 
    target.PropertyChanged += currentContainer.PropertyChangedHandler; 
} 
+0

+1, लेकिन मुझे लगता है कि यह अनावश्यक रूप से जटिल है: एक 'शब्दकोश <स्ट्रिंग, PropertyChangedEventHandler> 'प्रति संपत्ति नाम के एक प्रतिनिधि को पकड़ सकता है। (हाँ, यह एक अलग तरह का कंटेनर वर्ग है।) – hvd

+0

हाँ, मैं बस एक सामान्य समाधान प्रस्तुत करना चाहता था। जो मैं स्पष्ट रूप से व्यक्त करने की कोशिश कर रहा था वह यह है कि बंद होने के साथ अज्ञात विधियां दृश्यों के पीछे एक कंटेनर क्लास उत्पन्न करती हैं जिसमें कैप्चर किए गए चर के संदर्भ शामिल हैं। तो अनिवार्य रूप से यह वही व्यवहार है लेकिन आप स्पष्ट कर रहे होंगे .. –

+0

बहुत बहुत धन्यवाद। यह काम करता हैं!!! 'PropertyChangedEventHandler' बस एक बार आग लगती है। – Nadya

0

तकनीकी तौर पर, यह एक ही गुमनाम विधि आपकी सदस्यता समाप्त करने की कोशिश कर रहे है। हर बार आपके OnPropertyChanged नामक .NET उस विधि का नया उदाहरण बनाता है। यही कारण है कि सदस्यता रद्द नहीं होगी।

+0

यह जरूरी नहीं कि तकनीकी रूप से एक अलग विधि है। यदि किसी भी कारण से 'संपत्ति नाम' के अलग-अलग 'स्ट्रिंग' उदाहरणों का उपयोग किया जाता है, तो यह * एक अलग विधि होनी चाहिए। – hvd

+0

@ एचवीडी अच्छा बिंदु – Anri

3

यदि आप से ईवेंट ईवेंट हैंडलर के भीतर सदस्यता छोड़ते हैं तो आप काम करने के लिए अपना पहला उदाहरण प्राप्त कर सकते हैं।

public static void OnPropertyChanged<T>(this INotifyPropertyChanged target, string propertyName, Action action) 
{ 
    if (target == null) 
    { 
     return; 
    } 

    // Declare the handler first, in order to create 
    // a concrete reference that you can use from within 
    // the delegate 
    PropertyChangedEventHandler handler = null; 
    handler = (obj, e) => 
    { 
     if (propertyName == e.PropertyName) 
     { 
      obj.PropertyChanged -= handler; //un-register yourself 
      action(); 
     } 

    }; 
    target.PropertyChanged += handler; 
} 

ऊपर कोड "एक और किया" ईवेंट हैंडलर के रूप में कार्य करता है। आप इनकी असीमित संख्या पंजीकृत कर सकते हैं, और प्रत्येक को केवल पंजीकरण रद्द करने से पहले ही निष्पादित किया जाएगा।

ध्यान रखें कि इन हैंडलरों में से एक को कई बार निष्पादित करना संभव है, यदि आप कम उत्तराधिकार में कई धागे में ईवेंट बढ़ाते हैं। इसे रोकने के लिए, आपको "ऑब्जेक्ट लॉक" करने के लिए एक स्थिर Dictionary(T,T) मैपिंग ऑब्जेक्ट इंस्टेंस बनाने की आवश्यकता हो सकती है और यह सुनिश्चित करने के लिए कुछ संभाल कोड जोड़ना चाहिए कि एक हैंडलर केवल एक बार निष्पादित हो। वर्तमान में लिखे गए अनुसार, उन कार्यान्वयन विनिर्देश आपके प्रश्न के दायरे से बाहर थोड़ा प्रतीत होते हैं।एक कंटेनर वर्ग के विचार के लिए

+0

यह अलग व्यवहार है। यह केवल इसे एक बार निकाल दिया जा रहा है, जबकि ओपी का कोड यह सुनिश्चित करने का प्रयास कर रहा था कि केवल एक ही हैंडलर है (लेकिन इसे कई बार निकाल दिया जा सकता है)। – Servy

+1

ओह, और ध्यान दें कि यदि इस घटना को कई समय से कई धागे से निकाल दिया जाता है तो यह कई बार चलाने के लिए संभव है। – Servy

+0

सभी अच्छे अंक। ऑब्जेक्ट्स का एक स्थिर शब्दकोश-> किसी ऑब्जेक्ट के प्रत्येक इंस्टेंस को एक ईवेंट हैंडलर तक सीमित करने के लिए हैंडलर की आवश्यकता हो सकती है। – BTownTKD

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