PDA

View Full Version : سوال: افزایش مقدار ProgressBar در زمان انجام یک پردازش سنگین (جلوگیری از freeze شدن UI ) ؟



salars
دوشنبه 13 شهریور 1391, 18:16 عصر
سلام به همه دوستان

من یه برنامه سیلورلایت دارم که دکمه ای به نام Run داره که با فشرددن اون برنامه شروع به یک پردازش سنگین میکنه و یه ProgressBar داره که باید در طی این پردازش به جلو حرکت کنه اما با فشردن دکمه Run صفحه Freeze میشه و بعد از اینکه پردازش تموم شد ProgressBar پر شده نشون داده میشه ک جالب نیست و کاربر فک میکنه ک برنامه قاتی کرده و سعی میکنه مروگر رو EndProcess کنه.

چجوری میشه از Freeze شدن UI جلوگیری کرد ؟

ممنون از همگی.

taghvajou
دوشنبه 13 شهریور 1391, 22:06 عصر
سلام به همه

این چیزی که شما میخوای ربطی به بنده خدا پروگرس بار نداره، بلکه مسئله به دست گیری ثرد مجری است. همون طوری که شما گفتی و میدونیم، ثردی که در حال اجراست وظیفه اش دو اپلیکیشن هستش که فقط یه پروسه رو اجرا میکنه لذا تا وقتی تسکی که دستشه تموم نشه نمیره سراغ دو اپلیکیشن ائونت.

پس باید شما کار رو به صورت آسینک و در پشت سر اجرا کنیم.

یه نکته برای انتخاب روش کار هست. اگه کار به زمان وابسته است از ثرد های تایمری استفاده بکنیم. اما اگه کار تعداد مشخص یا شرط مشخص داره از کارگر پشت صحنه یا بک گراند ورکر که حدس بنده اینه که شما نوع دوم مدنظرت هست چرا که اشاره به پردازش سنگین کردین:

1- شما واسه این کار یه ثرد بک گراند ورکر (BackgroundWorker) درست کن و کار رو با تابع دو ورک اون بسپار که وقتی شروع بشه کار رو انجام بده.
private BackgroundWorker bworker = new BackgroundWorker();

2- بعد مقدار ویژگی ماکزیمم پروگرس بار رو معادل تعداد دفعاتی که این پروسس انجام قرار بشه، قرار بده.

3- بعد یه رویداد پیشرفت تغییر یافته یا بک گراند ورکر پروگرس چنجد داریم تو بک گراند ورکر، به ازای هر بار اجرای کاری که میخوای، به مقدار پر شده پروگرس باز یه دونه اضافه کن. البته ویژگی اعلام نتیجه رو باید ترو کنی>

4- تو محلی که میخوای کار شروع بشه، دستور شروع ناهمزمان یا همون استارت آسینک رو اجرا کن. که کار شروع بشه

5 - نهایتا با استفاده از رویداد اتمام کار یا بک گراند ورکر کامپلیتد اتمام کار رو جشن بگیر.

salars
سه شنبه 14 شهریور 1391, 11:36 صبح
سلام به همه

این چیزی که شما میخوای ربطی به بنده خدا پروگرس بار نداره، بلکه مسئله به دست گیری ثرد مجری است. همون طوری که شما گفتی و میدونیم، ثردی که در حال اجراست وظیفه اش دو اپلیکیشن هستش که فقط یه پروسه رو اجرا میکنه لذا تا وقتی تسکی که دستشه تموم نشه نمیره سراغ دو اپلیکیشن ائونت.

پس باید شما کار رو به صورت آسینک و در پشت سر اجرا کنیم.

یه نکته برای انتخاب روش کار هست. اگه کار به زمان وابسته است از ثرد های تایمری استفاده بکنیم. اما اگه کار تعداد مشخص یا شرط مشخص داره از کارگر پشت صحنه یا بک گراند ورکر که حدس بنده اینه که شما نوع دوم مدنظرت هست چرا که اشاره به پردازش سنگین کردین:

1- شما واسه این کار یه ثرد بک گراند ورکر (BackgroundWorker) درست کن و کار رو با تابع دو ورک اون بسپار که وقتی شروع بشه کار رو انجام بده.
private BackgroundWorker bworker = new BackgroundWorker();

2- بعد مقدار ویژگی ماکزیمم پروگرس بار رو معادل تعداد دفعاتی که این پروسس انجام قرار بشه، قرار بده.

3- بعد یه رویداد پیشرفت تغییر یافته یا بک گراند ورکر پروگرس چنجد داریم تو بک گراند ورکر، به ازای هر بار اجرای کاری که میخوای، به مقدار پر شده پروگرس باز یه دونه اضافه کن. البته ویژگی اعلام نتیجه رو باید ترو کنی>

4- تو محلی که میخوای کار شروع بشه، دستور شروع ناهمزمان یا همون استارت آسینک رو اجرا کن. که کار شروع بشه

5 - نهایتا با استفاده از رویداد اتمام کار یا بک گراند ورکر کامپلیتد اتمام کار رو جشن بگیر.



سلام
ممنون از اینکه پاسخ دادی .

اما من قبلن از این استفاده کردم :



BackgroundWorker worker = new BackgroundWorker();
//this is where the long running process should go
worker.DoWork += (o, ea) =>
{
//no direct interaction with the UI is allowed from this method
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(50);
}
};
worker.RunWorkerCompleted += (o, ea) =>
{
//work has completed. you can now interact with the UI
SampleIndicator.IsBusy = false;
};
//set the IsBusy before you start the thread
SampleIndicator.IsBusy = true;
worker.RunWorkerAsync();



اما پردازش من که باید در قسمت DOWork قرار بگیره شامل کار مستقیم با UI هسته (یه سری محاسبات و مثلن ریختن نتایج در یک RichTextBox و ادامه محاسبات تا اتمام کار) و همونطور که میدونیم تو قسمت DOWork نمیشه کدی قرار داد که مستقیمن با UI کار کنه ، تو یه مقاله خوندم که از

Dispatcher.BeginInvoke(() => action);


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

بازم ممنون.:چشمک:

taghvajou
سه شنبه 14 شهریور 1391, 12:07 عصر
خب تقریبا آره، ما مثل وین فرم که دستور application.doevent() داشتیم، تو سیلورلایت نداریم. در نتیچه تغییر رو نمیشه کامل دید.

اگه بخوای هم مستقیما مقدار شو عوض کنین اکسپشن میندازه که به اون ثرد دسترسی نداری.


اما از یه لحاظ هم نه!
وقتی داریم از رویداد انجام (completed) استفاده میکنیم یه جوری دستور میدیم به پروسس جی یو آی که این اتفاق رو رندر کن. شاید کافی باشه اسلیپش کرد یا اینکه یه تایمر بذار وسط کار اون بعد کل کار رو با ورکر انجام نده بلکه بخش بخش بسپار این تایمر اون رو استارت و استاپ کنه.

انجام ندادم هنوز. اگه لازم شد ندا بدین باهم یه همفکری بیشتر بکنیم و سمپل دربیاریم. اگه نتیجه هم داد لطفا باز ما رو بی خبر نذار

taghvajou
سه شنبه 14 شهریور 1391, 17:36 عصر
سلام به همه

با توجه به اینکه احساس کردم مطلب قبلی ابتر باقی گذاشتم، یه سمپل کوچولو آماده کردم.

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

بازم اگه سوالی بود در خدمتم.

salars
چهارشنبه 15 شهریور 1391, 13:16 عصر
مشکله هنوز هسته. در هر حال مرسی آقا
ممنون.

taghvajou
چهارشنبه 15 شهریور 1391, 13:35 عصر
اگه مشکل هنوز هست، خوب بگین شما کجاش گیر میکنین یا کد رو بده ببینیم چه خبر؟ در هر حال مرسی یعنی اینکه ادامه ندیم؟ این همفکریها واسه خود ما هم خوبه برای اینکه، ممکنه یه روزی بنده و سایر دوستان هم به چنین مشکلی بر بخوریم. وقتی شما حل نشده ولش میکنی بعدا گریبانگیرمون خواهد شد.
ضمنا برای تشکر هم از اون دکمه پایین هر پست می تونین خیلی راحت استفاده کنین