کنترل کننده رویداد (event Handler)

رابط گرافیکی کاربر در دات نت و ویژوال سی شارپ از مکانیزم کنترل کننده رویداد برای کنترل رویدادها که در هنگام اجرای برنامه به وقوع می پیوندند استفاده می کند.رویدادها رفتارهایی یا اتفاقاتی هستند که هنگام اجرای برنامه به وقوع می پیوندند.کنترل رویداد فرایند نظارت بر وقوع یک رویداد مشخص می باشد. فرم های ویندوزی از کنترل کننده رویداد برای اضافه کردن یک قابلیت و پاسخ به کاربر استفاده می کنند.بدون کنترل کننده رویداد، فرم ها و رابط گرافیکی تا حد زیادی بدون استفاده هستند.در این درس فرض بر این است که شما بر مفاهیم delegates و events (رویداد) تسلط دارید. رویدادها با استفاده از یک delegate به عنوان یک نوع تعریف می شوند.delegate ها آدرس متدها را در خود ذخیره می کنند. در مثال زیر یک delegate و یک event تعریف شده اند.

public delegate void SampleEventHandler(int);

public event SampleDelegate SampleEvent;

بر اساس تعریف بالا delegate آدرس متدهایی را قبول می کند که دارای مقدار برگشتی نیستند و یک آرگومان ساده از نوع int قبول می کنند.سپس از این نوع delegate برای ایجاد event مان استفاده می کنیم.حال یک کنترل کننده رویداد به رویداد اضافه می کنیم.همانطور که قبلا اشاره شد، هر رویداد دارای یک delegate مخصوص به خود است که این delegate دارای یک یا چند متد می باشد. کنترل کننده های رویداد متدهایی هستند که امضای آنها همانند امضای این delegate است و هنگام وقوع رویداد اجرا می شوند.آنها (کنترل کننده های رویداد) چسبیده به یک event هستند و هنگامی که رویداد به وقوع می پیوندد اجرا می شوند.می توان چندین کنترل کننده های رویداد را به یک event متصل کرد تا هنگام وقوع رویداد اجرا شوند. برای این کار ابتدا باید کنترل کننده رویداد را ایجاد کنید. بعد از ایجاد ،مطمئن شوید که امضای آن با امضای delegate ی که رویداد از آن استفاده می کند مطابق باشد. به عنوان مثال delegate مثال بالا دارای نوع برگشتی void بوده و یک پارامتر از نوع int دریافت می کند، پس کنترل کننده رویداد ما نیز باید دارای نوع برگشتی void بوده و یک پارامتر از نوع int دریافت کند (به این نکته توجه کنید که سطح دسترسی مهم نیست).

public void ShowMessage(int number)
{
    MessageBox.Show("Hello World");
}

سپس می توان با استفاده از عملگر =+ یک رویداد را متصل کرد :

SampleEvent += new SampleEventHandler(ShowMessage);

برای فعال کردن رویداد به همان روشی که متد ها را فراخوانی می کردیم آن را صدا زده و آرگومانی را که لازم دارد به آن ارسال می کنیم.

ShowMessage(3);

 

کنترل کننده رویداد در فرم های ویندوزی

قبل از توضیح کنترل کننده رویداد در ویندوز فرم ابتدا ارتباط بین کنترل کننده رویداد، delegate و رویداد را دوباره یادآوری می کنیم :

جمله بالا در کد زیر خلاصه می شود :

SampleEvent += new SampleDelegate(SampleEventHandler);

به این نکته هم اشاره کنیم که در سی شارپ تعداد زیادی event و delegate از پیش تعریف شده وجود دارد که ویژوال استودیو مسئولیت اداره آنها را به عهده دارد. برای شرح استفاده از رویدادها در فرم های ویندوزی، یک فرم ویندوزی جدید ایجاد کرده و نام آن را eventHandling بگذارید. بر روی فرم دوبار کلیک کرده تا ویژوال استودیو به صورت خودکار یک کنترل کننده رویداد ایجاد کرده و آن را به رویداد Load فرم متصل کند. به شکل زیر توجه کنید :
event-handling-07
همانطور که در شکل بالا مشاهده می کنید، یک کنترل کننده رویداد به نام Form1_Load به طور خودکار ایجاد می شود، که دارای دو پارامتر است. در مورد این دو پارامتر در ادامه توضیح می دهیم. نکته ای که بهتر است در همین جا به آن اشاره کنیم نحوه نامگذاری کنترل کننده های رویداد توسط ویژوال استودیو است. در ویژوال استودیو کنترل کننده های رویداد بر طبق یک قرار داد نامگذاری می شوند. هنگام نامگذاری آنها ابتدا نام کنترل (که در خاصیت Name کنترل مشخص شده است)، سپس علامت زیر خط و بعد از آن نام رویداد می آید مانند : Form1_Load. می توان این قرارداد را زمانی که کنترل کننده رویداد به وسیله چند رویداد مورد استفاده قرار می گیرد، نادیده گرفت که در ادامه توضیح داده خواهد شد. همانطور که گفتیم ویژوال استودیو به صورت خودکار یک کنترل کننده رویداد ایجاد کرده و آن را به رویداد Load فرم متصل می کند. برای مشاهده رویداد ایجاد شده و اتصال آن به کنترل کننده رویداد کافی است که در پنجره Solution Explorer بر روی Form1.Designer.cs دوبار کلیک کنید. به شکل زیر توجه کنید :
event-handling-08
همانطور که در شکل بالا مشاهده می کنید، رویداد Load دارای یک delegate از نوع EventHandler است که کنترل کننده رویداد Form1_Load در داخل آن قرار می گیرد. ویژوال استودیو با استفاده از عملگر =+ این کنترل کننده را که قرار است هنگام وقوع رویداد Load اجرا شود را به رویداد معرفی می کند. بیشتر رویدادهای کنترل ها یک delegate از نوع System.eventHandler دارند. مثال زیر تعریفی از دلیگیت eventHandler می باشد:

public delegate void EventHandler(object sender, EventArgs e)

همانطور که مشاهده می کنید ،delegate مثال بالا دارای مقدار برگشتی نیست و دارای دو پارامتر است، یکی object و دیگری یک نمونه از eventArgs.

 

پارامتر object sender

object sender نشان دهنده کنترلی است که رویداد را فعال می کند و ویژوال استودیو از این آرگومان برای تشخیص کنترلی که رویداد مربوط به آن است استفاده می کند.(بعدا توضیح داده می شود). از آن جایی که نوع این پارامتر object است ، هر کنترلی می تواند منبع ارسال رویداد باشد چون هر کنترل یک شی است که از کلاس پایه object مشتق می شود.از آنجایی که ارسال کننده رویداد(کنترل) به نوع object تبدیل می شود ، برای استفاده مجدد از خصوصیات کنترل باید آن را با استفاده از عمل cast تبدیل کنیم ( تولید کنیم). برای روشن شدن مطلب به مثال زیر توجه کنید. ابتدا یک کنترل button را روی فرم قرار دهید و سپس خاصیت Text آن را به “Hello World!” تغییر دهید.
event-handling-01
بر روی کنترل دوبار کلیک کنید تا یک کنترل کننده رویداد برای رویداد کلیک آن ایجاد شود. مانند رویداد Load، رویداد Click نیز یک کنترل کننده رویداد دارد.کد زیر را در داخل کنترل کننده رویداد بنویسید :

private void button1_Click(object sender, EventArgs e)
{
    Button source = (Button)sender;
    MessageBox.Show("The message inside the button is " + source.Text);
}

برنامه را اجرا کرده و بر روی دکمه کلیک کنید. یک جعبه متن نمایش داده خواهد شد. این متن هنگام وقوع رویداد Click نمایش داده می شود.
event-handling-02
خط اول کنترل کننده رویداد شی sender را با استفاده از عمل cast به یک دکمه تبدیل می کند بنابراین می توانیم به خاصیت Text دکمه دسترسی داشته باشیم. سپس متد Show از کلاس MessageBox را برای نشان دادن مقدار خاصیت Text دکمه که به رویداد فرستاده شده است، فراخوانی می کنیم.

 

پارامتر eventArgs

این پارامتر نمونه ای از کلاس eventArgs می باشد و می توان آن را به عنوان آرگومان رویداد در نظر گرفت که حاوی دادهایی در مورد رویدادی که اتفاق افتاده است می باشد . eventArgs در اصل یک کلاس پایه است و دارای اعضای مفیدی نمی باشد. این پارامتر در برخی از کنترل کننده های رویداد متفاوت است. مثلا در رویداد Click این آرگومان EventArgs و در رویداد MouseClick به صورت MouseEventArgs می باشد. همانطور که گفتیم، کلاس پایه eventArgs در هیچ خاصیتی که شما بتوانید در کنترل کننده رویداد خود از آن استفاده کنید ندارد :
event-handling-09
اما MouseEventArgs دارای خواص مفیدی از جمله اینکه کدام دکمه ماوس فشار داده شده ، تعداد کلیک ها ، مقدار چرخش ماوس و مختصات مکانی که رویداد کلیک در آن اتفاق افتاده است می باشد :
event-handling-10
رویداد MouseClick از کنترل button است که نسخه بهتری از رویداد Click می باشد. از آنجایی که این رویداد (MouseClick) رویداد پیشفرض نیست، برای دسترسی به آن باید از بخش events از پنجره Properties اقدام نمایید. مطمئن شوید که کنترل button در قسمت طراحی فرم انتخاب شده است. بر روی آیکون events ( که به شکل جرقه است) کلیک کنید. ابتدا کنترل کننده رویداد Click را حذف کنید تا با این رویداد(MouseClick) تداخل پیدا نکند. برای حذف رویداد Click از پنجره Properties بر روی آیکون جرقه کلیک کرده و از لیست رویدادها، رویداد Click را پیدا کرده و سپس بر روی آن راست کلیک و سپس دکمه Reset را بزنید :
event-handling-06
سپس رویداد MouseClick را یافته و بر روی آن دوبار کلیک کرده و کد زیر را در داخل کنترل کننده رویداد MouseClick آن بنویسید :

private void button1_MouseClick(object sender, MouseEventArgs e)
{
    MessageBox.Show("You clicked at point (" + e.X + ", " + e.Y + ")");
}

کد بالا با استفاده از پارامتر event argument به مختصات x و y نقطه ای که با ماوس بر روی آن کلیک شده است دست می باید. خروجی زیر بستگی به این دارد که شما بر روی چه نقطه ای از دکمه کلیک کنید.
event-handling-03
انواع زیادی event argument وجود دارد که هر کدام خواص مفیدی برای رویدادی که اتفاق می افتد پیشنهاد می دهند.

 

استفاده از پنجره خواص برای اضافه کردن کنترل کننده رویداد

همانطور که می دانید صرف نظر از دوبار کلیک کردن بر روی کنترل ها برای ایجاد کنترل کننده رویداد می توانیم از پنجره Properties برای این کار نیز استفاده کنیم. بر روی آیکونی که شبیه به یک جرقه است کلیک کنید تا وارد بخش رویداد های (Events) پنجره Properties شوید.
event-handling-04
از منوی باز شونده ای که با فلش قرمز در شکل بالا نشان داده شده است برای انتخاب کنترل ها در محیط طراحی استفاده می شود. استفاده از این منو زمانی مفید است که شما بخواهید یک کنترل غیر قابل رویت و یا بسیار کوچک را انتخاب کنید. رویداد مورد نظر را پیدا کنید. برای اضافه کردن کنترل کننده رویداد به آن می توانید بر روی نام رویداد دوبار کلیک کنید تا کنترل کننده رویداد مربوط به آن ایجاد شود. همچنین اگر از قبل کنترل کننده های رویداد دیگری نیز ایجاد کرده اید می توانید مانند شکل زیر به آنها دسترسی داشته باشید.
event-handling-05

به این نکته توجه کنید که نام برخی از رویدادها در داخل نام رویدادهای پنجره Properties نیست. رویداد MouseWheel یکی از این رویدادهاست. برای دسترسی به چنین رویدادهایی می توانید از محیط کدنویسی و قابلیت IntelliSense استفاده کنید. البته این کار نیاز به کمی مهارت و یا حتی جستجو در بین سایت های مختلف دارد. ولی قواعد کلی همان است که در بالا اشاره شد. به کد زیر توجه کنید :

using System.Windows.Forms;

namespace eventHandling
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            this.button1.MouseWheel += new MouseEventHandler(this.button1_MouseWheel);            
        }

        private void button1_MouseWheel(object sender, MouseEventArgs e)
        {
            this.button1.Width += e.Delta;
        }
    }
}

MouseWheel رویداد مربوط به حرکت دکمه وسط ماوس به طرف بالا و پایین است. همانطور که در کد بالا مشاهده می کنید کافیست که در قسمت سازنده form1 این رویداد را به مثلا دکمه اضافه کنیم. سپس یک کنترل کننده رویداد (button1_MouseWheel) به آن وصل کنیم. کدهای بدنه کنترل کننده رویداد باعث می شوند که با چرخاندن دکمه وسط ماوس به سمت بالا و پایین عرض دکمه ی روی فرم کم و زیاد شود.
 

استفاده از یک کنترل کننده رویداد برای چندین رویداد

به این نکته توجه کنید که می توان از یک کنترل کننده رویداد برای چندین رویداد که دارای نماینده (delegate) یکسانی هستند، استفاده کرد. برای انجام این کار لازم است که یک کنترل کننده رویداد با یک امضای مناسب ایجاد کنید. مثلا رویدادهای click و Load دارای امضاهای یکسانی هستند، پس می توان یک کنترل کننده رویداد را به این دو رویداد اختصاص داد. یک دکمه بر روی فرم قرار داده و سپس با زدن دکمه F7 به محیط کدنویسی رفته و کد زیر را بنویسید :

private void myEventHandler(object sender, EventArgs e)
{
   MessageBox.Show("This is myEventHandler!");              
}

بعد از ایجاد کنترل کننده رویداد بالا (myEventHandler)، با استفاده از عملگر =+ آن را به رویداد مورد نظرتان اختصاص دهید. فرض کنید که می خواهید قبل از اینکه فرم بالا بیاید و یا بر روی دکمه کلیک شود، این کنترل کننده رویداد اجرا شود. برای این منظور کنترل کننده رویداد را به صورت زیر به رویداد های Load فرم و Click دکمه اختصاص دهید :

using System;
using System.Windows.Forms;

namespace eventHandling
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            this.Load     += new EventHandler(myEventHandler);
            button1.Click += new EventHandler(myEventHandler);
        }

        private void myEventHandler(object sender, EventArgs e)
        {
            MessageBox.Show("This is myEventHandler!");
        }
    }
}

قبلا ذکر شد که می توان قرارداد نامگذاری کنترل کننده های رویداد، زمانی که توسط چندین رویداد مورد استفاده قرار می گیرند را نادیده گرفت، این نکته را در کد بالا مشاهده می کنید. به این نکته توجه کنید که این کنترل کننده رویداد (myEventHandler) را برای هر رویدادی (مثلا FormClosing) نمی توان مورد استفاده قرار داد. چون کنترل کننده های رویدادی که با اجرای این رویداد به وقوع می پیوندند در داخل Delegate ی قرار می گیرند که کنترل کننده های رویدادی با امضای زیر را قبول می کند :

private void Form1_FormClosing(object sender, FormClosingEventArgs e)

در حالیکه کنترل کننده رویداد ما دارای امضای زیر است :

private void myEventHandler(object sender, EventArgs e)

و در آخر به این نکته خیلی مهم توجه کنید که با کپی کردن یک کنترل کننده رویداد در محیط کدنویسی، کدهای داخل آن اجرا نمی شوند. برای روشن شدن مطلب یک برنامه ویندوزی ایجاد کرده و یک دکمه بر روی فرم قرار دهید. حال با زدن دکمه F7 به محیط کدنویسی رفته و کنترل کننده رویداد زیر را در آن کپی کنید :

private void button1_Click(object sender, EventArgs e)
{
    MessageBox.Show("Hello World!");
}

به صورت زیر
event-handling-in-c-20
همانطور که از کد بالا پیداست، این کد برای رویداد کلیک دکمه نوشته شده است، به طوریکه اگر بر روی دکمه کلیک شود یک پیغام نمایش داده شود. حال با زدن دکمه F5 برنامه را اجرا کرده و بر روی دکمه کلیک کنید. مشاهده می کنید که هیچ پیغامی نمایش داده نمی شود. دلیل این امر روشن است و آن این است که ما این کنترل کننده رویداد را به رویداد Click وصل نکرده ایم. برای این منظور دو راه وجود دارد. اولین راه این است که برنامه را متوقف کرده و بر روی دکمه دو بار کلیک کنید تا ویژوال استودیو به طور خودکار این کار را انجام دهد. در این حالت اگر به صورت زیر بر روی فایل Form1.Designer.cs دو بار کلیک کنید مشاهده می کنید که کنترل کننده رویداد به رویداد Click متصل شده است :
explore-csharp-express-21
حال اگر برنامه اجرا و بر روی دکمه کلیک کنید، مشاهده می کنید که پیغام نمایش داده می شود. راه دوم هم این است که خودتان به صورت دستی این کنترل کننده رویداد را به رویداد Click وصل کنید :
event-handling-in-c-21

لطفا اگر نظر، پیشنهاد و یا انتقادی در باره مطلب بالا دارید در قسمت زیر و اگر سوالی دارید در بخش پرسش و پاسخ مطرح بفرمایید.