Make your own free website on Tripod.com

دروس مرتبط

 

  صفحه اصلی > آموزش #C > رخدادها و Delegate (سوم)

   

> معرفی #C

     آغاز کار با #C

     متغیرها،عبارات وعملگرها

     دستورهای کنترلی شرطی

     دستورهای کنترلی حلقه ای

 

> قالب برنامه ها

     کلاسها در #C

     آشنایی با NameSpace

     چگونگی نوشتن متد

     ساختارها (Structure)

 

> کار با کامپوننت ها

     ویژگی ها (Properties)

     صفات (Attribute)( اول)

     صفات (Attribute)( دوم)

     رخدادها و Delegate

     ( اول)

    رخدادها و Delegate

    ( دوم)

    رخدادها و Delegate

    ( سوم)

    کنترل خطاها

 

 
 

 رخدادها و delegate ها در  C#(بخش سوم)

فهرست مطالب بیان شده در این قسمت به قرار زیر است:

       درك اينكه يك رخداد يا يك event چيست؟

       اعلان رخدادها

       نكات و توضيحات پيشرفته

       ثبت شدن در يك رخداد

       لغو عضويت در يك رخداد

       فراخواني رخدادها

       مثالي پيشرفته از استفاده رخدادها در فرمهاي ويندوز

       نكات كليدي درباره رخدادها و delegate ها

رخدادها (Events)

در برنامه‌هاي Console ، برنامه منتظر ورود اطلاعات يا دستوراتي از سوي كاربر مي‌ماند و با استفاده از اين اطلاعات كار مورد نظر را انجام مي‌دهند.  اين روش برقراري ارتباط با كاربر، روشي ناپايدار و غير قابل انعطاف است. در مقابل برنامه‌هاي Console، برنامه‌هاي مدرن وجود دارند كه با استفاده از GUI با كاربر در ارتباطند و بر پايه رخدادها بنا شده‌اند (Event-Based)، بدين معنا كه رخدادي (منظور از رخداد اتفاقي است كه در سيستم يا محيط برنامه صورت ميگيرد.) در سيستم روي مي‌دهد و بر اساس اين رخداد عملي در سيستم انجام مي‌شود.  در برنامه‌هاي تحت ويندوز، نيازي به استفاده از حلقه‌هاي متعدد جهت منتظر ماندن براي ورودي از كاربر نيست، بلكه با استفاده از رخدادها، تراكنش بين سيستم و كاربر كنترل مي‌شود.

يك event در زبان C#، عضوي از كلاس است، كه در صورت بروز رخداد خاصي، فعال مي‌شود و عملي را انجام مي‌دهد. معمولاً براي فعال شده event از دو عبارت fires و raised استفاده مي‌شود. هر متدي كه بخواهد، ميتواند در ليست رخداد ثبت شده و به محض اتفاق افتادن آن رخداد، از آن مطلع گردد.

بطور كلي مي‌توان گفت كه يك رخداد همانند يك فيلد اعلان مي‌شود با اين تفاوت مهم كه نوع آنها حتماٌ بايد يك delegate باشد.

Delegate و رخدادها در كنار يكديگر كار مي‌كنند تا قابليت‌هاي يك برنامه را افزايش دهند. اين پروسه با شروع يك كلاس كه يك رخداد را تعريف مي‌كند، آغاز مي‌شود. هر كلاسي، كه اين رخداد را درون خود داشته باشد، در آن رخداد ثبت شده است و مي‌تواند متدي را به آن رخداد تخصيص دهد. اين عمل با استفاده از delegate ها صورت مي‌پذيرد، بدين معني كه delegate متدي را كه براي رخداد ثبت مي‌شود را تعيين مي‌نمايد. Delegate ها مي‌توانند هر يك از delegate هاي از پيش تعريف شدة .Net و يا هر delegate ي باشند كه توسط كاربر تعريف شده است. بطور كلي، delegate ي را به رخدادي تخصيص مي‌دهيم تا متدي را كه بهنگام روي دادن رخداد فراخواني مي‌شود، معين گردد. مثال زير روش تعريف رخداد را نشان مي‌دهد.

ابتدای صفحهF

مثال 2-14 : اعلان و پياده‌سازي رخدادها

using System;

public delegate void MyDelegate();

class Listing14-2

{

   public static event MyDelegate MyEvent;

   static void Main()

   {

      MyEvent += new MyDelegate(CallbackMethod);

 

      // فراخواني رخداد

      MyEvent();

      Console.ReadLine();

   }

   public static void CallbackMethod()

   {

      Console.WriteLine("CallbackMethod.");

   }

}

در اين مثال، ابتدا اعلان يك delegate ديده مي‌شود.  درون كلاس، رخدادي با نام MyEvent و از نوع MyDelegate تعريف شده است. در متد Main() نيز مرجع جديدي به رخداد MyEvent افزوده شده است. همانطور كه در اين مثال نيز مشاهده مي‌كنيد، delegate ها تنها با استفاده از += مي‌توانند به رخدادها افزوده شوند. در اين مثال هر گاه MyEvent فراخواني شود، متد CallbackMethod اجرا مي‌شود چراكه با استفاده از مرجع delegate به رخداد مرتبط شده است. (يا در اصطلاح در رخداد ثبت شده است.)

مثال فوق را بدون استفاده از رخداد نيز مي‌توان نوشت. اين نسخه از مثال 2-14 كه تنها در آن از delegate استفاده شده در زير آورده شده است :

using System;

public delegate void MyDelegate();

class UsingDelegates

{

   static void Main()

   {

      MyDelegate del = new MyDelegate(CallbackMethod);

      // delegate فراخواني

      del();

      Console.ReadLine();

   }

   public static void CallbackMethod()

   {

      Console.WriteLine("CallbackMethod.");

   }

}

بايد توجه كنيد كه موارد كاربرد رخدادها بيشتر در برنامه‌هاي تحت ويندوز نمايان مي‌شود و در اينجا شايد وجود آنها در برنامه براي شما مشهود نباشد. در آينده، به بررسي برنامه‌نويسي فرمهاي ويندوز نيز خواهيم رسيد و در آنجا به طور مفصل درباره event ها و delegate ها مجدداً بحث خواهيم نمود.

بطور خلاصه مي‌توان گفت، با استفاده از delegate ها روشي براي ايجاد دسترسي به متدها بط.ور پويا را فراهم نموديم. با استفاده از رخدادها نيز، در صورت بروز اتفاقي خاص، عملي خاص انجام مي‌گيرد. اين عمل معمولاٌ با استفاده از يك delegate كه مرجعي به يك متد در خود دارد انجام مي‌گيرد.

 ابتدای صفحهF

توضيحات پيشرفته :

در انتهاي اين درس مي‌خواهم توضيحات پيشرفته تري را نيز در اختيار شما قرار دهم. در قسمت مربوط به delegate ها در همين درس، مثالي مطرح شد كه در آن delegate ي با نام Tick وجود داشت. اعلان اين delegate به صورت زير بود :

delegate void Tick(int hours, int minutes, int seconds);

حال ميخواهيم به اين مثال يك رخداد نيز اضافه كنيم. در زير رخداد tick از نوع Tick اعلان شده است :

class Ticker

{

    public event Tick tick;

   

}

بايد توجه نماييد كه يك رخداد بطور خودكار ليست اعضاي خود را مديريت مي‌كند و نيازي به استفاده از يك مجموعه، مانند آرايه، براي مديريت اعضاي مرتبط با آن نيست.

نكته : يك رخداد بطور خودكار خود را تخصيص دهي مي‌كند و نيازي به ساخت نمونة جديد از روي يك رخداد وجود ندارد.

ابتدای صفحهF

عضو شدن در يك رخداد (تبث شدن در يك رخداد)

براي افزودن delegate جديد به يك رخداد كافيست تا از عملگر += استفاده نماييم. مثال زير كلاس Clock را نشان مي‌دهد كه در آن فيلدي از نوع Ticker با نام pulsed وجود دارد. كلاس Ticker داراي رخداد tick از نوع delegate ي بنام Tick است. متد Clock.Start، delegate ي از نوع Tick را با استفاده از عملگر += به pulsed.tick مي‌افزايد. 

delegate void Tick(int hours, int minutes, int seconds);

class Ticker

{

    public event Tick tick;

}

 class Clock

{

    public void Start()

    {

        pulsed.tick += new Tick(this.RefreshTime);

    }

     private void RefreshTime(int hours, int minutes, int seconds)

    {

    }

    private Ticker pulsed = new Ticker();

}

هنگاميكه رخداد pulsed.tick اجرا مي‌شود، تمامي delegate هاي مرتبط با آن نيز فراخواني مي‌شوند كه در اينجا يكي از آنها RefreshTime است. (به مثال موجود در بخش delegate رجوع نماييد.)

 ابتدای صفحهF

خارج شدن از ليست يك رخداد

همانطور كه با استفاده از عملگر += مي‌توان delegate ي را به يك رخداد افزور، با استفاده از عملگر -= نيز مي‌توان delegate خاصي را از ليست اعضاي يك رخداد خارج نمود.

class Clock
{  
    public void Stop()
    {
        pulsed.tick -= new Tick(this.RefreshTime);
    }
    private void RefreshTime(int hours, int minutes, int seconds)
    {
    }    
    private Ticker pulsed = new Ticker();
}

نكته : همانطور كه مي‌دانيد، عملگرهاي += و -= بر پاية دو عملگر اصلي + و ايجاد شده‌اند. از اينرو در مورد delegate ها نيز مي‌توان از عملگر + استفاده نمود. استفاده از عملگر + براي delegate ها باعث ايجاد delegate جديدي مي‌شود كه به هنگام فراخواني هر دو delegate را به هم فرامي‌خواند.

 ابتدای صفحهF

فراخواني يك رخداد

يك رخداد نيز همانند delegate، با استفاده از دو پرانتز فراخواني مي‌گردد. پس از اينكه رخدادي فراخواني شد، كليه delegate هاي مرتبط با آن بترتيب فراخواني مي‌شوند. براي مثال در اينجا كلاس Ticker را در نظر بگيريد كه داراي متد private با نام Notify است كه رخداد tick را فرا مي‌خواند :

class Ticker

{

    public event Tick tick;

    private void Notify(int hours, int minutes, int seconds)

    {

        if (tick != null)

        {

            tick(hours, minutes, seconds);

        }

    }   

}

نكته مهم : توجه كنيد كه در مثال فوق چك كردن null نبودن رخداد tick ضروري است، چراكه فيلد رخداد بطور ضمني null در نظر گرفته مي‌شود و تنها زماني مقداري به غير null ميگيرد كه delegate ي به آن مرتبط شده باشد. در صورت فراخواني رخداد null، خطاي NullReferenceException روي خواهد داد.

رخدادها داراي سطح امنيتي داخلي بسيار بالايي هستند. رخدادي كه بصورت public اعلان مي‌شود، تنها از طريق متدها يا عناصر داخل همان كلاس قابل دسترسي است. بعنوان مثال، tick رخدادي درون كلاس Ticker است، از اينرو تنها متدهاي درون Ticker مي‌توانند tick را فرا بخوانند.

class Example
{
    static void Main()
    {
        Ticker pulsed = new Ticker();
        pulsed.tick(12, 29, 59); // خطاي زمان كامپايل رخ مي‌دهد
    }
}

 ابتدای صفحهF

مثالي پيشرفته از استفادة رخدادها در فرمهاي ويندوز

حال كه تا حدودي با رخدادها و ساختار آنها آشنا شديد، در اين قسمت قصد دارم تا مقداري دربارة استفاده رخدادها در فرمهاي ويندوز و GUI ها صحبت نمايم. هر چند تا كنون كليه برنامه‌ها و مطالبي كه مشاهده كرده‌ايد مبتني بر ‍Console بوده‌اند، اما به علت استفاده بيشمار رخدادها در فرمهاي ويندوز و برنامه‌هاي مبتني بر GUI، لازم ديدم تا مطالبي نيز در اين باره بيان كنم. هر چند فرمهاي ويندوز و GUI مطالبي هستند كه خود نياز به بحث و بررسي دقيق دارند و انشا ا... در رئوس آتي سايت مورد بررسي قرار خواهند گرفت. درصورتيكه مطالب اين قسمت براي شما دشوار و يا گنگ بود نگران و يا ناراحت نشويد چرا كه فعلاً براي يادگيري اين مطالب آنهم بدون مقدمه اندكي زود است، بيشتر هدف من از اين بخش آشنا شدن شما با كاربردهاي پيشرفته‌تر رخدادها در برنامه‌نويسي بوده است.

كلاسهاي GUI مربوط به .Net Framework بطور گسترده‌اي از رخدادها استفاده مي‌نمايند. در مثالي كه در اينجا مورد بررسي قرار مي‌دهيم، برنامه‌اي وجود دارد كه داراي يك فرم به همراه دو دكمه (Button) بر روي آن است. اين دو دكمه بوسيلة دو فيلد از نوع Button ايجاد مي‌شوند. (Button عضو System.Windows.Forms است). كلاس Button از كلاس Control ارث‌بري مي‌كند و داراي رخدادي با نام Click از نوع EventHandler است. به مثال توجه نماييد.

namespace System

{

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

    public class EventArgs

    {

    }

}

namespace System.Windows.Forms

{

    public class Control :

    {

        public event EventHandler Click;

     }

    public class Button : Control

    {

    }

}

توجه نماييد كه كد فوق، كد مربوط به namespace مربوط به System است كه نحوة پياده‌سازي آنرا نشان مي‌دهد. همانطور كه ملاحظه مي‌نماييد، درون System، delegate ي با نام EventHandler تعريف شده است. در زير اين namespace، اعلان System.Windows.Forms نيز آورده شده تا نحوة اعلان رخداد Click و ارث‌بري كلاس Button از كلاس Control نيز مشخص شود.

پس از اينكه بر روي دكمه‌اي واقع در فرم ويندوز كليك كنيد، Button بطور خودكار رخداد Click را فرا مي‌خواند. هدايت اين پروسه باعث مي‌شود تا بتوان به سادگي delegate ي براي كنترل اين رخداد ايجاد نمود. در مثالي كه در زير مشاهده مي‌كنيد، دكمه‌اي با نام Okay، متدي بنام Okay_Click و رخدادي جهت اتصال Okay به متد Okay_Click وجود دارد.

class Example : System.Windows.Forms.Form
{
    private System.Windows.Forms.Button okay
    public Example()
    {
     this.okay = new System.Windows.Forms.Button();
     this.okay.Click += new System.EventHandler(this.okay_Click
    }
   private void okay_Click(object sender, System.EventsArgs args)
    { 
    }
}

همانطور كه مشاهده مي‌كنيد، كلاس Example از System.Windows.Forms.Form مشتق مي‌شود، از اينرو تمامي خواص آن را به ارث مي‌برد. Okay نيز از نوع Button اعلان شده است. درون سازندة (Constructor) كلاس Example، متد Okay.Click به رخداد افزوده شده و مرجع this.Okay.Click نيز، متد مورد نظر را تعيين نموده است. همانطور كه گفته شد، EventHandler نيز delegate مورد نظر در اين مثال است. درون متد Okay_Click نيز ميتوان كد خاصي را قرار داد تا عمل مورد نظر را انجام دهد. پس از كليك كردن بر روي دكمة Okay، عمل مورد نظري كه درون متد Okay_Click قرار داده شده، اجرا مي‌شود.

اين كد، شبيه به كدهايي است كه توسط محيط‌هاي برنامه‌سازي نظير Visual Studio.Net و يا C#Builder بطور خودكار  توليد مي‌شوند و تنها كافيست تا شما كد مربوط به Okay_Click را درون آن وارد نماييد.

رخدادهايي كه توسط كلاسهاي GUI توليد مي‌شوند همواره از يك الگوي خاص پيروي مي‌كنند. اين رخدادها همواره از نوع delegate ي هستند كه مقدار بازگشتي ندارد (void) و داراي دو آرگومان است. آرگومان اول هميشه فرستندة رخداد و آرگومان دوم هميشه آرگومان EventArgs يا كلاس مشتق شده از EventArgs است.

آرگومان sender به شما اين امكان را مي‌دهد تا از يك delegate براي چندين رخداد استفاده نماييد. (بعنوان مثال براي چندين دكمه.)

 ابتدای صفحهF

نكاتي چند درباره delegate ها و event ها

Delegate ها بطور ضمني از System.Delegate ارث‌بري مي‌كنند. Delegate حاوي متدها، property ها و عملگرهايي است كه مي‌توان آنها را بعنوان پارامتر به متدهاي ديگر ارسال نمود. همچنين به دليل اينكه System.Delegate بخشي از .Net Framework است، از اينرو delegate هاي ايجاد شده در C# را مي‌توان در زبانهاي ديگري نظير Visual Basic.Net نيز استفاده نمود.

هنگام اعلان پارامترها براي delegate، حتماً بايد براي آنها نام در نظر بگيريد و فقط به مشخص كردن نوع پارامترها بسنده نكنيد.

رخدادها عناصر بسيار مفيد و پر استفاده‌اي هستند كه با بكارگيري delegate ها بسيار قدرتمند ظاهر مي‌شوند. بدست آوردن مهارت در ايجاد و استفاده از آنها نياز به تمرين و تفكر بسيار دارد.

 

ابتدای صفحهF  

Back Next

  صفحه اصلی
    C# آموزش
    مفاهیم شی گرایی
    برنامه های نمونه
    کار با محیط
    معرفی کتاب
    نقشه سایت
    درباره ما
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
                               
[صفحه اصلی] [آموزش #C] [مفاهیم شی گرایی] [برنامه های نمونه] [کار با محیط] [معرفی کتاب] [نقشه سایت] [درباره ما]