تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
برنامجك أكثر تجواباً أكثر تفاعلاً مع BackgroundWorker
#1
كاتب الموضوع : مهند بيسك أوغلو

بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاته...
أنا اسمي مهند وهيبة, جديد على هذا المنتدى الرائع..فأحببت أن أشارك في هذا الموضوع المتواضع
لا أعرف إن كان الموضوع قد طُرح سابقاً, ولكن سأتوكل على الله وابدأ بالموضوع .
============================================
BackgroundWorker عبارة عن مكون موجود في نطاق الأسماء:
System.ComponentModel.BackgroundWorker
لماذا استخدم BackgroundWorker ؟
لنفترض أن لديك برنامج يقوم البحث بين الملفات ولكن مهمة البحث ليست الغرض الأساسي من البرنامج فهناك العديد من المهام التي يمكن للمستخدم أن يقوم بها ,فهل من المعقول أن ينتظر المستخدم انتهاء عملية البحث حتى يقوم بتصفح مهام برنامجك الأخرى؟؟ وخصوصاً أن عملية البحث هذه تأخذ وقتاً طويلاً من الانتظار! أن واثق من استخدامك للأسلوب السابق سيفقد احترام المستخدمين لبرنامجك , وأول عملية سيقوم بها بعد TaskManager سهي إزالة جذور برنامجك من حاسوبه!!! بل الأسوأ من ذلك :بافتراض أن العملية هي عملية نسخ أو حذف ملفات ضخمة لن يستجيب برنامجك لضغطات زر الفأرة على زر "إلغاء الأمر"!!إنها بلا شك مصيبة ضخمة!وأزيد من المصائب مصيبة(جعلها الله مجرد مصائب برمجية لنا ولكم) وهي مشكلة واجهة المستخدم UI التي ستصبح
صمٌ بكمٌ عميٌ بدون استخدام BackgroundWorker
============================================
BackgroundWorker في الخدمة
بعد هذه المقدمة الطويلة المملة ! قد تكون عرفت المشكلة وخطورتها والآن هيا نتوكل على الله ونبدأ بتعلم BackgroundWorker .
أولاً: إضافة BackgroundWorker إلى مشروعك
تستطيع إضافة هذا المكون برمجيا عن طريق إنشاء نسخة منه
ومن ثم قنص أحداثه بواسطة AddHandler أو WithEvents على مزاجك.
وهناك طريقة أسهل منها وهي من قائمة الأدوات في قسم Components ومن ثم أضفه إلى المشروع.
============================================
مثال : برنامج قبل BackgroundWorker
لكي تذوق جمال BackgroundWorker يجب عليك أن تعرف كيف كانت الحال قبله
فعلى سبيل المثال:لدي نافذة Form وفيها Progressbar و زر "إلغاء الأمر"
بكل بساطة يقوم البرنامج بزيادة قيمة ال"Value" لل" Progressbar " عند الضغط على زر "ابدأ" أما الزر "إلغاء الأمر" فإنه يقوم بإعطاء قيمة " Cancelled" = trueوبعد الانتهاء من العملية يظهر
النتيجة على عنوان النافذة أي إذا تم إلغاء العملية أو لا.
ابدأ مشروع جديد أضف إلى النافذة :
o ProgressBar rg
o Command Button :cmdCancel
o Command Button:cmdStart
o BackgroundWorker:BGW

و إليك الكود كاملاً:


كود :
Public Class Form1
Dim Cancelled As Boolean
Private Sub cmdStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdStart.Click
DoSomeWork()
FinallyWork()
End Sub
Private Sub AddValue(ByVal i As Integer)
prg.Value = i
End Sub
Private Sub FinallyWork()
If Cancelled Then
Me.Text = "نم إلغاء العملية"
Else
Me.Text = "انتهى التحميل بنجاح"
End If
End Sub
Private Sub DoSomeWork()
'هذه حلقة دوران لزيادة القيمة
For i As Integer = 0 To 100
'مع أني متأكد من أنها لن تنفع ولكن سأكتبها
If Cancelled Then
Exit Sub
End If
AddValue(i) 'Progressbar زيادة قيمة
System.Threading.Thread.Sleep(100) 'تأخير العملية قليلاً
Next
End Sub

Private Sub cmdCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdCancel.Click
Cancelled = True
End Sub

End Class
============================================
آمل ألا تصادفك مشاكل عند تجربة الكود, على كل حال بعد أن تشغل البرنامج وتضغط على الزر cmdStart يبدأ ProgressBar بزيادة قيمته والآن حاول
خلال الزيادة أن تضغط زر cmdCancel أو حاول تحريك النافذةَ!
النتيجة أكيد سيئة جداً !! ولكن أطمئنك هذه الحالة ستزول إن شاء الله بعد استخدامك للBGW أو BackgroundWorker
لنبدأ أولاً بفهم الكود من الأول وإجراء التعديلات اللازمة:
نلاحظ أن عندنا 3 إجراءات:
o AddValue: يقوم بإسناد قيمة ال ProgressBar عن طريق المتغير i
o : DoSomeWork يقوم بحلقة دوران عند بداية كل دورة يتأكد من Cancelled و يستدعي الإجراء AddValue
o FinallyWork : يظهر النتيجة المناسبة حسب قيمة Canceled
و بالنسبة إلى الزر : CmdStart يقوم باستدعاء الإجراءين DoSomeWork,FinallyWork أما الزر CmdCancel يقوم بإسناد قيمة Cancelled إلى True
هذا هو الكود بكل بساطة. ...والآن سيدخل BGW إلى الساحة فلنر ما هي التعديلات التي سنقوم بها
============================================
وإليك الكود كاملاً:


كود :
Public Class Form1
'Dim Cancelled As Boolean لم أعد أحتاج إليك
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
BGW.WorkerReportsProgress = True
BGW.WorkerSupportsCancellation = True 'من أجل أن يدعم إلغاء العملية

End Sub

Private Sub cmdStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdStart.Click
DoSomeWork()
' FinallyWork() لم أعد أحتاجه
End Sub
Private Sub cmdCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdCancel.Click
'يقوم هذا الحدث بإلغاء العملية
'BGW_RunWorkerCompleted ومن ثم ينتقل إلى
BGW.CancelAsync()
End Sub
Private Sub AddValue(ByVal i As Integer)
prg.Value = i
End Sub

Private Sub DoSomeWork()
'كل الخرابيط التي كانت هنا استبدلناها بهذه الجملة
BGW.RunWorkerAsync() 'الان تبدأ المهمة في خلفية البرنامج
End Sub


Private Sub BGW_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
'هذه حلقة دوران لزيادة القيمة
For i As Integer = 0 To 100
'مع أني متأكد من أنها لن تنفع ولكن سأكتبها
'If Cancelled Then
' Exit Sub
'End If
'الأن ستنفع إن شاء الله ولكن بعد القيام ببعض التعديلات
If BGW.CancellationPending Then
e.Cancel = True
Exit Sub
End If
' AddValue(i) 'Progressbar زيادة قيمة
'الآن سنزيد القيمة ولكن بغير طريقة
BGW.ReportProgress(i)
System.Threading.Thread.Sleep(100) 'تأخير العملية قليلاً
Next
End Sub

Private Sub BGW_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BGW.ProgressChanged
'BGW_DoWork في الحدث
' BGW.ReportProgress تلاحظ أننا استدعينا
'الذي بدوره يستدعي هذا الحدث ويمرر له وسيطة نسبة التقدم
AddValue(e.ProgressPercentage)
End Sub

Private Sub BGW_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BGW.RunWorkerCompleted
'FinallyWork هذا الحدث بدل
'يتم استدعاءه عند الانتهاء من العملية
If e.Cancelled Then
Me.Text = "نم إلغاء العملية"
Else
Me.Text = "انتهى التحميل بنجاح"
End If
End Sub
End Class
أول شيء سنقوم به هو إزالة المتغير العام Canceled
نأتي الآن إلى الإجراء DoSomeWork ماذا سنفعل!!سنستبدل كل الكلام المكتوب فيه بجملة واحدة هي BGW.RunWorkerAsync()
ماذا تفعل هذه الجملة السحرية ؟! بكل بساطة تقوم باستدعاء الحدث BGW_DoWork الذي يقوم بالعمل الثانوي إن كان بحث عن ملفات أو تحميل ملف من الانترنيت أو تعامل مع قاعدة بيانات ....الخ إذا فحلقة الدوران التي كتبناها في الإجراء DoSomeWork سنكتبها هنا مع إجراء بعض التعديل
نسيت أن أقول لك أن تسند قيمة BGW.WorkerSupportsCancellation = True و ذلك من أجل أن تدعم إمكانية إلغاء العملية
نرجع إلى BGW_DoWork , للتحقق من أن العملية تم إلغائها أم لا سنضع جملة الشرط التالية :


كود :
If BGW.CancellationPending = true Then
e.Cancel = True
Exit Sub
End if
سؤال : ما هو الذي سيجعل قيمة CancellationPending تساوي True ؟؟
الجواب:هو الإجراء البسيط BGW.CancelAsync()
سؤال ثاني: لماذا أسندت قيمة Cancel إلى True ؟ مالفائدة منها؟؟
الجواب: سترى الجواب في السطر التالي
هناك حدث آخر أريد أن أعرفك عليه ! وهو الحدث BGW_RunWorkerCompleted , ولكن متى يستيقظ هذا الحدث!؟
يستيقظ أو يحدث في هذه الحالات
o إتمام العملية:أي وصل تنفيذ البرنامج إلى السطر End Sub في الحدث BGW_DoWork
o إلغاء العملية: أي عندما نسند قيمة e.Cancel إلى True في الحدث BGW_DoWork
o حدوث خطأ :مثل أن تستدعي الإجراء BGW.RunWorkerAsync()بينما BGW.isBusy=True
إذاً من المنطقي أن نستدعي الإجراء BGW. CancelAsync() من خلال الحدث CmdCancel_Click
حتى لا تختلط عليك الأمور بالنسبة لإلغاء العملية :أعرض عليك هذا الملخص البسيط:
1- حتى تتمكن من إلغاء العملية التي تعمل في الخلفية يجب عليك إسناد قيمة BGW. WorkerSupportsCancellation إلى True
2- حتى تجعل CancellationPending إلى True يجب أن تستدعي الاجراء BGW. CancelAsync
3- في الحدث BGW_DoWork يجب عليك أن تتأكد من قيمة CancellationPending فإذا كانت True اجعل e.Cancel=true
4- لتعرف إذا كانت العملية تم إلغاءها أم لا فعليك بالحدث BGW_RunWorkerCompleted من خلال الخاصية e.Cancelled المتعلقة بالخاصية e.Cancel المشار إليها في البند السابق
ولكن مهلاً أين كود تعديل قيمة ProgressBar ؟
يسعدني ان اقول لك أن هذا الكود انتقل مع عائلته الكريمة إلى الحدث ProgressChanged ليصبح الكود هكذا:
AddValue(e.ProgressPercentage) ..أوه !! ماهذا الشيء الغريب الذي بين القوسين؟؟!!؟! إنه يا عزيزي المبرمج نسبة التقدم المئوية
إني لا أطلب منك يامهند الترجمة بل أطلب إليك ما معناه في البرمجة!
اوه...حسناً أريد ان أقول لك لو كان عندك كود ينسخ ملفات من مجلد
فبماذا ستتعلق قيمة النسبة المئوية؟ أكيد..بعدد الملفات المنسوخة إلى عدد الملفات الكلية.وكذلك الحال بالنسبة لكود تحميل ملف أو بحث في قاعدة بيانات, أما في برنامجنا الحالي ستتعلق بعدد دورات الحلقة المئة أي بعد كل دورة سيزيد ProgressPercentage مقدار 1
ولكن متى سينطلق الحدث ProgressChanged ؟
مثل بساطة انطلاق الحدث DoWork سينطلق هذا الحدث عند استدعاء الطريقة BGW.ReportProgress التي تتطلب وسيطة واحدة من نوع Integer , أما أين سنستدعي هذه الطريقة ؟ في الحدث BGW_DoWork وهكذا يصبح الحدث BGW_DoWork بشكل كامل:


كود :
For i As Integer = 0 To 100
If BGW.CancellationPending Then
e.Cancel = True
Exit Sub
End If
BGW.ReportProgress(i)
System.Threading.Thread.Sleep(100)
Next
هناك ملاحظة أريد أن أقولها لك هي لن تستطيع استدعاء الحدث BGW.ReportProgress إلا عندما تجعل قيمة BGW.WorkerReportsProgress = True
========================================
خاتمة...
"ربنا لا تؤاخذنا إن نسينا أو أخطأنا"
ليس هناك موضوع لا أخطاء وخاصة إذا كان كاتب هذا المقال من المبتدئين في عالم الدوت نيت فلذلك أرجو أن تستقبلوا موضوعي بصدر رحب وإن كنت قد أضعت وقتك في هذا المقال فأرجو أن تسامحني وأنا أعتذر منك أشد الاعتذار أما إذا شعرت أنك قد استفدت ولو بشيء قليل فما أطلب منك إلا أن تقول لي "جزاك الله خيراً " فتكون قد بالغت في العطاء
...أخوك:مهند وهيبة
.....والله ولي التوفيق


الملفات المرفقة
.rar   AfterBGW.rar (الحجم : 62.32 ك ب / التحميلات : 104)
.rar   BeforeBGW.rar (الحجم : 60.35 ك ب / التحميلات : 70)
}}}}
تم الشكر بواسطة:


المواضيع المحتمل أن تكون متشابهة .
الموضوع : الكاتب الردود : المشاهدات : آخر رد
  [مقال] دمج كل ملفات برنامجك الى ملف تنفيذى واحد ali.alfoly 25 7,933 02-12-16, 04:04 PM
آخر رد: ali.alfoly
  حصرياً ( إطبع على الوورد من خلال برنامجك ) ( شرح بالصور ) m.sami.ak 20 1,999 20-08-16, 11:53 PM
آخر رد: الوادي
  الاستفادة من بارمترات الاخراج من SQL Server داخل برنامجك ابو ليلى 1 205 20-08-16, 02:16 AM
آخر رد: الوادي
Star [VB.NET] شرح عمل امتداد خاص لبرامجك وجعل برنامجك يقرأ هذة الملفات mohammed_gamal381 22 7,435 01-06-16, 02:55 PM
آخر رد: ابراهيم كركوكي
  طريقة مميزة لعمل إعدادات Setting لحفظ اعدادات برنامجك بدون أكواد kslawy 6 1,671 26-05-16, 12:07 PM
آخر رد: CLARO
  حصرياً على اليوتوب,,, إطبع على الوورد من خلال برنامجك ( شرح بالفيديو ) مبرمج أوتار 5 1,831 15-05-16, 05:06 PM
آخر رد: CLARO
  كيف تجعل برنامجك عالميا و يدعم أكثر من لغة silverlight 5 745 15-05-16, 05:03 PM
آخر رد: CLARO
  موضوع الاستاذ رامي مثال \ لطريقة تفعيل برنامجك عند العميل وتغيير كلمة مرور اRamilove سعود 7 2,068 26-01-16, 08:07 PM
آخر رد: سعود
Question [مثال] كيف تضيف اكثر من لغة الى برنامجك HASAN6.0 3 433 26-11-15, 11:20 PM
آخر رد: hamada558
  كيف تتعامل مع برنامج الإكسيل من برنامجك rinawi 6 1,800 25-06-15, 05:49 AM
آخر رد: Nadir_Nabous

التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم