PDA

View Full Version : نمایش Progress Bar بصورت Marquee



mr.sirwan
شنبه 22 آذر 1399, 21:57 عصر
سلام و درود
دوستان بنده میخوام موقع اجرای دستورات دیتابیس، یه فرم با پراگرس بار داخلش نمایش بدم بصورت Marquee و اصلا روند و درصد پیشرفت برام مهم نیست چون اصلا درصد پیشرفت قابل اندازه گیری نیست. روش های زیادی با استفاده از backgroundworker وجود داره ولی من نمیخوام توی تمامی متدهام بیام و بکگران ورکر نیو کنم و متد یا دستوراتم رو به DoWork پاس بدم، من یه چیز خیلی راحت و ساده میخوام که داخل بدنه متدهام، ابتدای هر متد یه فانکشنی صدا بزنم که بیاد و پراگرس بار رو برای کاربر نمایش بده و در پایان متدها یه فانکشن دیگه ای صدا بزنم که کارش بستن فرم پراگرس بار هستش

حالا برای اینکار من اومدم یه کلاس تعریف کردم به این شکل:
public static class LoadingProgress
{
private static Thread _LoadingScreenThread;
private static LoadingForm _ls;
private static bool _shown = false;
private static Form _parent;

public static void ShowLoadingScreen(Form parent = null)
{
_parent = parent;

Initiate();
}

private static void Initiate()
{
if (_LoadingScreenThread == null)
{
_LoadingScreenThread = new Thread(new ThreadStart(DoShowLoadingScreen));
_LoadingScreenThread.SetApartmentState(ApartmentSt ate.STA);
_LoadingScreenThread.IsBackground = true;
_LoadingScreenThread.Start();
}
}

public static void CloseLoadingScreen()
{
//Thread.Sleep(50);
if (_ls != null && _ls.InvokeRequired)
{
_ls.Invoke(new MethodInvoker(CloseLoadingScreen));
}
else
{
if (_shown)
{
_shown = false;
Application.ExitThread();
}

try
{
if (_LoadingScreenThread != null)
_LoadingScreenThread.Interrupt();

ActivateParentForm();
_ls?.Close();
_ls?.Dispose();

_LoadingScreenThread = null;
}
catch
{ }
}
}

private static void ActivateParentForm()
{
if (_parent != null)
{
if (_parent.InvokeRequired)
_parent.Invoke(new Action(() =>
{
_parent.Activate();
}));
else
_parent.Activate();
}
}

private static void DoShowLoadingScreen()
{
_ls = new LoadingForm();
_shown = true;
try
{
_ls.TopMost = true;
_ls.ShowDialog();
}
catch
{
}
}
}


همونطور که معلومه داخل کلاس یه ترد ایجاد میشه برای نمایش فرم پراگرس بار، این کلاس تا حدودی کار منو راه مینداخت حالا بماند که یکسری مشکلات و ارور ها هم میده حین اجرا ولی به خاطر همون ارور ها، بخش catch مربوط به try هارو خالی گذاشتم و هیچ اکسپشنی ازشون دریافت نمیکنم، اما همین امروز شروع کرد داخل دیباگر خود ویژوال ستودیو یه سری ارورهارو بهم نمایش دادن، که دوتاشونو میذارم. البته ناگفته نماند که این ارور ها فقط داخل دیباگر و در حالت دبیاگ بهم نمایش داده میشن و UI برنامه و خود فرم پراگرس بار، به مراتب داره کندتر میشه تا جایی که ارور رو بهم نمایش میده ولی توی حالت ریلیز گویا مشکلی وجود نداره و برنامه هم با کندی مواجه نمیشه.

اینم ارورهایی که میگیرم:

ارور اول:
Managed Debugging Assistant 'DisconnectedContext' : 'Transition into COM context 0x1a36328 for this RuntimeCallableWrapper failed with the following error: The callee (server [not server application]) is not available and disappeared; all connections are invalid. The call did not execute. (Exception from HRESULT: 0x80010012 (RPC_E_SERVER_DIED_DNE)). This is typically because the COM context 0x1a36328 where this RuntimeCallableWrapper was created has been disconnected or it is busy doing something else. Releasing the interfaces from the current COM context (COM context 0x1a36270). This may cause corruption or data loss. To avoid this problem, please ensure that all COM contexts/apartments/threads stay alive and are available for context transition, until the application is completely done with the RuntimeCallableWrappers that represents COM components that live inside them.'



ارور دوم:

Managed Debugging Assistant 'ContextSwitchDeadlock' : 'The CLR has been unable to transition from COM context 0x20692f8 to COM context 0x20693b0 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this problem, all single threaded apartment (STA) threads should use pumping wait primitives (such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.'


حالا در رابطه با ارور ها میدونم داره از طولانی شدن یه عملیاتی شکایت میکنه ولی نمیدونم و نمیتونم بفهمم که چه عملیاتیه که طولانی هست، چون واقعیتش من اصلا عملیات انچنانی انجام نمیدم، فقط سلکت توسط دستورات Linq هستش، و داخل پروفایلر اس کیو ال که نگاه میکنم ببینم کوئری های اضافه ای اجرا نشن، خیر هیچ کوئری اضافه ای اجرا نمیشه و هر کوئری کمتر از 0.5 ثانیه و طولانیترینشون 1.5 ثانیه طول میکشه اجرا بشه، خب حالا که مشکلی از طرف دستورات اس کیو ال نیست، پس به این نتیجه میرسم که مشکل از خود پراگرس بار و مربوط به تردی هستش که داخلش وجود داره

حالا چندتا سوال:
1. چون در حالت ریلیز این ارور ها وجود ندارن و مشکلی هم ظاهرا از بابت کندی سرعت پیش نمیاد، آیا این مشکل رو بذارم همینجوری بمونه و نیازی نیست برطرفش کنم؟
2. آیا این روش نمایش پراگرس بار روش خوب و بهینه تری داره؟ شاید باور نکنید ولی دغدغه این پراگرس بار به اندازه کل این نرم افزاره منو پیر کرده

اگر کسی در این رابطه و این مشکل تجربه ای داره و تونسته حلش کنه لطفا راهنمایی بفرمایید

mr.sirwan
شنبه 29 آذر 1399, 17:34 عصر
مثل اینکه چاره ای جز ویرایش تمامی متدهام و قراردادن دستورات داخلشون توی background worker ندارم :ناراحت::اشتباه: و این خودش یه جور دوباره کاری و دوباره بازنویسی متدها هست و خیلی هم طاقت فرساست، چون باید از نو همه شونو تست بگیرم که بعد از اضافه کردن background worker جایی ارور یا مشکلی پیش نیاد

daniyaltjm
شنبه 29 آذر 1399, 18:47 عصر
سلام قبلا یادمه برای یک دیکشنری با بکگراند ورکر یه همچین چیزی درست کردم که زمانی که کلمه ایی داره جستجو میشه یک دونه ازین سیرکل پراگرس ها بچرخه ....

152698

152699

152700

mr.sirwan
شنبه 29 آذر 1399, 21:31 عصر
ممنون دوست عزیز ولی بنده میخواستم تا جایی که امکان داره از بک گراندورکر استفاده نکنم، چون همونطور که گفتم من قبلا متدهام رو نوشتم و تست شده هستن، اگه بخوام از بک گراندورکر استفاده کنم باید همه شونو بازنویسی کنم، من دنبال یه راه ساده تر بودم که فقط لازم بود در ابتدای متد، دستور نمایش پراگرس بار رو بنویسم و در انتهای متد هم دستور مخفی کردن پراگرس بار
ولی اینجور که پیداست چاره ای نیست و باید از بک گراند ورکر استفاده کنم

daniyaltjm
شنبه 29 آذر 1399, 21:47 عصر
ممنون دوست عزیز ولی بنده میخواستم تا جایی که امکان داره از بک گراندورکر استفاده نکنم، چون همونطور که گفتم من قبلا متدهام رو نوشتم و تست شده هستن، اگه بخوام از بک گراندورکر استفاده کنم باید همه شونو بازنویسی کنم، من دنبال یه راه ساده تر بودم که فقط لازم بود در ابتدای متد، دستور نمایش پراگرس بار رو بنویسم و در انتهای متد هم دستور مخفی کردن پراگرس بار
ولی اینجور که پیداست چاره ای نیست و باید از بک گراند ورکر استفاده کنم

حالا اگه اول متد دستور نمایش رو بنویسی و بعد عملیات دستور پنهان کردن رو چطور میشه؟:متفکر:

mr.sirwan
شنبه 29 آذر 1399, 22:02 عصر
حالا اگه اول متد دستور نمایش رو بنویسی و بعد عملیات دستور پنهان کردن رو چطور میشه؟:متفکر:

یه همچین چیزی میشه:
public void DoSomeTimeConsumingStuff()
{
LoadingProgress.ShowLoadingScreen();

// اینجا دستورات موردنظر رو مینویسی که قراره زمانبر باشن

LoadingProgress.CloseLoadingScreen();
}

در واقع توی کلاس LoadingProgress داریم از thread استفاده میکنیم برا اینکه برنامه فریز نشه و پراگرس بار دایره ایمون مدام در حال چرخش باشه، حالا دستورات اصلی متد میتونه بصورت synchronous
اجرا بشن و الزامی در کار نیست که حتما توسط Task.Run و یا با استفاده از ترد اجرا بشن

daniyaltjm
شنبه 29 آذر 1399, 23:34 عصر
یه همچین چیزی میشه:
public void DoSomeTimeConsumingStuff()
{
LoadingProgress.ShowLoadingScreen();

// اینجا دستورات موردنظر رو مینویسی که قراره زمانبر باشن

LoadingProgress.CloseLoadingScreen();
}

در واقع توی کلاس LoadingProgress داریم از thread استفاده میکنیم برا اینکه برنامه فریز نشه و پراگرس بار دایره ایمون مدام در حال چرخش باشه، حالا دستورات اصلی متد میتونه بصورت synchronous
اجرا بشن و الزامی در کار نیست که حتما توسط Task.Run و یا با استفاده از ترد اجرا بشن

فکر کنم استاندارد ترین کار همین بکگراند ورکر و تررد هست یعنی راه دیگه ای فکر نکنم باشه پس بهتره تغییرات رو انجام بدی...

pe32_64
یک شنبه 30 آذر 1399, 22:18 عصر
سلام
دوست عزیز
راحت ترین راه استفاده ار task هستش.
در مورد api اون تحقیق کنید و یادش بگیرید. فعلا ساده ترین و بهترین راه هستش.

Mahmoud.Afrad
سه شنبه 02 دی 1399, 02:29 صبح
یه همچین چیزی میشه:
public void DoSomeTimeConsumingStuff()
{
LoadingProgress.ShowLoadingScreen();

// اینجا دستورات موردنظر رو مینویسی که قراره زمانبر باشن

LoadingProgress.CloseLoadingScreen();
}

در واقع توی کلاس LoadingProgress داریم از thread استفاده میکنیم برا اینکه برنامه فریز نشه و پراگرس بار دایره ایمون مدام در حال چرخش باشه، حالا دستورات اصلی متد میتونه بصورت synchronous
اجرا بشن و الزامی در کار نیست که حتما توسط Task.Run و یا با استفاده از ترد اجرا بشن


اون خطی که متد SetApartmentState را فراخوانی میکنه رو فعلا کامنت کن ببین نتیجه چیه.



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

mr.sirwan
چهارشنبه 03 دی 1399, 10:10 صبح
اون خطی که متد SetApartmentState را فراخوانی میکنه رو فعلا کامنت کن ببین نتیجه چیه.



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


ممنون جناب افراد، اون خط رو کامنت کردم در حال حاضز اروری نمیده حالا ببینم بعدا چی پیش میاد، تشکر از شما

mr.sirwan
دوشنبه 02 فروردین 1400, 16:06 عصر
دوستان جدیدا یه کد دیگه پیدا کردم، داخلش به جای اینکه توسط دستور form.Showdialog فرم مربوط به پراگرس بار رو نمایش بده از application.run استفاده شده و در حال حاضر قشنگ کار میکنه، ولی برام سوال بود که این دستور application.Run در دراز مدت که برنامه در حال اجراست روی سیستم کاربر و تقریبا برای هر عملی که انجام میده نیازه که پراگرس بار بهش نمایش داده بشه، آیا مشکلی از بابت پرفرمنس روی کامپیوتر بوجود میاره؟
نکته ای هم که وجود داره اینه که بعد از هر بار نمایش پراگرس بار، آبجکت فرم پراگرس بار close و null میشه