PDA

View Full Version : مانیتور کردن متغیر داخل یک کلاس که توسط Background Worker اجرا شده



hamed jalili
چهارشنبه 05 بهمن 1390, 12:00 عصر
با سلام ،

دوستان من با استفاده از Background worker یک تابع را داخل یک کلاس اجرا می کنم ، این تابع مقدار یک متغیر Public و Global را داخل کلاس تغییر می دهد . با استفاده از Report Progress می خواهم مقدار این متغییر را در یک Progress bar نشان بدهم . از کد زیر استفاده کردم ولی هیچ Progress ی نشان داده نمی شود.



Reasoning_Engine RE = new Reasoning_Engine();

void Run_Reasoning_Background_Worker_DoWork(object sender, DoWorkEventArgs e)
{
RE.Run_Reasoning();
Run_Reasoning_Background_Worker.ReportProgress(RE. Rotation_Angle);
}


void Run_Reasoning_Background_Worker_ProgressChanged(ob ject sender, ProgressChangedEventArgs e)
{
Rotation_Progress_bar.Value = e.ProgressPercentage;
}




کسی میتونه راهنماییم کنه که ایراد کار کجاست ؟

amir3321
چهارشنبه 05 بهمن 1390, 14:13 عصر
از کدت زیاد سر در نیاوردم ببین این لینک (http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx) مشکلت رو حل می کنه

hamed jalili
چهارشنبه 05 بهمن 1390, 16:13 عصر
کد من که پیچیده نبود .

اون لینک ی که شما داده بودین ، تقریبا همین کار رو انجام میده با این تفاوت که در آنجا متغیری که Progressbar بر اساس اون کار میکنه در داخل همان کلاسی است که Background Worker رو اجرا میکنه ولی اینجا متغیر در داخل کلاس دیگری قرار داره .

gwbasic
چهارشنبه 05 بهمن 1390, 22:13 عصر
همانطور که می دونید از Backgeoundworker برای انجام کار زمان بر استفاده می شه که احتمالا متد Run_Reasoning برای شما کار زمانبری رو انجام می ده. اما کدی رو که نوشتید باعث می شه ایتدا این کار زمانبر انجام بشه و وقتی کار این متد تمام شد شما مقدار Rotation_Angle رو دارید Report می کنید در نتیجه این Report‌فقط یک بار اتفاق می افته و مقدار Rotation_Angle رو در Value پراگرس بار نمایش می ده.
شما باید داخل متد مقدار Progress‌رو Report کنید.

برای آشنایی بیشتر به آموزشی که در امضام هست مراجعه کنید

hamed jalili
پنج شنبه 06 بهمن 1390, 10:07 صبح
ممنون از راهنماییتون ؛

با انتقال RE.Run_Reasoning به بعد از Run_Reasoning_Background_Worker.ReportProgress باز هم مشکل من حل نشد .
آموزشی رو هم که لطف کرده بودین ، مطالعه کردم ، در همان مثال شما ، فرآیند زمان گیر در داخل همان Function DoWork انجام میشه و شما می توانید Report Progress را همان جا فراخوانی کنید ، ولی کل فرآیند من داخل یک کلاس کاملا جدا انجام میگیره که با صدا زدن Run_Reasoning شروع به کار میکنه ، متغییری که من قصد مانیتور کردن آن را دارم داخل این کلاس تغییر میکنه و تغییرات در چندین موقعیت مختلف صورت میگیره .
از Report Progress هم در داخل آن کلاس نمی تونم استفاده کنم ، چون در آن کلاس Background worker ی که برای اجرای این کلاس استفاده کرده ام ، تعریف نشده است در نتیجه نمی توانم از داخل کلاس Report Progress بکنم .


دوستان راه حلی به نظرتون میرسه ؟

gwbasic
پنج شنبه 06 بهمن 1390, 17:50 عصر
عرض من هم همین بود اون متد مربوط به کلاستون باید از backgroundworker آگاه باشه. راه های زیادی وجود داره می تونید پراپرتی ای در سطح کلاس Reasoning_Engine از جنس backgroundworker تعریف کنید و قبل از صدا زدن متد Run_Reasoning مقدار این پراپرتی رو برابر backgroudworker جاریتون قرار بدید به این شکل دسترسی به backgroundworker در متدتون وجود داره و مشکل حل می شود.
و راه دیگه که وابستگی کمتری ایحاد می کنه این می تونه باشه که شما در setter مربوط به پراپرتی Rotation_Angle یک raise event ای انجام بدید مثلا با نام Rotation_AngleChangedValue و سپس داخل فرم باید این رویداد رو هندل کنید و عمل report progress‌رو در پشت این رویداد بنویسید به این شکل دیگه کلاستون مستقل از UI عمل میکنه و دیگه هیچ وابستگی ای وجود نخواهد داشت

hamed jalili
پنج شنبه 06 بهمن 1390, 20:58 عصر
روش دوم ، روش جالبی به نظرم رسید ، میشه لطفا کمی بیشتر توضیح بدین ( اگه با کد توضیح بدین خیلی ممنون میشم )

gwbasic
پنج شنبه 06 بهمن 1390, 21:50 عصر
یک پروزه شامل فرمی که ProgressBar و یک کلاس شبیه کلاستون با متد و پراپرتی مد نظرتون (هرآنچه که لازمه و جزء صورت مسئله هست) رو اینجا بذارید تا براتون کاملش کنم

hamed jalili
جمعه 07 بهمن 1390, 00:04 صبح
باعث زحمتتون میشه !!

لطفا اگه امکانش هست با روش دوم تغییرات رو اعمال کنید . ممنون از لطفتون .

gwbasic
شنبه 08 بهمن 1390, 20:15 عصر
مراحل زیر را باید انجام دهید:

1- تعریف ValueEventArgs برای فرستان مقدار از طریق event

public class ValueEventArgs : EventArgs
{
public int Value { get; set; }
public ValueEventArgs()
{
}
public ValueEventArgs(int value)
{
Value = value;
}
}


2- تعریف event برای تک تک پراپرتی ها و rasied‌کردن آن در setter پراپرتی مربوطه

private int rotation_Angle;
public int Rotation_Angle
{
get { return rotation_Angle; }
set
{
if (rotation_Angle != value)
{
rotation_Angle = value;
OnRotation_AngleValueChaned(value);
}
}
}
public event EventHandler<ValueEventArgs> Rotation_AngleValueChanged;
private void OnRotation_AngleValueChaned(int value)
{
if (Rotation_AngleValueChanged != null)
Rotation_AngleValueChanged(this, new ValueEventArgs(value));
}
private int move_Step;
public int Move_Step
{
get { return move_Step; }
set
{
if (move_Step != value)
{
move_Step = value;
OnMove_StepValueChanged(value);
}
}
}
public event EventHandler<ValueEventArgs> Move_StepValueChanged;
private void OnMove_StepValueChanged(int value)
{
if (Move_StepValueChanged != null)
Move_StepValueChanged(this, new ValueEventArgs(value));
}

حالا هر وقت پراپرتی های مورد نظر ما تغییر کنند event مربوطه raised‌خواهد شد و ما می توانیم عمل نمابش آن را انجام دهیم

3- در فرم مورد نظر event های مورد نظر را subscribe‌می کنیم:

Reasoning_Engine RE = new Reasoning_Engine();
public Form1()
{
...
RE.Rotation_AngleValueChanged += new EventHandler<ValueEventArgs>(RE_Rotation_AngleValueChanged);
RE.Move_StepValueChanged += new EventHandler<ValueEventArgs>(RE_Move_StepValueChanged);
...
}


4- پشت متدهای مربوط به event ها با استفاده از backgroundworker عمل نمایش مقدار پراپرتی ها را انجام می دهیم. دقت شود که ما در Thread‌دیگری قرار داریم و باید از backgroundworker‌برای عمل نمایش استفاده کنیم

void RE_Move_StepValueChanged(object sender, ValueEventArgs e)
{
Run_Reasoning_Background_Worker.ReportProgress(e.V alue, "Move_Step");
}
void RE_Rotation_AngleValueChanged(object sender, ValueEventArgs e)
{
Run_Reasoning_Background_Worker.ReportProgress(e.V alue, "Rotation_Angle");
}




5- در نهایت نوشتن متد progress‌ مربوط به backgroundworker

void Run_Reasoning_Background_Worker_ProgressChanged(ob ject sender, ProgressChangedEventArgs e)
{
if (e.UserState.ToString() == "Move_Step")
Move_Progress.Value = e.ProgressPercentage;
else
Rotation_Progress.Value = e.ProgressPercentage;
}