PDA

View Full Version : کار با Thread و خطا در هنگام اجرای Thread



ali_autumnal
سه شنبه 30 شهریور 1389, 23:00 عصر
باسلام

من تو پروژه ای که نوشتم نزدیک به 18 تا comboBox دارم و میخوام نام کلیه رنگ های سیستم رو تو اونها قرار بدم.

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

برای این منظور متغیر ها و توابعی که تعریف کردم به شکل زیر هستش:

متغیرهای عمومی:



private System.Threading.Thread thMain;
private ComboBox[] cmb;
private string[] ColorName;


سازنده فرم:



public FSetting()
{
InitializeComponent();

cmb = new ComboBox[]
{
cmbColorbtnDelete,cmbColorbtnEdit,cmbColorbtnNew,c mbColorbtnSave,cmbColorbtnSearch,cmbColorForm,
cmbColorLabel,cmbColorTabControlColor1,cmbColorTex tBox,cmbColorbtnDeleteText,cmbColorbtnEditText,
cmbColorbtnNewText,cmbColorbtnSaveText,cmbColorbtn SearchText,cmbColorTextBoxText,cmbColorTabControlC olor2,
cmbColorTabItem,cmbColorTabItemSelect
};

ColorName = Enum.GetNames(typeof(KnownColor));
Array.Sort(ColorName);



هنگام لود:




thMain = new System.Threading.Thread(new System.Threading.ThreadStart(SetItemComboBox));
thMain.Start();

و تابعی که میخوام تو یه نخ جداگانه ای انجام بشه:



private void SetItemComboBox()
{
foreach (string item in ColorName)
{
foreach (ComboBox c in cmb)
c.Items.Add(item);
}
thMain.Abort();
}



و خطای صادر شده ای که در قسمت قرمز رنگ مشخص کردم



Cross-thread operation not valid: Control 'cmbColorbtnDelete' accessed from a thread other than the thread it was created on.




متشکر
علی پاییزی

sinashahab
سه شنبه 30 شهریور 1389, 23:13 عصر
من میتدی هستم ولی یه چیزایی خونده بودم که باید از delegate استفاده کنی.

ولی یکی از دوستانم اینو بهم پیشنهاد داد که درست هم کار می کرد :

Control.CheckForIllegalCrossThreadCalls = false;

با تشکر
سینا شیری همدانی:بامزه:

:لبخند:

salehbagheri
سه شنبه 30 شهریور 1389, 23:35 عصر
cmb و ColorName رو در یک متد جداگانه مقدار دهی کنید.

mohsen_csharp
سه شنبه 30 شهریور 1389, 23:37 عصر
با سلام
راه اصولی اینکه باید از Invoke استفاده کنی

ali_autumnal
چهارشنبه 31 شهریور 1389, 09:54 صبح
cmb و ColorName رو در یک متد جداگانه مقدار دهی کنید.

الان pc ايم و پروزه ام دمه دست نيست اما چك ميكنم.

بنظر شما مشكل در مقدار دهي cmb هست؟ آخه همين مقدار دهي رو هم تو همون تابع قبل از حلقه انجام داده بودم اما باز همين خطا صادر شده بود.

Saeed_m_Farid
چهارشنبه 31 شهریور 1389, 10:32 صبح
فکر کنم من ده ها بار شاهد پرسیدن این مورد در فروم بودم!
شما نمی تونید از Thraed جداگانه (یعنی Thraed ای غیر از Thread اصلی فرم) با عناصر روی فرم کار کنید : Thread-Safe Calls to Windows Forms Controls (http://msdn.microsoft.com/en-us/library/ms171728.aspx)؛ برای اینکار می تونید از BackgroundWorker (http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx) و یا روش delegate و Callback (که نمونه بحث مطرح شده در این زمینه رو می تونید اینجا (http://www.barnamenevis.org/forum/showthread.php?t=197197)ببینید.) استفاده کنید.
یعنی یه چیزی مثل کد زیر باید بنویسید و در نهایت هم SetItemComboBox_ThreadSafe رو استفاده کنید:
delegate void SetItemComboBoxCallback(ComboBox cbox);
private void SetItemComboBox(ComboBox cbox)
{
foreach (string item in ColorName)
{ cbox.Items.Add(item); }
}
private void SetItemComboBox_ThreadSafe();
{
foreach (ComboBox cb in cmb)
{
if (cb.InvokeRequired)
{
SetItemComboBoxCallback sicb = new SetItemComboBoxCallback(SetItemComboBox)
this.Invoke(sicb, new object[] { cb });
}
else
SetItemComboBox(cb)
}
}
پ.ن. : البته من ابن کد رو تو Notepad نوشتم و تست نکردم، خواستم کلیت مطلب رو برسونم!

ali_autumnal
چهارشنبه 31 شهریور 1389, 15:08 عصر
فکر کنم من ده ها بار شاهد پرسیدن این مورد در فروم بودم!
شما نمی تونید از Thraed جداگانه (یعنی Thraed ای غیر از Thread اصلی فرم) با عناصر روی فرم کار کنید : Thread-Safe Calls to Windows Forms Controls (http://msdn.microsoft.com/en-us/library/ms171728.aspx)؛ برای اینکار می تونید از BackgroundWorker (http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx) و یا روش delegate و Callback (که نمونه بحث مطرح شده در این زمینه رو می تونید اینجا (http://www.barnamenevis.org/forum/showthread.php?t=197197)ببینید.) استفاده کنید.
یعنی یه چیزی مثل کد زیر باید بنویسید و در نهایت هم SetItemComboBox_ThreadSafe رو استفاده کنید:
delegate void SetItemComboBoxCallback(ComboBox cbox);
private void SetItemComboBox(ComboBox cbox)
{
foreach (string item in ColorName)
{ cbox.Items.Add(item); }
}
private void SetItemComboBox_ThreadSafe();
{
foreach (ComboBox cb in cmb)
{
if (cb.InvokeRequired)
{
SetItemComboBoxCallback sicb = new SetItemComboBoxCallback(SetItemComboBox)
this.Invoke(sicb, new object[] { cb });
}
else
SetItemComboBox(cb)
}
}
پ.ن. : البته من ابن کد رو تو Notepad نوشتم و تست نکردم، خواستم کلیت مطلب رو برسونم!


دستت درد نکنه.
دقیقا درست فرمودید.

ali_autumnal
چهارشنبه 31 شهریور 1389, 15:51 عصر
من میتدی هستم ولی یه چیزایی خونده بودم که باید از delegate استفاده کنی.

ولی یکی از دوستانم اینو بهم پیشنهاد داد که درست هم کار می کرد :


با تشکر
سینا شیری همدانی:بامزه:

:لبخند:


هرچند اطلاعات زیادی ندارم اما احتمال میدم کار اصولی نباشه!!

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

یعنی فرم لود میشه براحتی، بعد چند لحظه جهت اعمال تغییرات زمان میبره.
در حالی که قبلا فرم لود نمیشد کمی مکث میکرد بعد با کل تغییرات لود میشد. من میخوام در یک لحظه همه این اتفاق ها بیفته.
متشکر