السلام عليكم و رحمة الله تعالى و بركاته...
قد نحتاج في بعض مشاريعنا البرمجية تنفيد كود بعد انقضاء وقت محدد. هذا الكود لا يحتاج إلى إعادة التنفيذ مرات عديدة فنضعه داخل Timer. من هذا المنطلق يمكننا كتابة دالة بسيطة تحاكي الدالة setTimeout للـ JavaScript. هذه الدالة تستقبل معاملين الأول هو الدالة المراد المناداة عليها وقت انتهاء الوقت المحدد على المعامل الثاني.
الدالة التي سنرى بعد قليل ستعمل بنفس المبدأ أي أنها سترجع بدون انتظار و بعض انقضاء الوقت المحدد سيتم تنفيذ الكود المحدد لها.
// الفئة التي تحتوي الدالة
public class Timeout
{
// تحديد تعريف الدوال التي يمكن المناداة عليها
public delegate void TimeoutMethod();
// تمكن الدالة من المناداة على الدالة المحددة بـ method بعد انقضاء الوقت millis
public static void SetTimeout(int millis, TimeoutMethod method)
{
// انشاء مسلك خاص لتنفيد العملية
System.Threading.Thread thrd;
thrd = new System.Threading.Thread(delegate() {
// انتظار انتهاء الوقت المخصص
System.Threading.Thread.Sleep(millis);
// المناداة على الدالة المحددة
method();
});
// لتفادي تجميد التطبيق وقت غلقه من طرف المستخدم
thrd.IsBackground = true;
// تنفيد الكود في مسلك خاص
thrd.Start();
}
}استخدام الدالة SetTimeout الخاصة بنا سهل جدا :
انتظار ثانية ثم تنفيد كود :
Timeout.SetTimeout(1000, delegate() {
Console.WriteLine("Tick");
});انتظار ثانية ثم المناداة على دالة مستقلة MyMethod حيث يكون تعريف الدالة من دون معاملات void MyMethod() { ... } :
Timeout.SetTimeout(1000, MyMethod);
ملاحظة :
يجب الانتباه إلى أن كود الدالة Timeout.SetTimeout يتم تنفيذه في مسلك خاص و محاولة الوصول إلى مربعات تحكم عبر الكود المحدد للدالة سيرفع استثناء من نوع InvalidOperationException لأن إطار الدوت نت يمنع الوصول إلى مربعات التحكم من مسلك مغاير للمسلك الذي تم إنشاء المربع فيه و ذلك وقت تتبع الأخطاء DEBUG.
مثلا الكود التالي سيرفع استثناء :
Timeout.SetTimeout(5000, delegate {
myForm.Text = "Tick";
});للتمكن من استخدام الدالة Timeout.SetTimeout للوصول إلى مربعات التحكم, يجب أولا كتابة دالة خاصة لهذا الغرض بالشكل التالي :
void SetMyFormText(string txt)
{
// إذا كان المسلك الحالي غير المسلك الذي إنشئ فيه النموذج
if(this.InvokeRequired) {
// استدعاء لنفس الدالة
this.Invoke((MethodInvoker) delegate {
SetMyFormText(txt);
});
// خروج
return;
}
// إذا وصلنا هنا, فنحن في المسلك الصحيح و يمكننا تحديد الخاصية بكل أمان
this.Text = txt;
}ثانيا, استخدام الدالة Timeout.SetTimeout للمناداة على الدالة SetMyFormText :
Timeout.SetTimeout(5000, delegate {
SetMyFormText("Set some text after 5 seconds.");
});يمكن و بكل سهولة زيادة امكانية المناداة على دوال تستقبل معاملات و لكن لتبسيط الموضوع تم تجاهل ذلك.
تحياتي...