السلام عليكم
إضافة إلى الميزات و التحسينات التي وضعتها شركة Microsoft بشأن تقنية الـ .NET جاءت ميزة اللاتزامنية asynchronous
بشكل سهل للغاية , مما يمكن المبرمجين من إقتناء هذه التقنية بشكل أفضل مما سبق.
العنصر BackgroundWorker هو الـ Component الجاهز لتأدية هذه المهام اللاتزامنية Multi Threading .
بحيث يعمل على Thread منفصل عن الـ UI Thread مهام واجهة البرنامج, لذلك هو يعمل في الخفاء background .
هذا العنصر له أحداث يسّرت من تقسيم العمل فيه بشكل واضح و جلي وهو سهل للغاية , لنبدأ الرحلة.
فكرة عن الدرس: سنقوم بإجراء عملية حسابية مطولة و سنرى كيف نوظفها عن طريق هذا العنصر,بحيث
يمكِنُنا من العمل على خانة نصية أخرى , بينما يقوم هو بمتابعة العملية حتى النهاية ثم يعود بالناتج في خانةٍِ أخرى.
أولاً متطلبات العمل : حمل المثال ستجد مشروع باسم Start-BackgroundWorker
يتكون من StatusStrip يضم عارضة مرئية ProgressBar و عنوان Label , كذلك على النموذج زرين و خانتين نصيتين و BGW
الـ BGW هو عنصر BackgroundWorker تم إدراجه من القائمة ToolBox و اختصرنا اسمه الى BGW,
كذلك أضفنا مهام لهذا المشروع ,لتُمكِنُكَ من كتابة النصوص البرمجية في مكانها الصحيح .
شاهد الصورة التوضيحية , بالضغط المزدوج على المهمة الاولى ستذهب إلى حدث تحميل النموذج.
في حدث التحميل Form Load Event.....
من الخصائص المهمة للعنصر BackgroundWorker خاصية WorkerReportsProgress و WorkerSupportsCancellation,
و هما ذوات قيمة منطقية كقيمة راجعة Boolean Value في حالة تمكين الخاصية الاولى سنكون قادرين على إستخدام الـ ProgressBar مع هذا العنصر
أما الخاصية الثانية WorkerSupportsCancellation فإنها تمكِنُنا من إلغاء المهمة إذا رغبنا في ذلك.
سنجعل كلتا الخاصيتين تساويان القيمة True .
'Enable Report Progress BGW.WorkerReportsProgress = True 'Enable Cancellation BGW.WorkerSupportsCancellation = True
في حدث الضغط على الزر btnStart .....
ستجد بعض النصوص مكتوبة من قبل, لإعطاء سرعة في إنجاز المشروع,وهي لا تؤثر على فهم الدرس.
المطلوب منا في هذا الحدث أن ننادي إجراء RunWorkerAsync للعنصر BackgroundWorker هذا الاجراء
يقوم بتشغيل المهمة,وقد يحتوي على ممرر أو دون ممرر , سنقوم بتشغيل هذ الاجراء
بحيث نممر له قيمة رقمية ليذهب بها إلى حدث أخر, سنتعرف عليه فيما بعد, بهذا الشكل يتم تفعيل المهمة.
'Run async process, High number for good example. BGW.RunWorkerAsync(90000)
في حدث الضغط على زر الإلغاء btnCancel .....
سنقوم بإلغاء المهمة عن طريق السلوك CancelAsync بحيث نتحقق قبل الالغاء بالخاصية المنطقية IsBusy
فإن كانت المهمة في معمعة العمل فإن هذه الخاصية ستعود بالقيمة True غير ذلك ستعود
بالقيمة False في حالة أن المهمة اُنجزت أو تعطلت بظهور خطءٍ ما Error . بهذا الشكل
'If the backgroundWorker is busy, still working then If Me.BGW.IsBusy Then 'Cancel the process BGW.CancelAsync() End If
في الحدث DoWork التابع للعنصر BackgroundWorker ......
عندما نقوم بتشغيل المهمه عن طريق RunWorkerAsync فإن هذا الأمر يقوم بتفعيل الحدث DoWork.
في هذا الحدث سنقوم بإنشاء عنصر من نوع BackgroundWorker بهذا الشكل
'Create backgroundWorker object Dim worker1 As BackgroundWorker = _ CType(sender, BackgroundWorker)
إن عملية الـ casting اي التحويل هي العملية الشرعية الوحيدة للتعامل مع هذا العنصر
فكما هو منوه عليه في MSDN أنه ليست هنالك إمكانية بإستخدام العنصر بشكل مباشر
وإنما نقوم بعملية إنشاء عنصر أخر ثم نستخدم التحويل CType لنمرر sender على اساس backgroundWorker
ثم نستخدم الخاصية Result التابعة للقالب DoWorkEventArgs التي من خلالها نستطيع جلب ناتج
العملية بعد الانتهاء, سيكون بهذا الشكل إستخدامها.
'Return Result by passing (Number(e.Argument),Object, and event (e)) e.Result = LoopLong(e.Argument, worker1, e)
حيثُ LoopLong إجراء نحن أنشأناهُ وفيه النصوص البرمجية اللازمة للعملية الحسابية كمثال فقط.
الممررات , الممرر الاول e.Argument هي القيمة التي أسندناها في حدث الضغط على الزر, وهي 90000
الممرر الثاني هو العنصر الذي صنعناه للتو وهو worker1 , أما الممرر الثالث فهو
القالب DoWorkEventArgs , لانه الاجراء LoopLong لكي يتوافق مع هذه التقنية, لابد أن يضم
ممررين إضافيين هما ممرر من نوع BackgroundWorker و الحدث DoWorkEventArgs .
في حدث الـ ProgressChanged .....
هذا الحدث يتم تفعيله عندما نقوم بمناداة السلوك ReportProgress .
الذي سنستخدمه لاحقاً.
في هذا الحدث سنقوم بإسناد القيمة العائدة من الممرر ProgressChangedEventArgs إلى الـProgressBar
بهذا الشكل.
'Assign the Percentage Process to ProgressBar Object. ProgressBar1.Value = e.ProgressPercentage
في الوظيفة LoopLong .....
الان هذا هو عملك , كمبرمج أو مطور ولك وظيفة بطيئة العمل بحكم الوظائف التي تؤديها فينبغي عليك أن تجعلها تعمل في الخفاء
حتى لا تؤثر على واجهة البرنامج مما ينتج عن ذلك عملية التجمد أو عدم الاستجابة للمستخدم ...
نبدأ بتعريف الوظيفة و ممررتها.
Public Function LoopLong(ByVal count As Integer, _ ByVal worker As BackgroundWorker, ByVal e As DoWorkEventArgs) As String()
هذه الوظيفة تممرر لها ثلاثة قيم الاولى count القيمة الرقيمة التي نرسلها من الممرر e.Argument من الحدث DoWork
الممرر الثاني هو العنصر الذي قمنا بتعريفة بعملية التحويل Casting وهو worker1
أما الممرر الثالث فهو القالب DoWorkEventArgs و الذي يمثلها e في الحدث DoWork.
كما تلاحظ هذه الوظيفة تعود بقيمة مصفوفية String() نصية النوع.
في بداية هذه الوظيفة سنقوم بإنشاء متغير نصي النوع ليقوم بإرجاع عائد العملية الحسابية في
هذه الوظيفة بهذا الشكل.
'Declare a string var for holding the final result. Dim Result As String = String.Empty
ثم نقوم بعمل حلقة , لتقوم بعملية حسابية, بالمتغير I إلى قيمة الممرر count و تتخطى عشر أرقام في كل حلقة بهذا الشكل.
'Loop until i reachs the count value For i As Integer = i To count Step 10
ثم نقوم بإسناد قيمة نصية مع قيمة الـ I للمتغير Result بهذا الشكل
'Assign some string & numbers to Result var Result &= "This is Number : " & i.ToString
ثم نعود إلى أول السطر (كعملية تنسيق الكتابة فقط) بهذا الشكل
'Assign new line to Result var. Result &= vbCrLf
ثم سنقوم بالتحقق هل تم إلغاء المهمة عن طريق الخاصية CancellationPending إذا كان كذلك
سنقوم بإرجاع قيمتين الاولى فارغة لتنظيف الخانة النصية و الثانية إخبارية لإعلام المستخدم
ان المهم قد اُلغيت. بهذا الشكل.
'If cancel is pending then (user Pressed cancel button)
If worker.CancellationPending Then
'Return the below strings
Return New String() {"", "Operation was cancelled by user..."}
End Ifبعدها سنقوم بتفعيل الحدث ProgressChanged عن طريق إسناد قيمة للإجراء ReportProgress العائد للممرر worker
'Return percentage of the total task will processing. worker.ReportProgress((i / count) * 100)
في الاخير عندما ننتهي من الحلقة for سنقوم بإرجاع القيمة النصية المصفوفية بهذا الشكل.
Next
'If the process completed successfully
'Return the string array result back to callers
Return New String() {Result, "Operation done successfully.."}ستعود القيمة Result للخانة النصية و القيمة الثانية للعنوان في الـ StatusBar Strip
في الحدث RunWorkerCompleted ...
هذا الحدث يتم تفعيله عندما يقوم الحدث DoWork بإرجاع قيمةٍ ما.
هذا الحدث يقع مرة واحدة فقط سواءً إكتملت المهمة أو لا فإنه سيتم تنفيذه في نهاية المطاف.
سنقوم في هذا الحدث بإختبار الخاصية Error هل هي ليست فارغة,لنقوم بإنشاء خطأ يظهر للمستخدم
بهذا الشكل.
'If there's an error then throw it If Not e.Error Is Nothing Then Throw New Exception(e.Error.ToString) End If
في الاخير سنقوم بعرض القيم العائدة عن طريق الخصاصية Result في كل من الخانة النصية و العنوان
بهذا الشكل.
'Finally get the result() as an array. Me.txtResult.Text = e.Result(0).ToString Me.lblResultProcess.Text = e.Result(1).ToString
بما أن الوظيفة LoopLong ترجع قيمة نصية مصفوفية Array فإني بذلك أستطيع أن أعطي كل خانة, القيمة العائدة لها.
هذا واللهُ أعلى و أعلم.






