C# Event Handler

C# Event Handler: GUI Programming, Event Driven Paradigm पर आधारित होता है, जिसका मतलब ये है कि जब Program Run हो रहा होता है, उसके Form पर स्थित विभिन्न Controls के माध्‍यम से Click, Keypress या System Timers जैसे Events द्वारा Program को किसी भी समय Interrupt किया जा सकता है और जब ये Event Trigger होते हैं, तो Program को उन Events को Handle करने के साथ ही Continue भी रखना होता है।

C# Events को Use करने के लिए Program Events को Asynchronously Handle करने का ये तरीका ही सबसे Perfect Event Handling तरीका है। Windows GUI Programming में Events को काफी ज्यादा Use किया जाता है। अन्‍य शब्दों में कहें तो Windows Programming एक प्रकार से Event Driven Programming ही है। जहां हर Event एक Action को Represent करता है, जिसके Response में हमें किसी न किसी Event Handler को Execute करना होता है।

इसलिए .NET Framework में GUI Windows Programming के लिए एक Standard Pattern को Follow किया जाता है और ये Pattern पूरी तरह से EventHandler Delegate Type पर आधारित है, जिसे .NET Framework के System Namespace में कुछ निम्नानुसार तरीके से Declare किया गया है:

public delegate void EventHandler(object sender, EventArgs e);

ये Delegate किसी भी तरह का कोई मान Return नहीं करता। जबकि इस Delegate के अनुसार पहले Parameter के रूप में हमें एक object Type के Reference sender को Specify करना होता है, जो कि उस Publisher Class के Object का Reference Hold करता है, जिसने Event Send किया है, जो कि सामान्‍यत: Publisher Class का Object होता है, क्योंकि वही Event Fire करता है, जिससे Publisher Object की Invocation List में Subscribers द्वारा Registered Callback Event Handlers Invoke होते हैं।

चूंकि पहला Argument एक object Type Parameter है, जो कि .NET Framework की Top Level Base Class है, इसलिए इस object Class का sender नाम का Reference Variable किसी भी प्रकार के Publisher Class के Object के Reference को Hold कर सकता है।

इस Delegate का दूसरा Parameter Application के किसी Appropriate Type की State यानी स्थिति को Hold करता है। ये Parameter EventArgs Type के Object का Reference Hold करता है, जिसे System Namespace में Declare किया गया है।

इस Class को किसी तरह का Data Receive करने के लिए Define नहीं किया गया है, बल्कि इस Parameter का प्रयोग उन Event Handlers द्वारा किया जाता है, जिन्हें Data Pass करने की जरूरत नहीं होती और इन Event Handlers द्वारा सामान्‍यत: इस Parameter को Ignore कर दिया जाता है।

जबकि यदि हम Event Handler द्वारा Data Pass करना चाहते हैं, तो हमें EventArgs Class को Derive करना जरूरी होता है और उस Derived Class में ही हमें वे Data Pass करने होते हैं, जिन्हें हम Parameter के रूप में Event Handler में Pass करना चाहते हैं।

हालांकि EventArgs Class Actual में कोई Data Pass नहीं करताए फिर भी EventHandler Delegate को Use करने के Pattern का ये एक महत्वपूर्ण हिस्सा है। हम जिन भी Actual Types को Parameters के रूप में Use करते हैं, ये Parameters उन Types की Base Classes को Represent करते हैं।

Event Handler के ये Parameters किसी भी EventEvent Handler के लिए Common Reference Variables की तरह काम करते हैं। ये दोनों Parameters इस बात को निश्चित करते हैं कि सभी EventHandler Delegate के Signature में केवल दो ही Parameters होंगे, जिसकी वजह से C# में Event Handling काफी आसान हो जाती है, क्योंकि हमें अलग-अलग Events के लिए अलग-अलग Signature को याद रखने की जरूरत नहीं होती।

इस तरह से यदि हम हमारे पिछले Program को ही इस नए Pattern के आधार पर Redesign करें, तो हमें हमारे Program में निम्न Modifications करने होंगे:

  • चूंकि हम System Defined EventHandler Delegate Use करेंगे, इसलिए हमें हमारे Program से Handler नाम के User Defined Delegate को Remove करना होगा।
  • Subscriber Class के EventHandler() Method का Signature, System Defined EventHandler Delegate से Match होना चाहिए, इसलिए हमें हमारी Subscriber Class के EventHandler() Method के Signature को भी Modify करना होगा और उसमें object तथा EventArgs Type के Parameters को Specify करना होगा।
  • साथ ही जब हम Subscriber Class में Event को Invoke करेंगे, तो हमें हमारे Event Raising Method को भी उपयुक्त Parameters के साथ Redefine करना होगा।

इस तरह से जब हम उपरोक्त तीनों Modification करेंगे, तो हमारा Modified Program कुछ निम्नानुसार होगा:

File Name: EventHandlingStandardPattern.cs
using System;

namespace CSharpEevents
{
    class Publisher
    {
        public event EventHandler valueChanged;		//Event Declared

        public void FireEvent(int value)
        {
            if (value == 3 && valueChanged != null)
                valueChanged(this, null);		//Raise or Trigger the Event 
        }
    }

    class Subscriber
    {
        public Subscriber(Publisher publisher)
        {
            publisher.valueChanged += EventHandler;
        }

        public void EventHandler(object source, EventArgs args)
        {
            Console.WriteLine("valueChanged Event Fired Successfully.");
        }
    }

    class UsingEvent
    {
        public static void Main()
        {
            Publisher evtGenerator = new Publisher();
            Subscriber eventListener = new Subscriber(evtGenerator);

            int number;
            do
            {
                Console.Write("Enter a Number: ");
                number = Convert.ToInt32(Console.ReadLine());
                evtGenerator.FireEvent(number);

                if (number == 3)
                    return;
                else
                    Console.WriteLine("Event Not Fired. Try Something Else.\n");
            } while (number != 3);
        }
    }
}

// Output:
   Enter a Number: 1
   Event Not Fired. Try Something Else.

   Enter a Number: 5
   Event Not Fired. Try Something Else.

   Enter a Number: 3
   valueChanged Event Fired Successfully.

इस तरह से हमने इस Program में सबसे पहले Handler नाम के User Defined Delegate को Remove किया और Publisher Class के Event को निम्नानुसार Declare किया है:

public event EventHandler valueChanged;             //Event Declared

फिर Publisher Class के ही Event Triggering Statement को निम्नानुसार दो Parameters Specify करके Modify किया है, जहां दूसरा Argument null है, क्योंकि इस दूसरे Argument की हमें कोई जरूरत नहीं है:

valueChanged(this, null);                               //Raise or Trigger the Event

अन्त में हमने Subscriber Class में Defined EventHandler() Method के Signature को निम्नानुसार तरीके से Modify किया है, ताकि ये Signature, System Defined EventHandler Delegate से Match हो जाए:

public void EventHandler(object source, EventArgs args)

परिणामस्वरूप अब जब हम इस Program को Run करते हैं, तो जैसाकि इस Program के Output द्वारा हम समझ सकते हैं कि हमें Exactly वही Output प्राप्त होता है, जो पिछली बार प्राप्त हुआ था। लेकिन इस बार हमने जिस Pattern को Use किया है, वह Pattern C# के Event Handling Mechanism का Standard Pattern है, जिसे Microsoft Visual Studio द्वारा Generate होने वाली Event Handling Coding में Use करता है।

Extending EventArgs for Passing Extra Data

हमारे Event Handler Method में दूसरे Argument के माध्‍यम से Extra Data Pass करने के लिए हमें EventArgs Class को Derive करना होता है और इस Derived Class में हमें Argument के रूप में Pass किए जाने वाले Extra Data को Hold करने के लिए Field Declare करने पडते हैं। साथ ही हमें इस बात का भी ध्‍यान रखना होता है कि हम जो नई Class Derive कर रहे हैं, उसके नाम का अन्त EventArgs से ही हो।

उदाहरण के लिए यदि हम हमारे पिछले Program की Publisher Class के लिए EventArgs Class को Derive करें, तो हमारी Class का नाम PublisherEventArgs होना चाहिए और हम इस Class को निम्नानुसार तरीके से Derive कर सकते हैं:

	public class PublisherEventArgs : EventArgs
	{
		public int extraData { get; set; }
	}

अब चूंकि हम उपरोक्तानुसार EventArgs Class को एक PublisherEventArgs Class में Derive कर चुके हैं, ताकि हम हमारे Event Handler के दूसरे Argument में किसी Extra Data को Pass कर सकें, इसलिए अब हमें एक नया Delegate Type भी बनाना होगा, जो इस Custom Data को Use कर सके।

इस जरूरत को पूरा करने के लिए हम Delegate EventHandler<> के Generic Version को Use कर सकते हैं। Generic Delegate Use करने के लिए हमें निम्नानुसार Statement लिखना होता है:

public event EventHandler<IncrementerEventArgs> valueChanged;

अब हमें Event के साथ Deal करने वाले Program के अन्‍य चारों हिस्सों में इन Custom Delegate व Custom PublisherEventArgs Class को Use करना होगा और ऐसा करने के लिए हमें हमारी Publisher Class को निम्नानुसार Modify करना होगा:

File Name: EventHandlingStandardPatternWithEventArgsParameter.cs
using System;

namespace CSharpEevents
{
    public class PublisherEventArgs : EventArgs
    {
        public int extraData { get; set; }
    }

    class Publisher
    {
        public event EventHandler<PublisherEventArgs> valueChanged;	//Event Declared

        public void FireEvent(int value)
        {
            PublisherEventArgs args = new PublisherEventArgs();
            args.extraData = value;
            if (value == 3 && valueChanged != null)
                valueChanged(this, args);			//Raise or Trigger the Event 
        }
    }

    class Subscriber
    {
        public Subscriber(Publisher publisher)
        {
            publisher.valueChanged += EventHandler;
        }

        public void EventHandler(object source, PublisherEventArgs args)
        {
          Console.WriteLine("valueChanged Event Fired Successfully with value: "+ args.extraData);
        }
    }

    class UsingEvent
    {
        public static void Main()
        {
            Publisher evtGenerator = new Publisher();
            Subscriber eventListener = new Subscriber(evtGenerator);

            int number;
            do
            {
                Console.Write("Enter a Number: ");
                number = Convert.ToInt32(Console.ReadLine());
                evtGenerator.FireEvent(number);

                if (number == 3)
                    return;
                else
                    Console.WriteLine("Event Not Fired. Try Something Else.\n");
            } while (number != 3);
        }
    }
}

// Output:
   Enter a Number: 1
   Event Not Fired. Try Something Else.

   Enter a Number: 5
   Event Not Fired. Try Something Else.

   Enter a Number: 3
   valueChanged Event Fired Successfully with value: 3.

जैसाकि इस Program के Output में हम देख सकते हैं कि इस बार हमें वह संख्‍या भी प्राप्त हो रही है, जिसे Input करने पर Publisher Class का valueChanged Event Fire होता है।

जब हम EventArgs Class को Extra Data Pass करने के लिए Derive करते हैं, तब हमें जिन;जिन स्थानों पर Modification करना होता है, उन्हें इस Program में Bold Face में Display किया गया है। इस Program में दूसरा Argument Specify करने के लिए किए गए Changes के अलावा अन्‍य सभी काम वैसे ही हो रहे हैं, जैसे पहले वाले Program में हो रहे थे।

Removing Event Handler

चूंकि Event Handler वास्तव में एक Callback Method ही होता है, जिसे Trigger किए जाने वाले Event Delegate में Add किया जाता है। इसलिए जब एक बार हमारा Callback Method अपना काम करने के लिए Execute हो जाता है, तो हम उस Method को Triggered Event Delegate से Remove करने के लिए -= Operator को Use कर सकते हैं। जैसे:

File Name: RemovingEventsOrUnsubscribing.cs
using System;

namespace CSharpEevents
{
    class Publisher
    {
        public event EventHandler simpleEvent;		//Event Declared

        public void FireEvent()
        {
            if (simpleEvent != null)
                simpleEvent(this, null);		//Raise or Trigger the Event 
        }
    }

    class Subscriber
    {
        public void EventHandler1(object source, EventArgs args)
        {
            Console.WriteLine("First Event Handler Executed.");
        }

        public void EventHandler2(object source, EventArgs args)
        {
            Console.WriteLine("Second Event Handler Executed.");
        }

        public void EventHandler3(object source, EventArgs args)
        {
            Console.WriteLine("Third Event Handler Executed.");
        }
    }

    class UsingEvent
    {
        public static void Main()
        {
            Publisher evtGenerator = new Publisher();
            Subscriber eventListener = new Subscriber();

            Console.WriteLine("After Adding all Event Handlers:");
            evtGenerator.simpleEvent += eventListener.EventHandler1;
            evtGenerator.simpleEvent += eventListener.EventHandler2;
            evtGenerator.simpleEvent += eventListener.EventHandler3;
            evtGenerator.FireEvent();

            Console.WriteLine("\nAfter Removing Event Handler2:");
            evtGenerator.simpleEvent -= eventListener.EventHandler2;
            evtGenerator.FireEvent();
        }
    }
}

// Output:
   After Adding all Event Handlers:
   First Event Handler Executed.
   Second Event Handler Executed.
   Third Event Handler Executed.

   After Removing Event Handler2:
   First Event Handler Executed.
   Third Event Handler Executed.

इस Program को हम C# Event Handling Mechanism समझने का सबसे सरल Program मान सकते हैं और इस Program द्वारा हम आसानी से Event Handling Mechanism की Internal Working को समझ सकते हैं कि किस तरह से किसी Publisher Object के साथ किसी Subscriber Event Handler को += Operator का प्रयोग करके Event के Response में Execute होने के लिए Assign किया जा सकता है और -= Operator का प्रयोग करके Publisher से Trigger होने वाले Event से किसी Event Handler Method को Unsubscribe किया जा सकता है।

यहां ध्‍यान देने वाली एक बात ये है कि जब हम एक ही Method को एक से ज्यादा बार += Operator का प्रयोग करके Publisher पर किसी Event के लिए Subscribe करते हैं, तो -= Operator का प्रयोग करने पर केवल अन्तिम Event Handler ही Publisher के Event से Unsubscribe करता है। “ोष सभी Callback Methods Event की Invocation List में Exist रहते हैं।

Event Accessors

हमने पहले भी बताया था कि Event के साथ हम केवल += -= Operators को Use करके Callback Event Handlers को ही Add या Remove कर सकते हैं और इन Operators को हमने हमारे सभी पिछले Programs में Use किया है।

लेकिन हम इन Operators के Behavior का Modify भी कर सकते हैं, जिससे Event हमारे द्वारा Specified Custom Code के आधार पर Callback Event Handlers को Add व Remove करने के अलावा अन्‍य काम भी कर सकता है।

हालांकि ये एक Advance Topic है और हम फिलहाल इस Topic में ज्यादा Deep में नहीं जाएेंगे। फिर भी इन Operators के Operations को Modify करने हेतु हम Event के लिए addremove Accessors को Define कर सकते हैं।

Accessors को Define करने पर ये काफी कुछ Properties के Definition के समान ही दिखाई पडते हैं। Events के लिए Accessors को हम कुछ निम्नानुसार तरीके से Define कर सकते हैं:

public event EventHandler simpleEvent
{
   add
   {
	... 		// Code to implement the =+ operator
   }

   remove
   {
	... 		// Code to implement the -= operator
   }
}

इन add remove दोनों ही Accessors में value नाम का एक Implicit Parameter होता है, जो किसी Instance Method या Static Method के Reference को Value के रूप में Accept करता है।

जब Accessors को Declare किया जाता है, तब Event में कोई Delegate Object Contained नहीं होता। इसलिए हमें Event के साथ Register किए जाने वाले Callback Event Handler Methods को Store करने तथा Remove करने के लिए हमारे स्वयं के Storage Mechanism को Implement करना पडता है।

जब हम add remove Accessors को Use करते हैं, तब हमें इस बात का हमेंशा ध्‍यान रखना होता है कि Event Accessors हमेंशा void Methods की तरह काम करते हैं। यानी Accessors कभी भी return Statement का प्रयोग करके किसी Value को Return नहीं कर सकते।

C# Raise Event
Generics in C#

C# in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C#.NET in Hindi | Page:908 | Format: PDF

BUY NOW GET DEMO REVIEWS