जब चर का मान बदला जाता है तो घटना को कैसे ट्रिगर किया जाए?


96

मैं वर्तमान में विजुअल स्टूडियो का उपयोग करके C # में एक एप्लिकेशन बना रहा हूं। मैं कुछ कोड बनाना चाहता हूं ताकि जब एक वैरिएबल का मान 1 हो तो कोड का एक निश्चित टुकड़ा बाहर किया जाए। मुझे पता है कि मैं एक बयान का उपयोग कर सकता हूं, लेकिन समस्या यह है कि मूल्य को एक अतुल्यकालिक प्रक्रिया में बदल दिया जाएगा, इसलिए तकनीकी रूप से यदि मूल्य को बदलने से पहले बयान को अनदेखा किया जा सकता है।

क्या एक इवेंट हैंडलर बनाना संभव है ताकि जब वैरिएबल वैल्यू में बदलाव आए तो एक इवेंट शुरू हो जाए? यदि हां, तो मैं यह कैसे कर सकता हूं?

यह पूरी तरह से संभव है कि मुझे गलतफहमी हो सकती है कि एक बयान कैसे काम करता है! कोई भी सहायताकाफी प्रशंसनीय होगी।


1
बस स्पष्ट होने के लिए, एक चर परिवर्तन का निरीक्षण केवल आपके स्वयं के चर के लिए संभव है (या जो पहले से ही IObservable / INotifyPropertyChanged / Event-related) है। यदि आप इसे देखने के लिए डिज़ाइन नहीं किए गए थे, तो आप सिस्टम चर परिवर्तन का निरीक्षण नहीं कर सकते।
कूर

जवाबों:


123

मुझे लगता है जैसे आप एक संपत्ति बनाना चाहते हैं।

public int MyProperty
{
    get { return _myProperty; }
    set
    {
        _myProperty = value;
        if (_myProperty == 1)
        {
            // DO SOMETHING HERE
        }
    }
}

private int _myProperty;

यह आपको किसी भी समय संपत्ति मूल्य में बदलाव के लिए कुछ कोड चलाने की अनुमति देता है। यदि आप चाहते हैं तो आप यहां एक घटना बढ़ा सकते हैं।


68

जब भी किसी फ़ील्ड का मान बदलने जा रहा हो, तो किसी ईवेंट को बढ़ाने के लिए आप प्रॉपर्टी सेटर का उपयोग कर सकते हैं।

आपके पास अपना स्वयं का EventHandler प्रतिनिधि हो सकता है या आप प्रसिद्ध System.EventHandler प्रतिनिधि का उपयोग कर सकते हैं।

आमतौर पर इसके लिए एक पैटर्न होता है:

  1. किसी ईवेंट हैंडलर डेलीगेट के साथ सार्वजनिक कार्यक्रम को परिभाषित करें (जिसमें EventArgs का एक तर्क हो)।
  2. OnXXXXX नामक एक संरक्षित आभासी विधि को परिभाषित करें (उदाहरण के लिए OnMyPropertyValueChanged)। इस विधि में आपको यह जांचना चाहिए कि क्या ईवेंट हैंडलर डेलीगेट अशक्त है और यदि नहीं तो आप इसे कॉल कर सकते हैं (इसका मतलब है कि ईवेंट डेलिगेशन से जुड़े एक या अधिक तरीके हैं)।
  3. जब भी आप ग्राहकों को सूचित करना चाहते हैं कि कुछ बदल गया है, तो इस संरक्षित विधि को कॉल करें।

यहाँ एक उदाहरण है

private int _age;

//#1
public event System.EventHandler AgeChanged;

//#2
protected virtual void OnAgeChanged()
{ 
     if (AgeChanged != null) AgeChanged(this,EventArgs.Empty); 
}

public int Age
{
    get
    {
         return _age;
    }

    set
    {
         //#3
         _age=value;
         OnAgeChanged();
    }
 }

इस दृष्टिकोण का लाभ यह है कि यदि आवश्यक हो तो व्यवहार को बदलने के लिए आप किसी अन्य वर्ग को अपनी कक्षा से विरासत में आने देना चाहते हैं।

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


3
संपूर्ण वेब पर सर्वश्रेष्ठ व्याख्याओं में से एक। मुझे लगता है कि मैं आखिरकार कस्टम इवेंट हैंडलिंग को समझ रहा हूं। इस पोस्ट के लिए धन्यवाद।
अलविदा

43

.NET फ्रेमवर्क वास्तव में एक इंटरफ़ेस प्रदान करता है जिसका उपयोग आप ग्राहकों को सूचित करने के लिए कर सकते हैं जब एक संपत्ति बदल गई है: System.ComponentModel.INotifyPropertyChanged। इस इंटरफ़ेस में एक इवेंट प्रॉपर्टीचेंज है। इसका उपयोग आमतौर पर बाध्यकारी के लिए WPF में किया जाता है, लेकिन मैंने इसे व्यावसायिक परतों में संपत्ति परिवर्तन अधिसूचना के मानकीकरण के रूप में उपयोगी पाया है।

थ्रेड सेफ्टी के संदर्भ में मैं सेटर के नीचे एक ताला लगा दूंगा ताकि आप किसी भी दौड़ की स्थिति में न भागें।

यहाँ कोड में मेरे विचार हैं :):

public class MyClass : INotifyPropertyChanged
{
    private object _lock;

    public int MyProperty
    {
        get
        {
            return _myProperty;
        }
        set
        {
            lock(_lock)
            {
                //The property changed event will get fired whenever
                //the value changes. The subscriber will do work if the value is
                //1. This way you can keep your business logic outside of the setter
                if(value != _myProperty)
                {
                    _myProperty = value;
                    NotifyPropertyChanged("MyProperty");
                }
            }
        }
    }

    private NotifyPropertyChanged(string propertyName)
    {
        //Raise PropertyChanged event
    }
    public event PropertyChangedEventHandler PropertyChanged;
}


public class MySubscriber
{
    private MyClass _myClass;        

    void PropertyChangedInMyClass(object sender, PropertyChangedEventArgs e)
    {
        switch(e.PropertyName)
        {
            case "MyProperty":
                DoWorkOnMyProperty(_myClass.MyProperty);
                break;
        }
    }

    void DoWorkOnMyProperty(int newValue)
    {
        if(newValue == 1)
        {
             //DO WORK HERE
        }
    }
}

आशा है कि यह उपयोगी है :)


6
+1 लॉक को शामिल करने के लिए जो अन्य उत्तर छोड़ता है।
ctacke

1
ऑब्जेक्ट _लॉक का उपयोग क्या है?
वोडेमिनक

2
@LodeVlaeminck यह संपत्ति के मूल्य को बदलने से रोकता है जबकि घटना संसाधित हो रही है।
डेविड सुआरेज़

IMHO, यह एक ताला के लिए एक विषम जगह है। [जब तक ताला का उपयोग कहीं और भी किया जाता है, जो एक अलग स्थिति है।] यदि दो अलग-अलग धागे साझा संपत्ति सेट करने की दौड़ की स्थिति में हैं, तो संपत्ति का "अंतिम" राज्य नियतात्मक नहीं है। इसके बजाय कुछ पैटर्न का उपयोग करें जहां एक धागा संपत्ति का "मालिक" होता है, और केवल वे इसे सेट करते हैं। जो पैटर्न स्थिति पर निर्भर करता है। (यदि वास्तव में धागे के बीच स्वामित्व बदलने की आवश्यकता है, तो एक बैटन / टोकन पास करें।) अगर मुझे यहां लॉक की आवश्यकता का सामना करना पड़ा, तो मैं समग्र डिजाइन की सावधानीपूर्वक जांच करूंगा। OTOH, यहाँ एक ताला हानिरहित है।
टूलमेकरसैट


0

आप सामान्य वर्ग का उपयोग कर सकते हैं:

class Wrapped<T>  {
    private T _value;

    public Action ValueChanged;

    public T Value
    {
        get => _value;

        set
        {
            OnValueChanged();
            _value = value;
        }
    }

    protected virtual void OnValueChanged() => ValueChanged?.Invoke() ;
}

और निम्नलिखित करने में सक्षम होंगे:

var i = new Wrapped<int>();

i.ValueChanged += () => { Console.WriteLine("changed!"); };

i.Value = 10;
i.Value = 10;
i.Value = 10;
i.Value = 10;

Console.ReadKey();

परिणाम:

changed!
changed!
changed!
changed!
changed!
changed!
changed!
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.