PDA

View Full Version : delegate , کاربرد آن در این پست ؟



dr_csharp
یک شنبه 26 اسفند 1386, 15:33 عصر
سلام
دوستمون در پست نکات ؛ ایده ها و ترفندهای کوچک (http://barnamenevis.org/forum/showthread.php?t=95001&page=24)یه مثال آوردن که ممنون میشم دوستان بیشتر شرح بدن !



delegate void MyDelegate(string s);

void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 10; i++)
{
MyDelegate md = new MyDelegate(AddItems);
this.Invoke(md, (object)("ASync" + i.ToString()));
System.Threading.Thread.Sleep(500);
}
}

private void AddItems(string s)
{
listBox1.Items.Add(s);
}

private void btnASync_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
worker.RunWorkerAsync();
}

چرا دراین مثال از delegate استفاده شده و Delegate چه جاهایی کاربرد داره ؟

sinpin
یک شنبه 26 اسفند 1386, 15:44 عصر
ممنون که مساله رو در یک تاپیک مستقل مطرح کردید.

خب شما بیاین و کد رو به شکل زیر تغییر بدید :

void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 10; i++)
{
listBox1.Items.Add(i.ToString());
System.Threading.Thread.Sleep(500);
}
}و حال برنامه رو اجرا کنید. میبینید که :

Cross-thread operation not valid: Control 'listBox1' accessed from a thread other than the thread it was created on.
دلیل : از درون یک thread نمیتوان بصورت مستقیم به عناصر UI ترد دیگر دسترسی داشت

sinpin
یک شنبه 26 اسفند 1386, 15:51 عصر
این پست از آقای برمودا رو هم ببینید :
http://barnamenevis.org/forum/showpost.php?p=474172

vcldeveloper
یک شنبه 26 اسفند 1386, 20:54 عصر
با #C چندان آشنا نیستم، ولی به نظر میاد کدی که به این صورت اجرا میشه، Update عنصر مربوط به GUI را در داخل Thread اصلی برنامه انجام میده. من از نحوه عملکرد Invoke اطلاع خاصی ندارم. آیا بعد از فراخوانی Invoke کنترل بالافاصله به خط بعد منتقل میشه، یا تا زمان اجرای کد اختصاص داده شده به Delegate صبر میکنه، بعد کنترل به خط بعد میر؟ اگر حالت دوم باشه، یعنی عملا کد بالا یک برنامه Multi-threaded رو تبدیل به یک برنامه Single-thread میکنه. چون با اجرای کد فوق، Thread مربوط متوقف میشه تا Update مربوط به ListBox در داخل Thread اصلی انجام بشه، بعد به کار خودش ادامه میده.
اگر همچین چیزی درست باشه، پیشنهاد میکنم که از روش های دیگه ایی برای Update کنترلهای GUI استفاده کنید، مثلا ارسال یک پیام ویندوز به Thread اصلی.

sinpin
یک شنبه 26 اسفند 1386, 23:20 عصر
به نظر میاد کدی که به این صورت اجرا میشه، Update عنصر مربوط به GUI را در داخل Thread اصلی برنامه انجام میده.
حقیقت اینه که عملی که در DoWork انجام میشه در واقع در یک thread جداگانه و مستقل از UI Thread و یا بقولی در پشت زمینه انجام میشه.
شاید بشه گفت BackgroundWorker در واقع نوعی encapsulation برای انجام کارهای مالتی تردینگ ساده است.

_______________________
در مورد این مثال هدف صرفا یک آشنایی مختصر در نحوه ی استفاده از delegate ها جهت دستکاری عناصر UI یک ترد در ترد دیگر بود اما در واقع نیازی به اینکار نبود و کد زیر هم دقیقا همونکار رو انجام میده :


BackgroundWorker worker;
delegate void MyDelegate(string s);

private void Form1_Load(object sender, EventArgs e)
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged );
}

void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
listBox1.Items.Add("ASync"+e.ProgressPercentage.ToString());
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 10; i++)
{
worker.ReportProgress(i);
System.Threading.Thread.Sleep(500);
}
}

vcldeveloper
یک شنبه 26 اسفند 1386, 23:59 عصر
حقیقت اینه که عملی که در DoWork انجام میشه در واقع در یک thread جداگانه و مستقل از UI Thread و یا بقولی در پشت زمینه انجام میشه.
اینو میدونم. مسئله اینه که آیا متد Invoke بصورت Asynchronous اجرا میشه یا نه. اگر Asynchronous نباشه، Worker Thread باید با هربار اجرای Invoke و فراخوانی Delegate متوقف بشه تا کد زیر توسط Delegate اجرا بشه:

listBox1.Items.Add(s);
در مثال بالا این توقف قابل صرف نظر هست، ولی اگر Worker Thread در حال انجام یک پردازش سنگین باشه و از طرفی آپدیت GUI هم به سادگی همین یک خط کد نباشه، عملا اجرا برنامه بصورت Multi-threaded تفاوتی با اجرای آن بصورت Single-thread نمیکنه.
پیشنهاد استفاده از پیغام های ویندوز هم به همین دلیل بود. وقتی پیامی توسط PostMessage از Worker Thread به Thread اصلی برنامه ارسال میشه، Worker Thread منتظر Thread اصلی نمیمونه، بلکه بالافاصله کار خودش رو ادامه میده. پیام در صف مربوط به پنجره دریافت کننده پیام، مثلا فرم اصلی برنامه، باقی میمونه تا توسط اون پنجره پردازش بشه. مثلا زمانی که پیام مربوط به عدد 2 در فرم در حال نمایش هست، Worker Thread در حال محاسبه عدد 6 هست.