PDA

View Full Version : سوال: مشکل با background worker



SHD.NET
شنبه 09 دی 1391, 17:02 عصر
سلام . چرا نمیشه توی بک گاند ورکر دستوراتی از قبیل دستورات زیر نوشت ؟


listbox1.listindex = x

کلا من هرچی آبجکت توش می نویسم اررو میده

ممنون

SHD.NET
شنبه 09 دی 1391, 18:51 عصر
آقا کسی جواب مارو نمیده ؟

amirzandi
شنبه 09 دی 1391, 19:04 عصر
باید از Delegate استفاده کنید.

فرید نجفلو
شنبه 09 دی 1391, 20:29 عصر
احتمالا شما با مشکل IllegalCrossThread مواجه می شید
راحت رین را اینه که جای داخل فرم مثلا تو لود بنویسید:
CheckForIllegalCrossThreadCalls = false;

راه دیگه ای هم اصولی تر هست Invoke کردن دستوراته ولی فکر نکنم به خاطر پیچیدگیش خوشتون بیاد:چشمک:

RamezanBeik
یک شنبه 10 دی 1391, 09:52 صبح
احتمالا شما با مشکل IllegalCrossThread مواجه می شید
راحت رین را اینه که جای داخل فرم مثلا تو لود بنویسید:
CheckForIllegalCrossThreadCalls = false;

راه دیگه ای هم اصولی تر هست Invoke کردن دستوراته ولی فکر نکنم به خاطر پیچیدگیش خوشتون بیاد:چشمک:
این بدترین کاری هست که می شه انجام داد و برنامه رو در حالت بن بست که شاید هیچوقت نتونی دلیلش رو پیدا کنی قرار می ده.

RamezanBeik
یک شنبه 10 دی 1391, 09:53 صبح
در مورد Cross Thrrading بحث زیاد شده یه سرچ تو همین سایت کنی مطالب خوبی پیدا می کنی
برای حل مشکلت باید از Invoke استفاده کنی

SHD.NET
یک شنبه 10 دی 1391, 11:18 صبح
میشه چندتا تاپیک شما معرفی کنین . چون تا حالا با background w کار نکردم

ممنومنننننممنمنمنمن

mousa1992
یک شنبه 10 دی 1391, 11:49 صبح
سلام
اول خاصیت WorkerReportProgress رو برابر true قرار میدی تا بتونی در حال اجرای background عملیاتی رو انجام بدی
خب فرض کن thread شما در طول برنامه اجا میشه در این حالت شما دستوراتی رو که شرایط بررسی میکنن و تصمیم گیری انجام میده رو در رویداد DoWork مینویسی
به نتیجه دلخواهت که رسیدی( از همونجا نمیتونی به اشیا thread اصلی برنامه دسترسی داشته باشی) ، با استفاده از متد ReportProgress)( یک عدد رو به عنوان ReportProgress پاس میدی که اونو میتونی از رویداد ProgressChanged بخونی و عملیات مورد نظرتو همونجا انجام بدی. خب تا اینجا کارتو تا حدی راه میندازه چیز خاصی نداره یکم باهاش کار کنی یاد میگیری ی نمونه هم برات میذارم(صرفا جهت اشنایی :D)



private void Form1_Load(object sender, EventArgs e)
{
bgw.WorkerReportsProgress = true;
bgw.RunWorkerAsync();
}

private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 10; i++)
{
object obj = "Counter:" + i;
Thread.Sleep(600);
bgw.ReportProgress(i * 10, obj);
}
}

private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
this.Text = e.UserState as string;
}


اینجا در متد ReportProgress ی عدد و یک شی ارسال میکنم و در رویداد ProgressChanged اونارو میگیرم و دیگه هر کاری دوز داری انجام بده :P
ی نکته : اگه BackGround شما قرار نیست تا پایان برنامه ادامه پیدا کنه ینی کارش تموم میشه شما میتونی از رویداد RunWorkerComplete هم استفاده کنی
موفق باشی

فرید نجفلو
یک شنبه 10 دی 1391, 13:20 عصر
کدی که دوستمون mousa1992 (http://barnamenevis.org/member.php?252440-mousa1992) دادن کاملا بیانگر نحوه کنترل نخ ها نیست
چون طبق اون کد شما کار ها رو به جز در اون رویداد bgw_ProgressChanged انجام بدید و مهمترین نکته یعنی Invoke هم ذکر نشده

یک فرم جدید به همراه دو دکمه ، یک لیست باکس و یک بک گراند ورکر ایجاد کنید
کد ها رو به شکل زیر بنویسید:
(بعد از کلیک هر یک از دکمه ها سعی کنید با فرم بازی کنید مثلا فرم رو جا به جا کنید یا آیتم های لیست رو انتخاب کنید)



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

private void button2_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
CreateList();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
CreateList();
}

private void CreateList()
{
for (int i = 1; i <= 20; i++)
{
System.Threading.Thread.Sleep(1000);//کدی جهت مختل کرد کار نخ جاری
if (this.InvokeRequired)
this.Invoke((Action<string>)AddItem, i.ToString());
else
AddItem(i.ToString());
}
}

private void AddItem(string Item)
{
listBox1.Items.Add(Item);
}



نتیجه:
دکمه اول به راحتی و بدون ایجاد مزاحمت به گرافیک و پاسخ گویی فرم کار می کنه اما دکمه دوم ...!

---------------
نکات:
سعی کنید هیچ وقت کار ها رو داخل روال رویداد ها ننویسید ، اون ها رو به متد ها و توابع بشکنید

خط this.InvokeRequired :
این خط بررسی میکنه که اگه نخ جاری چیزی غیر از نخ اصلی فرم (که توانایی کار با کنترل ها رو داره) باشه متد مورد نظر رو داخل نخ فرم اجرا می کنه در غیر این صورت به حالت عادی استفاده میشه

توجه کنید که با زدن دکمه اول عملا ما دو نخ (نخ اصلی یا نخ فرم و نخ بک گراند ورکر) خواهیم داشت اما نکته اینجاست که متد AddItem در هر صورت (دکمه اول یا دوم) در داخل نخ فرم اجرا میشه

حالت جالب1:
خط مربوط به Sleep رو به داخل متد AddItem انتقال بدید در این حالت چیزی که مشاهده میشه حالتی بین تک نخی و چند نخی هست
نه به اندازه چند نخی روان کار میکنه و نه به اندازه تک نخی عدم پاسخ گویی داره (البته هیچ تضمینی وجود نداره که پاسخ گویی در سطح بالا یا پایین بمونه)
پس نوشتن کدها در جای مناسب حین برنامه نویسی چند نخی از اهمیت ویژه ای بر خورداره

حالت جالب2:
با همون کد اولیه بعد یا قبل از خط Sleep این خط رو هم اضافه کنید:

Application.DoEvents();


عمل کرد دکمه دوم جالب خواهد بود