اذهب إلى المحتوى

حسام برهان

الأعضاء
  • المساهمات

    215
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    31

كل منشورات العضو حسام برهان

  1. مرحبًا بك في هذه السلسلة الجديدة التي سنتعلّم من خلالها كيف سنتعامل مع إطار العمل Vue.js. هذا الإطار الواعد الذي يُسهّل العمل في تطوير الواجهة الأمامية للتطبيقات Frontend Applications إلى حدّ بعيد. سنتدرّج في هذه السلسلة بشكل سلس، حيث سنتناول موضوعات بسيطة في البداية، ثم ومع تقدّمنا في الدروس سنغطي موضوعات أوسع وأشمل. ستلاحظ وجود تطبيقات بسيطة في كل درس، نشرح من خلالها فكرة أو أفكار محدّدة. ولكن في نهاية السلسلة سنختم بتطبيقين عمليين، يوضّحان معظم الأفكار التي تمّت تغطيتها مسبقًا. هذه السلسلة هي سلسلة تعليمية، الهدف منها هو أن تنطلق مع Vue.js بسهولة ويُسر، وبالتالي فهي ليست سلسلة مرجعيّة شاملة لإطار العمل Vue.js. سأفترض أنّه لديك معرفة جيدة بلغة JavaScript و بـ HTML أيضًا، كما ويُفضّل أن تمتلك معرفة أساسيّة بـ CSS. سنتطرق في هذا المقال إلى النقاط التالية: ماهو إطار العمل framework في JavaScript؟ تطبيقك الأوّل مع Vue.js. إضافة مزايا جديدة لتطبيقنا الأوّل. العمل على حاسوب محلّي. ماهو إطار العمل framework في JavaScript؟ ببساطة و بمعزل عن أي تفاصيل تقنية، يساعدنا إطار العمل عمومًا في إنشاء تطبيقات عصرية حديثة، حيث يحتوي على الأدوات اللازمة لتسهيل حياة المبرمجين في إنشاء تطبيقات معقّدة بزمن قياسي، فلا يحتاج المبرمج أن يستخدم الأسلوب التقليدي القديم في التعامل مع نموذج كائنات المستند DOM باستخدام JavaScript، حيث يمكن باستخدام إطار العمل التعامل مع العناصر في DOM بشكل قياسي ومجرّد وسهل إلى حدّ بعيد. بدأ العمل مع JavaScript بتطوير مكتبات شهيرة مثل jQuery و Mootools، حيث سهّلت مثل هذه المكتبات العمل مع JavaScript على نحو كبير، وقلّلت مشاكل التوافقية بين المتصفحات المختلفة التي لم تكن تتبع معيارًا موحدًّا. تطوّرت الأمور بعد ذلك لتبدأ أُطر عمل متكاملة في الظهور يمكن أن نقسّمها إلى مرحلتين أساسيتين. المرحلة الأولى كانت مع ظهور أُطر عمل مثل Backbone و Ember و Knockout و AngularJS. أمّا المرحلة الثانية وهي المرحلة الحالية فكانت مع أطر عمل مثل React و Angular و Vue. تٌعدّ Vue.js من أحدث أُطر العمل في JavaScript، وهي إطار عمل واعد، يجمع بين السهولة والمرونة والقوة، بالإضافة إلى صغر حجم الملف الخاص بها (فقط 26 كيلو بايت) مما يجعل تحميل صفحات الويب سهلة إلى حد بعيد. سنهتم بالإصدار Vue.js 2 مع التاكيد بأنّ ما سنأخذه هنا يمكن تطبيقه بسهولة في إصدارات لاحقة. تطبيقك الأول مع Vue.js قبل البدء باستخدام Vue.js علينا أن نحصل على الملف الخاص به. لدينا عدّة خيارات لذلك، سأختار أحد أسهل الخيارات وهو الحصول على الملف الخاص بإطار العمل عن طريق شبكة تسليم محتوى CDN، ثم نتحدّث عن الخيارات الأخرى فيما بعد. يمكنك استخدام رابط CDN التالي للحصول على Vue.js؛ الرابط هو unpkg.com/vue@2.6.11/dist/vue.js سنحتاج حاليًا إلى الرابط فقط. انتقل الآن إلى الموقع jsfiddle.net الذي يوفّر بيئة تطوير بسيطة وممتازة لتجريب Vue.js دون تحميل أي شيء على حاسوبك. ستحصل على شكل شبيه بما يلي: انقر على الرابط URL الذي يظهر في القسم الأيسر في الأعلى من النافذة السابقة، بجوار كلمة Resources: بعد نقر الرابط السابق ستحصل على مربّع نص، انسخ فيه رابط CDN السابق، ثم انقر الزر المجاور الذي يظهر على شكل إشارة زائد: نكون بذلك قد أخبرنا بيئة التطوير المصغّرة أنّنا بصدد استخدام الملف الخاص بإطار العمل Vue.js. انسخ الآن شيفرة HTML التالي إلى القسم الخاص بأكواد HTML من الصفحة الرئيسية لموقع jsfiddle: <div id="app"> {{ message }} </div> ثم انسخ شيفرة JavaScript التالية والصقها ضمن القسم الخاص بشيفرات JavaScript في الصفحة الرئيسية الموقع: var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) انقر الآن زر التشغيل Run الموجود في الزاوية اليسرى العليا من الصفحة. إذا نفذت الخطوات السابقة بدقة، ستلاحظ ظهور العبارة Hello Vue! في القسم الأيمن الأسفل من الصفحة. مبارك! لقد بنيت تطبيق Vue.js الأول لك. دعنا الآن نحلّل ما قمنا به حتى الآن. أتوقّع أنّ رُماز HTML الذي استخدمناه سهل وواضح، حيث أنشأنا عنصر div وأسندنا له المعرّف app، ووضعنا ضمن وسمي الفتح والإغلاق له التعبير التالي: {{ message }} هذا التعبير هو الأساس في Vue.js، سنتحدّث عنه بعد قليل. الآن لاحظ معي شيفرة JavaScript التالية: var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) أعتقد أنّ بداية هذه الشيفرة مألوفة، حيث أنّنا نعمل على إنشاء كائن من النوع Vue باستخدام الكلمة المفتاحية new. لاحظ معي ماذا نمرّر إلى النوع Vue: { el: '#app', data: { message: 'Hello Vue!' } } المقطع السابق عبارة عن كائن آخر يُسمى بكائن الخيارات (options instance) يحوي الإعدادات التي نريد أن تكون ضمن كائن Vue.js الجديد. ففي الحقل el (يمثّل أول حرفين من كلمة element أي العنصر) نُسند القيمة '‎#app' والتي تمثّل معرّف عنصر HTML المُستَهدف (في حالتنا هذه هو عنصر div الذي أنشأناه قبل قليل)، أمّا الحقل data فيتم إسناد كائن آخر إليه يحتوي على حقل واحد وهو message وقيمته 'Hello Vue!'. لاحظ أنّ الكلمة 'message' هي نفسها الموجودة ضمن رُماز HTML السابق الموضوعة بحاضنة مزدوجة {{ message }}. وهكذا فعند تنفيذ البرنامج السابق سيعمل Vue على استبدال التعبير {{ message }} ضمن عنصر HTML الذي يحمل المعرّف app بالنص 'Hello Vue!‎' وهذا كلّ شيء. ملاحظة: رغم وجود من يميّز بين الكائن object والنسخة instance، إلّا أنني لا أفرّق بينهما من الناحية العمليّة. لذلك تراني أستخدم الترجمة "كائن" دومًا. حاول الآن إجراء بعض التغييرات على النص السابق، وأعد التنفيذ باستخدام الزر Run لتشاهد التغييرات الجديدة على الخرج. في الحقيقة إنّ ما جرى في هذا المثال يتعدّى عن كونه مجرّد عملية استبدال تعبير برسالة مجهزّة مسبقًا، إن ما يجري من وراء الكواليس هو عملية ربط كامل بين الحقل message الموجود ضمن شيفرة JavaScript وبين التعبير {{ message }} الموجود ضمن رُماز HTML وسنرى كيف ذلك في الفقرة التالية. إضافة مزايا جديدة لتطبيقنا الأول حان الوقت لإجراء بعض التحسينات على تطبيقنا الأول. انتقل إلى قسم HTML وأضف عنصر إدخال نصّي input على النحو التالي: <div id="app"> <input type='text' v-on:input="updateInfo"/> {{ message }} </div> لقد وضعت عنصر الإدخال فوق التعبير {{ message }} مباشرة. الشيء الجديد هنا هي السمة v-on:input وهي بحد ذاتها مكوّنة من قسمين الموجّه directive وهو: v-on والوسيط input المراد تمريره إلى الموجّه. يلعب الموجّه v-on دور مُنصِت حدث event listener. وفي حالتنا هذه فإنّنا نرغب بالإنصات لحدث الإدخال input (معامل [parameter]) لعنصر الإدخال النصي. لاحظ القيمة المُسندة الموجّه: updateInfo وهي بكل بساطة اسم التابع الذي سيتم استدعاؤه في حال تمّ إجراء أي إدخال ضمن عنصر الإدخال النصي من قِبَل المستخدم. سنعرّف هذا التابع الآن. استبدل الشيفرة القديمة الموجودة بالقسم المخصّص لشيفرات JavaScript في الصفحة الرئيسية للموقع بالشيفرة التالية: var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' }, methods:{ updateInfo:function(event){ this.message = event.target.value; } } }) الفرق الوحيد بين المقطعين الجديد والقديم، أنّنا أضفنا القسم methods الذي يتم فيه تعريف جميع التوابع (methods) التي نرغب باستخدامها. واضح أنّنا سنعرّف التابع updateInfo الذي تحدثنا عنه قبل قليل. عرّفنا هذا التابع على أنّه function ومرّرنا إليه الكائن event وهو كائن يحتوي على بيانات الحدث الذي تمّ توليده تلقائيّا بسبب كتابة المستخدم ضمن مربّع النص. العبارة البرمجية الوحيدة الموجودة في هذا التابع هي: this.message = event.target.value; على نحو غريب قليلًا، ترمز الكلمة this هنا إلى الحقل data (المعرّف ضمن نفس كائن Vue.js) والذي يحتوي بدوره على الحقل message. سنوضّح سبب ذلك في درس لاحق. القسم الثاني من العبارة بسيط، وفيه نستخلص البيانات التي أدخلها المستخدم من خلال التعبير event.target.value. جرّب تنفيذ البرنامج الآن بنقر زر Run، ثم حاول كتابة أي شيء ضمن مربع النص، ستلاحظ أنّه سيتم تحديث الرسالة بشكل فوري بالنص الذي تكتبه! العمل على حاسوب محلي إذا لم ترغب أن تعمل على jsfiddle.net يمكنك العمل بالتأكيد في وضع عدم اتصال محليًّا على حاسوبك الشخصي. علينا أوّلًا تنزيل Vue.js عن طريق الرابط https://Vue.js.org/js/vue.js (من الممكن أن يظهر محتوى الملف كاملًا ضمن صفحة عادية في المتصفح، انسخ محتويات الصفحة واحفظها ضمن جديد، سمّه: vue.js). في الحقيقة يمكنك استخدام هذه النسخة لأغراض التطوير البرمجية فقط، أمّا عندما يصبح التطبيق قيد الاستخدام العملي فيُنصح باستخدام النسخة التالية: https://Vue.js.org/js/vue.min.js حصلت على النسختين السابقتين من الموقع الرسمي لإطار العمل Vue.js من الصفحة التالية: https://Vue.js.org/v2/guide/installation.html أنشئ مجلّدًا وسمّه Vue.js-first-app، ثم انسخ ضمن هذا المجلّد ملف vue.js الذي نزّلته قبل قليل. باستخدام محرّر HTML المناسب لك، أنشئ ملف جديد واختر له مثلا الاسم index.html. ثم احفظه في نفس المجلّد السابق بجوار الملف vue.js، وبعد ذلك أضف إليه المحتوى التالي الذي قمت بتجميعه من محتويات التطبيق المحسّن الذي تناولناه في الفقرة السابقة: <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>Vue.js</title> <script src="vue.js"></script> </head> <body> <div id="app"> <input type='text' v-on:input="updateInfo"/> {{ message }} </div> <script type="text/javascript"> var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' }, methods:{ updateInfo:function(event){ this.message = event.target.value; } } }) </script> </body> </html> لاحظ معي أنّنا قد أضفنا مرجعًا لملف vue.js المحلّي عن طريق وسم script ضمن القسم head من المستند، وأضفنا شيفرة JavaScript المسؤولة عن تحديث خرج التطبيق ضمن القسم body من المستند. يمكنك متابعة كتابة تطبيقاتك على هذا النحو، ولو أنّني أفضّل استخدام منصّات مثل jsfiddle.net و codepen.io على الأقل في هذه المرحلة التي نسبر بها أغوار Vue.js. ختامًا تناولنا في هذا الدرس مقدّمة سريعة إلى إطار العمل الواعد Vue.js حيث تعلّمنا كيف نبدأ مع Vue.js وكيف نكتب تطبيقات بسيطة توضّح لنا مدى السهولة والمرونة التي يتمتّع بها إطار العمل هذا. سنتابع عملنا في الدروس اللاحقة لنسبر أغوار Vue.js بشكل سهل ومتدرّج. تمارين داعمة سأزودك في التمرينين التاليين بمسألتين بسيطتين للتدرّب على المفاهيم الموجودة في هذا الدرس. يوجد بعد كل تمرين حل مقترح، حاول ألّا تنظر إلى الحلول المقترحة قبل تقديم حلولك. تمرين 1 استخدم الوسيط click بدلًا من الوسيط input مع الموجّه v-on لكي يستجيب التطبيق عندما ينقر المستخدم على عنصر الإدخال بدًلا من الكتابة داخله وذلك في التطبيق المحسّن الذي تحدثنا عنه قبل قليل. اجعل التطبيق يعرض الرسالة "Clicked!" عندما ينقر المستخدم. .anntional__paragraph { border: 3px solid #f5f5f5; margin: 20px 0 14px; position: relative; display: block; padding: 25px 30px; } الحل المقترح الحل في هذا التمرين بسيط. استبدل الوسيط input بالوسيط clicked ضمن رُماز HTML ثم وفي القسم المخصّص لشيفرة JavaScript، استبدل بالسطر التالي: this.message = event.target.value; السطر: this.message = 'Clicked!'; تمرين 2 في هذا التمرين ستُنشئ تطبيق آلة حاسبة بسيط يقوم بعملية حسابية واحدة وهي جمع عددين. أقترح الواجهة البسيطة التالية: الميزة في هذا التطبيق أنّه إذا بدأ المستخدم بالكتابة في أي مربّع، يجب أن يقوم التطبيق بإيجاد المجموع بشكل فوري أثناء إدخاله الأرقام. لن نقوم في هذا التمرين بالتحقّق من صحة إدخال المستخدم. الحل المقترح طريقة التنفيذ مشابهة جدّا للتطبيقات التي تناولناها في هذا الدرس. سأضيف حقلين إضافيين فقط لتخزين قيمتي المعاملين الأيمن والأيسر لعملية الجمع. شيفرة HTML المقترحة هي: <div id="app"> <input type='text' v-on:input="updateLeftOper"/> <label>+</label> <input type='text' v-on:input="updateRightOper"/> <label>=</label> <label>{{result}}</label> </div> أما شيفرة JavaScript المقترحة فهي على الشكل التالي: var app = new Vue({ el: '#app', data: { result: 0, leftOper: 0, rightOper: 0 }, methods:{ updateLeftOper: function(event){ this.leftOper = parseFloat(event.target.value) this.result = this.leftOper + this.rightOper; }, updateRightOper: function(event){ this.rightOper = parseFloat(event.target.value) this.result = this.leftOper + this.rightOper; } } }) إذا لم تستطع استيعاب الشيفرة السابقة تمامًا فلا بأس، سنتكلم المزيد عن هذه الأمور لاحقًا. اقرأ أيضًا المقال التالي: استخدام Vue.js للتعامل مع DOM النسخة الكاملة لكتاب أساسيات إطار العمل Vue.js
  2. لدي طريقة أسهل. وتقوم بعكس أي شيء: string number; string reversedNumber = ""; Console.Write("Please input your number: "); number = Console.ReadLine(); var set = number.Reverse(); foreach(char c in set) { reversedNumber += c; } Console.WriteLine("Your reversed number is: {0}", reversedNumber);
  3. سنتعرّف في هذا المقال من سلسلة المقالات حول التعامل مع ويندوز 10 على أدوات الصيانة الرئيسيّة الموجودة ضمنيًّا في ويندوز 10. تساهم هذه الأدوات بتحسين وتسريع الأداء العام لنظام التشغيل، بالإضافة إلى اكتشاف بعض الأخطاء المحتملة. من أهم هذه الأدوات: إلغاء تجزئة محركات الأقراص وتحسينها، وتنظيف القرص، وتشخيص الذاكرة لـ Windows. جميع الأدوات السابقة تقع ضمن تصنيف "الأدوات الإدارية في Windows". من الممكن الوصول إلى هذا التصنيف من خلال النقر على زر ابدأ، ومن ثمّ استخدام شريط التمرير للوصول إلى بند "الأدوات الإدارية في Windows". انقر السهم الصغير بجوار البند السابق لعرض الأدوات المتاحة كما في الشكل التالي: أداة "إلغاء تجزئة محركات الأقراص وتحسينها" استخدام شريط التمرير كما يظهر من الشكل السابق للوصول إلى أداء إلغاء تجزئة محركات الأقراص وتحسينها. سيظهر لك شكل شبيه بما يلي: الوظيفة الرئيسيّة لهذه الأداة هو إعادة ترتيب وتنظيم البيانات على القرص الصلب، مما يساهم في زيادة الكفاءة لعمليات القراءة والكتابة من وإلى القرص الصلب، وبالتالي تحسين أداء الحاسوب بصورة عامة. تحتوي نافذة هذه الأداة على بعض الخيارات البسيطة. حيث يظهر من الشكل السابق وجود قائمة من محركات الأقراص المتاحة. بعد اختيار أحدها، يمكن نقر زر "تحليل" لتعمل هذه الأداة على تحليل هذا المحرّك وعرض النسبة المئوية للمساحة التي تحتاج إلى إلغاء التجزئة. أمّا زر "تحسين" المجاور، فسيعمل على البدء بعملية إلغاء التجزئة بشكل فعلي. هناك أيضًا زر "تغيير الإعدادات" لجدولة عمليات إلغاء التجزئة لتحدث تلقائيًّا بشكل يومي أو أسبوعي أو شهري. أنصح، بضبط هذه الإعدادات ليكون معدّل التكرار أسبوعيًّا. أداة "تنظيف القرص" تفيد هذه الأداة في التخلص من الملفات غير الضروريّة التي من الممكن أن توجد نتيجة ملفات البرامج المؤقّتة والتي لم تعد هذه البرامج بحاجة إليها، أو قد تكون ملفات انترنت مؤقتة، أو ملفات البرامج التي تمّ تنزيلها على سبيل المثال. لتشغيل هذه الأداة اختر "تنظيف القرص" من مجموعة "الأدوات الإدارية في Windows" انظر إلى النافذة اليمنى من الشكل التالي: بعد اختيار القرص الذي ترغب بتنظيفه ستبدأ الأداة بتحليل القرص وحساب المساحة الممكن تنظيفها منه كما يظهر في النافذة اليسرى. بعد الانتهاء من تحليل القرص ستظهر النافذة الرئيسيّة لأداة تنظيف القرص كما في الشكل التالي: تعرض النافذة السابقة أماكن وجود الملفات غير الضرورية والتي ستعمل الأداة على حذفها نهائيًّا، كما تعطيك تقريرًا بالمساحة التي ستحصل عليها عند الانتهاء من هذا الإجراء. بالنسبة إلي، تخبرني هذه الأداة بأنّه سيتم تحرير مساحة قدرها 283 ميغا بايت من القرص الصلب الخاص بجهاز الحاسوب لدي، وذلك في حال اختيار جميع المصادر من القائمة الموجودة في الأعلى. أمّا في حال ترك الاعدادات الافتراضيّة كما هي فسأحصل على 46.1 ميغا بايت فقط. في الأحوال العادية ستحصل على رقم أكبر من هذا بكثير. لاحظ وجود زر اسمه "تنظيف ملفات النظام". سيؤدّي النقر على هذا الزر إلى إعادة تشغيل الأداة من جديد، مع التركيز على تحليل ملفات النظام غير الضرورية وذلك للتخلص منها. في كلتا الحالتين سيؤدي النقر على زر "موافق" إلى البدء بعمليّة التنظيف والتي قد تستغرق بعضًا من الوقت بحسب عدد الملفات وحجمها وسرعة الحاسوب لديك. أداة "تشخيص الذاكرة لـ Windows" تُعتبر مشاكل الذاكرة من أصعب المشاكل اكتشافًا وأكثرها إرباكًا. يوفّر ويندوز أداة "تشخيص الذاكرة لـ Windows" لاكتشاف العيوب الكامنة في ذاكرة الحاسوب. لتشغيل هذه الأداة اختر " تشخيص الذاكرة لـ Windows " من مجموعة "الأدوات الإدارية في Windows" لتظهر لك نافذة شبيهة بما يلي: يمكنك البدء فورًا بتحليل الذاكرة بالنقر على خيار "إعادة التشغيل الآن والبحث عن المشاكل" ليعمل نظام ويندوز على إعادة التشغيل الحاسوب، ومن ثمّ وبعد الإقلاع سيشّغل أداة خاصّة لتحليل الذاكرة. أو يمكنك نقر خيار "البحث عن الأخطاء عند تشغيل الكومبيوتر المرة الثانية" ليعمل ويندوز على تشغيل هذه الأداة في الإقلاع التالي للحاسوب. في كلتا الحالتين، ستظهر هذه الأداة التي ستعمل بعد الإقلاع مباشرةً على الشكل التالي: سيتم إجراء اختبار الذاكرة على مرحلتين. الصورة السابقة تظهر تقدّم الفحص في المرحلة الأولى. أمّا بعد إجراء الاختبار للمرحلة الثانية، ستعمل الأداة على إعادة تشغيل الحاسوب تلقائيًّا. بعد إعادة التشغيل وتسجيل الدخول، سيعرض ويندوز تقريرًا حول المشاكل التي قد وجدها في الذاكرة. بالنسبة لي لم أحصل على أيّة مشاكل. الخلاصة تعرّفنا في هذا المقال على كيفيّة التعامل مع بعض أدوات الصيانة والتشخيص في ويندوز. فقد تحدثنا عن كيفيّة الوصول إلى الأدوات الإدارية، وتعلّما كيف نتعامل مع أدوات إلغاء تجزئة محركات الأقراص وتحسينها، وتنظيف القرص، وتشخيص الذاكرة لـ Windows. تعمل الأدوات السابقة بالمجمل على تسريع عمل الحاسوب واكتشاف الأخطاء الكامنة التي قد تؤدّي إلى عرقلة العمل في ويندوز.
  4. string input = "أنا أحب السباحة"; Console.WriteLine(input[10]); دليل الحرف س هو 10 وليس 11. لأنّ الترقيم يبدأ من الصفر.
  5. سنتعرف في هذا المقال من سلسلة المقالات حول التعامل مع ويندوز 10 على جدار الحماية Firewall الخاص بويندوز 10 ، حيث سنتعلّم التعامل معه بشكل أساسيّ، ثم نبحر في بعض التفاصيل حول كيفيّة ضبطه، ومن ثمّ التحكّم بوصول التطبيقات المثبتة على ويندوز 10 إلى الانترنت. ما هو جدار الحماية؟ جدار الحماية Firewall ببساطة عبارة عن برمجيّة تعمل على إدارة حركة الاتصالات الشبكيّة الصادرة من، والواردة إلى الحاسوب. حيث تسمح بمرور أو منع هذه الاتصالات بالاستناد إلى قواعد محدّدة معرّفة سابقًا. كما قد يكون الجدار الناري عبارة عن جهاز مستقل بذاته يشكل همزة وصل بين الشبكة الداخلية لإحدى الشركات وبين شبكة الانترنت. يحتوي ويندوز 10 كما هو الحال مع الإصدارات السابقة، على برمجيّة جدار حماية مضمّنة فيه يمكن الوصول إليها وإعدادها. توجد في الواقع العديد من البرمجيّات الأخرى التي من الممكن أن تلعب مثل هذا الدور. وخاصّة برمجيّات مكافحة الفيروسات التي تتضمّن في الكثير من الأحيان برمجيّة جدار الحماية. سنتحدّث في هذا المقال عن برمجيّة جدار الحماية الخاص بويندوز 10. إعداد جدار الحماية الخاص بويندوز 10 انقر زر ابدأ، ثم انتقل إلى لوحة التحكم. ستظهر لك نافذة شبيهة بما يلي: انقر النظام والأمان كما يظهر في الشكل السابق لتحصل على الشكل التالي: يظهر من الشكل السابق بند "جدار حماية Windows"، انقره للوصول إلى النافذة الرئيسيّة لتطبيق جدار الحماية كما في الشكل التالي: يظهر من هذا الشكل وجود نوعين من الشبكات التي يقوم جدار حماية ويندوز بمراقبتها. سبب وجود أكثر من شبكة يساعد على جعل العمل على ويندوز 10 أيسر. هناك نوعين من الشبكات كما هو واضح من الشكل السابق: النوع الأول هو "شبكات خاصة" والتي تشتمل على الشبكات المنزليّة، وشبكات العمل والتي تُعتبر بيئة عمل آمنة، فقد يرغب المرء بمشاركة الملفات والصور بين أجهزة الحاسوب المتصلة على نفس الشبكة، أو الوصول إلى الطابعة اللاسلكية مثلًا، وغيرها من الأجهزة التي يمكن وصلها على الشبكة. فمن الممكن في هذه الحالة تعطيل جدار الحماية على هذا النوع من الشبكات، وذلك لجعل تنفيذ مثل هذه العمليّات أسهل بكثير، ودون الحاجة إلى ضبط الكثير من الاعدادات، كون أنّ مثل هذه الشبكات تكون آمنة على المستوى الشخصي. أمّا النوع الثاني فهو "شبكات عامة أو شبكات الضيوف" وهو نوع غير آمن بالضرورة، حيث نحتاج في هذه الحالة إلى تفعيل جدار الحماية للوقاية من الأخطار الكامنة. يتيح لنا التصنيف السابق أن نجعل عمليّة الحماية انتقائيّة بحسب نوع الشبكة. فبالنسبة إلى النوع الأوّل يمكننا تعطيل جدار الحماية بكل بساطة، أمّا بالنسبة إلى النوع الثاني، فيمكننا إبقاء حالة التشغيل له، وسيتذكّر ويندوز 10 مثل هذه الخيارات دومًا بالنسبة لكل شبكة، مما يغنينا عن تشغيل أو إيقاف جدار الحماية بالنسبة لكل نوع. لإيقاف تشغيل جدار الحماية بالنسبة للشبكات الخاصة انقر على الرابط "تشغيل جدار الحماية Windows أو إيقاف تشغيله" الموجود في الجهة اليمنى من النافذة التي تظهر في الشكل السابق لتظهر لك النافذة التالية: انقر على خيار "إيقاف تشغيل جدار حماية Windows (غير مستحسن)" الخاص بإعدادات الشبكات الخاصة. ثم انقر زر "موافق". إنشاء قواعد للتحكم بوصول التطبيقات إلى الانترنت يمكن التحكّم بوصول تطبيق مُحدّد موجود على الحاسوب إلى الانترنت، أو حتى إلى الشبكة الخارجية، وذلك عن طريق الإعدادات المتقدّمة الموجودة في الجهة اليمنى من النافذة الرئيسية الخاصة بإعدادات جدار الحماية. عند نقر "إعدادات متقدّمة" ستحصل على شكل شبيه بما يلي: انقر Outbound Rules للتحكم بقواعد الاتصالات الصادرة. ستعرض النافذة جميع القواعد المتوفرة كما في الشكل التالي: انقر الخيار New Rule الموجود ضمن العمود الأيمن من النافذة في الشكل السابق، لتحصل على شكل شبيه بما يلي: يتم من خلال هذه النافذة تحديد النوع الذي ستطبّق عليه هذه القاعدة. فيما إذا كان برنامج عادي Program أو منفذ Port أو قاعدة معرفة مسبقًا Predefined أو قاعدة مخصّصة Custom. سنترك الخيار الافتراضي وهو Program. انقر بعد ذلك الزر Next. ستظهر لك نافذة تسمح لك بتحديد البرنامج الذي سيتم تطبيق هذه القاعدة عليه. انقر زر Browse لتحديد مسار الملف البرمجي المطلوب كما في الشكل التالي: اختر مسار البرنامج الذي ترغب بمنعه من الوصول إلى الانترنت. بالنسبة إلي سأختار برنامج المفكرة المحلق بالويندوز على سبيل المثال. انقر بعدها على Next. ستظهر نافذة تطلب منك تحديد نوع القاعدة فيما إذا كانت قاعدة منع للاتصال أم قاعدة سماح للاتصال أم قاعدة سماح بالاتصال في حال كان الاتصال آمنًا secured. وهذا يعني أنّ نفس الخطوات ستجري تمامًا إذا أردنا السماح لتطبيق ما بالاتصال بالانترنت وليس منعه. سنختار بالطبع منع التطبيق من الاتصال بالانترنت “Block the connection” في مثالنا هذا. انقر زر Next للمتابعة حيث ستحصل على الشبكات التي سيتم تطبيق هذه القاعدة عليها. اترك الاختيارات الافتراضية كما هي، ثم انقر زر Next مجددًا. بقي أمر أخير قبل إنشاء القاعدة وهو تحديد اسم لها Name، مع إضافة بعض الوصف ضمن الحقل Description. بالنسبة إلي سأختار الاسم Block Notepad Application. اضغط زر Finish ليتم انشاء القاعدة ومن ثمّ إدراجها ضمن مجموعة القواعد التي لديك. الخلاصة تعرّفنا في هذا المقال على كيفيّة التعامل مع جدار الحماية الخاص بويندوز. ذلك التطبيق المهم الذي يُستخدم للحماية من الأخطار التي تهدّد الخصوصيّة والأمن للمستخدم. تعلّمنا كيفيّة ضبطه بالشكل الملاءم للشبكة التي نتصل من خلالها، كما تعلّمنا كيفيّة منع تطبيق مُحدّد من الاتصال بالانترنت حسب قواعد rules خاصّة. هناك الكثير مما يمكن قوله حول جدران الحماية، ولكن سنكتفي بما أوردناه في هذا المقال.
  6. سنكمل في هذا المقال من سلسلة المقالات حول التعامل مع ويندوز 10 ما بدأناه في المقال السابق حول إجراء النسخ الاحتياطي في ويندوز 10. حيث سنعمل على استعادة النسخ الاحتياطي لكل نوع من الأنواع التي تعاملنا معها. استعادة النسخ الاحتياطي القياسي للملفات في ويندوز 10 انقر زر ابدأ ثم انقر زر الاعدادات الموجود فوق زر الطاقة مباشرةً: ستظهر أمامك نافذة الاعدادات. اختر منها "التحديث والأمان" لتظهر النافذة المسؤولة عن جميع مزايا التحديث والأمان. اختر من القائمة الموجودة في الطرف الأيمن "النسخ الاحتياطي" لتظهر محتويات النسخ الاحتياطي كما في الشكل التالي: صِل القرص الصلب الخارجي الذي استخدمته لعمليّة النسخ الاحتياطي، في حال استخدمت قرصًا صلبًا خارجيًا، أمّا في حال كنت قد استخدمت قرصًا داخليًا، فيمكنك أن تنقر مباشرةً على "خيارات أكثر" ثم تستخدم شريط التمرير للانتقال إلى أسفل النافذة ليظهر لك شكل شبيه بما يلي: انقر على "استعادة الملفات من النسخة الاحتياطية الحالية" لتظهر لك نافذة شبيهة بما يلي: يظهر في الشكل السابق المجلّدات التي أجريت لها نسخًا احتياطيًّا بالأسلوب القياسي من قبل. يمكنك نقر الزر الأخضر الموجود في الوسط لتبدأ عملية الاستعادة للملفات. قد تظهر لك رسالة تفيد بأنّه يوجد تشابه بأسماء الملفات، حيث سيعرض عليك خيارات تشتمل على الكتابة فوق الملفات القديمة. اختر منها ما يناسبك. وبعد الانتهاء أغلق نافذة الاسترداد. استعادة النسخ الاحتياطي الشامل (استعادة صورة القرص الصلب) سنعمل في هذه الحالة على استرداد صورة القرص الصلب كاملةً. سيؤدي ذلك إلى إرجاع القرص الصلب للحاسوب إلى الحالة التي كان عليها عند إجراء النسخ الاحتياطي. ويجب الانتباه إلى أنّ هذه العمليّة ستؤدّي إلى إزالة أيّ ملفات جديدة أُحدثَت بعد النسخ الاحتياطي، أو حتى أي تعديلات أو برمجيّات تمّ تثبيتها على نظام التشغيل. لإجراء عملية الاستعادة سنحتاج إلى إعادة تشغيل الحاسوب. انقر زر ابدأ ثم انقر أيقونة الطاقة لتظهر لك قائمة صغيرة. اضغط المفتاح Shift من لوحة المفاتيح، ثم انقر على خيار "إعادة التشغيل". سيؤدّي ذلك إلى إعادة تشغيل الحاسوب مع الدخول في طور الصيانة. انظر إلى الشكل الذي حصلت عليه بعد إعادة التشغيل: انقر الخيار "استكشاف الأخطاء وإصلاحها" لتظهر لك نافذة شبيهة بما يلي: اختر من هذه النافذة الخيار "خيارات متقدّمة" لتحصل على نافذة جديدة شبيهة بما يلي: اختر الآن "استرداد صورة النظام" لتصل إلى النافذة التالية: لاحظ هنا أنّ معالج الاسترداد سيطلب منك تسجيل الدخول إلى الحساب المرتبط بنظام التشغيل الحالي الموجود على الحاسوب، وذلك نظرًا للضرورة الأمنيّة التي تتمثّل في منع الأشخاص غير المخوّل لهم بإجراء هذه العمليّة الحسّاسة. انقر على الحساب الخاص بك، واكتب كلمة المرور، ثم انقر زر متابعة لتحصل على النافذة التالية: تخبرنا هذه النافذة عن مكان تواجد أحدث نسخة احتياطيّة متوفّرة (يجب أن يكون القرص الصلب الخارجي الذي يحتوي على النسخ الاحتياطي موصولًا قبل الوصول إلى هذه النافذة). انقر زر "Next" لتصل إلى النافذة التالية: انقر زر "Next" من جديد لتصل إلى النافذة الأخيرة التي تخبرنا بما سيحدث عند البدء بعمليّة الاستعادة، حيث تحذرنا هذه النافذة أنّه في حال حدثت مقاطعة لعمليّة الاستعادة، كأن يتوقف تشغيل الحاسوب مثلًا فمن الممكن حدوث مشكلة بنظام التشغيل. انقر زر "Finish" ليعرض لك رسالة تأكيد، اختر منها "نعم" لتبدأ عملية الاستعادة التي قد تأخذ بعض الوقت. عند الانتهاء سيعمل نظام ويندوز 10 بشكل طبيعي وينقلك إلى شاشة تسجيل الدخول. لقد عاد القرص الصلب كما في اللحظة التي تمّ فيها إنشاء النسخة الاحتياطية الشاملة. استرداد نقطة استعادة لنظام التشغيل سنعمل على استرداد حالة نظام التشغيل وفقًا لنقطة استعادة قديمة كنت قد أنشأتها من قبل. انتقل إلى لوحة التحكّم، ومنها اختر "النظام" لتظهر لك النافذة التالية: اختر من القائمة الموجودة في الجهة اليمنى "إعدادات النظام المتقدّمة" لتظهر لك النافذة الموافقة. اختر لسان التبويب "حماية النظام" من الأعلى لتحصل على شكل شبيه بما يلي: انفر زر "استعادة النظام" ليبدأ معالج الاستعادة كما في الشكل التالي: انقر زر التالي لتحصل على النافذة التي تحتوي على نقاط الاستعادة المتوفرة على حاسوبك. اختر نقطة الاستعادة المرغوبة ثم انقر زر "التالي". لتصل إلى النافذة التي ستخبرك بملخص العمل الذي سيتم إنجازه. انقر زر "إنهاء"، سيعرض معالج الاسترداد رسالة تأكيد. وافق عليها لتبدأ عملية الاسترداد التي قد تتطلّب بعض الوقت أيضًا. الخلاصة تعرّفنا في هذا المقال على كيفيّة استرداد أشكال النسخ الاحتياطي التي يدعمها ويندوز 10 والتي تعرّفنا عليها في مقال سابق. ربما قد تكون قد لاحظت اختلاف وتنوّع طرق الاستعادة بحسب نوع النسخ الاحتياطي الذي أجريناه. قد تكون بعض هذه الطرق تتطلّب إجراءات متعدّدة، ووقت كبير نسبيًّا لإتمام عمليّة الاستعادة، إلّا أنّ المستخدم لن يحتاج إلى مثل هذه العمليّة إلًّا نادرًا.
  7. سنتحدّث في هذا المقال من سلسلة المقالات حول التعامل مع ويندوز 10 عن النسخ الاحتياطي في ويندوز 10 وأنواعه ومميزاته. مما لا شك فيه أنّنا جميعًا نحتاج إلى إجراء نوع من النسخ الاحتياطي للبيانات التي نمتلكها. تتنوّع البيانات التي بحوزتنا، من مجرّد ملفات عامّة كالصور والمستندات سواءً الشخصيّة أو تلك المتعلّقة بالعمل. أو البرمجيّات والاعدادات الخاصة بنظام التشغيل. قد يؤدّي فقدان الملفات سواءً الشخصيّة أن تلك المتعلّقة بالعمل إلى أضرار كبيرة وربما يكون من الصعب جدًّا تلافيها، أمّا البرمجيّات والاعدادات الخاصة بنظام التشغيل فقد يؤدّي فقدانها بسبب مشكلة أو طارئ أصاب نظام التشغيل إلى خسارة وقت وجهد كبيرين في محاولة إعادة تنصيب البرمجيّات وضبط اعدادات نظام التشغيل من جديد. توجد لدينا بعض الحلول الفعّالة للمشاكل السابقة. فلحل مشكلة النسخ الاحتياطي للبيانات من ملفات ومستندات فمن الممكن استخدام أحد الأسلوبين التاليين: خدمات التخزين السحابيّة. من بين هذه الخدمات خدمة OneDrive التابعة لمايكروسوفت والتي تحدثنا عنها في مقال سابق. والتي يمكنها حل مشكلة حفظ البيانات بصورة آمنة، واستخدامها من خلال أكثر من جهاز بما فيها أجهزة أندرويد وiPhone، أو حتى مشاركتها مع الآخرين. ميزة خدمة OneDrive الأساسيّة هي في تكاملها مع نظام التشغيل ويندوز 10، وبصورة أدق مع حساب مايكروسوفت الذي تمتلكه. استخدام ميزة النسخ الاحتياطي للملفات، وهي مدعومة من قبل ويندوز 10. وفيه يعمل ويندوز 10 على أخذ نسخ احتياطي محلّي للملفات لكامل القرص الصلب، أو ضمن قسم أو مجلّد محدّد ضمنه. ستحتاج للاستفادة من هذه الميزة إلى وجود قرص صلب خارجي، أو قرص صلب داخلي مستقل (ومن الممكن استخدام الشبكة المحليّة لإجراء نسخ على خادوم مخصّص). أمّا بالنسبة لمشكلة النسخ الاحتياطي للإعدادات والبرمجيّات الخاصة بنظام التشغيل، فيوجد أسلوبين منفصلين أيضًا: الأسلوب الأوّل قديم مازال مدعومًا في ويندوز 10 وهو إنشاء صورة image شاملة عن القرص الصلب يمكن الرجوع إليها مستقبلًا، مما يسمح بإعادة القرص الصلب بكل ما يحتويه مطابقًا للحظة التي أُخذت فيها هذه الصورة. استخدام ميزة إنشاء نقطة استعادة لنظام التشغيل وهي مفيدة في حال أردنا إنشاء نقطة مرجعيّة للإعدادات الأساسيّة لنظام التشغيل، يمكن العودة إليها في أيّ وقت في حال حصلت مشكلة طارئة لمثل هذه الاعدادات أثّرت على عمل الجهاز. سنتحدّث عن هذه الأنواع في مقالنا هذا. النسخ الاحتياطي القياسي للملفات في ويندوز 10 انقر زر ابدأ ثم انقر زر الاعدادات الموجود فوق زر الطاقة مباشرةً: ستظهر أمامك نافذة الاعدادات. اختر منها "التحديث والأمان" لتظهر النافذة المسؤولة عن جميع مزايا التحديث والأمان. اختر من القائمة الموجودة في الطرف الأيمن "النسخ الاحتياطي" لتظهر المحتويات النسخ الاحتياطي كما في الشكل التالي: صِل قرصًا صلبًا خارجيًا، ثم انقر على "إضافة محرك أقراص" ليعمل ويندوز عند ذلك على البحث عن الأقراص المتوفرة والتي من الممكن استخدمها في عملية النسخ الاحتياطي. بالنسبة لي أظهر ويندوز 10 القرص التالي المتوفّر لدي (وهو قرص تجريبي، يمكنك التأكّد من ذلك بالنظر إلى حجمه المتواضع 44.9 جيغا بايت). انقر على القرص المتوفّر لديك، سيعمل ويندوز 10 على البدء بعمليّة النسخ الاحتياطي، لمجموعة محدّدة من المجلّدات. إذا أردت الاطلاع عليها يمكنك نقر "خيارات أكثر" لتظهر نافذة تعرض خيارات إضافية تتحكم بعمليّة النسخ الاحتياطي مثل توقيت أخذ النسخ الاحتياطي، بالإضافة إلى عرض المجلّدات الحالية التي يتم النسخ منها. يمكنك إضافة المزيد من المجلّدات التي سيعمل ويندوز 10 على أخد نسخة احتياطية من محتوياتها، بالنقر على زر "إضافة مجلّد". النسخ الاحتياطي الشامل (صورة القرص الصلب) في هذه الحالة سيقوم ويندوز 10 بأخذ ما يشبه الصورة لكامل القرص الصلب بكل ما يحتويه، وهو النسخ الاحتياطي الأشمل الذي يمكن للمرء أن يجريه. علمًا أنّ هذه الخدمة كانت موجودًا مسبقًا في إصدارات قديمة للويندوز، ولكنّها مازالت مدعومة في ويندوز 10. انقر زر ابدأ، ثم اكتب مباشرةً "لوحة التحكم" ليقوم ويندوز بالبحث عنها، وعرضها. انقر على لوحة التحكم من نتائج البحث لتظهر لك النافذة الخاصة بها. اختر منها "النسخ الاحتياطي والاستعادة (Windows 7)". في حال لم يكن هذا الخيار ظاهرًا، فيمكنك اختيار طريقة العرض: "أيقونات صغيرة". بعد ظهور النافذة المطلوبة، اختر من الجهة اليمنى في الأعلى "إنشاء صورة نظام" ليعمل الويندوز على البحث عن وسائط التخزين المتوفرة. لاحظ أنّه يعرض عليك حفظ الصورة في ثلاثة أماكن مختلفة كما في الشكل: سأختار الحفظ ضمن القرص الصلب المستقل الخاص بي (الخيار الأوّل) ثم سأنقر زر "التالي". ستوضّح لك هذه النافذة الأقراص التي سيتم النسخ منها. بعد التأكّد من أنّ جميع الأمور تجري كما هو متوقّع يمكن نقر زر "بدء النسخ الاحتياطي" كما يظهر في الشكل التالي: مع الانتباه إلى أنّ هذه العمليّة ستأخذ وقتًا طويلًا نسبيًّا بحسب سرعة المعالج وسرعة القرص الصلب، وحسب حجم الصورة أيضًا. إنشاء نقطة استعادة لنظام التشغيل وهي ميزة مفيدة في حال أردنا إجراء نسخ احتياطي سريع للإعدادات الرئيسيّة المستقرّة لنظام التشغيل. ومن ثمّ العودة إليها وقت الحاجة. انتقل إلى لوحة التحكّم، ومنها اختر "النظام" لتظهر لك النافذة التالية: اختر من القائمة الموجودة في الجهة اليمنى "إعدادات النظام المتقدّمة" لتظهر لك النافذة الموافقة. اختر لسان التبويب "حماية النظام" من الأعلى لتحصل على شكل شبيه بما يلي: انقر زر موافق وسيطلب منك الويندوز ادخال اسم لنقطة الاستعادة هذه. أدخل اسمًا معبّرًا وانقر موافق، لتبدأ عملية الإنشاء التي ستستغرق بعض الوقت. الخلاصة تعرّفنا في هذا المقال على مزايا النسخ الاحتياطي التي يدعمها ويندوز 10. هذه المزايا المهمة والضرورية للحفاظ على سلامة البيانات وعلى عدة مستويات. يختلف نوع النسخ الاحتياطي الواجب اعتماده حسب الحاجة الشخصيّة أو حاجة المؤسّسة التي يعمل بها المستخدم. بالنسبة إليّ، فقد استخدمت النسخ الاحتياطي الذي يوفره ويندوز 10 عدة مرّات، وبخاصة ميزة الصورة الشاملة. سنتابع في المقال التالي، كيفيّة استعادة النسخ الاحتياطي الذي أجريناه في هذا المقال.
  8. سنتناول في هذا المقال من سلسلة المقالات حول التعامل مع ويندوز 10 خدمة التخزين السحابي الخاصة بمايكروسوفت OneDrive، وتكاملها مع ويندوز 10. وكيفية استثمارها والاستفادة منها بالشكل الأمثل. من الواضح أنّه توجد العديد من خدمات التخزين السحابي المنافسة. والتي قد تكون ذات فعالية ومرونة أكبر من OneDrive، ولكن ما يميّز OneDrive هو تكاملها مع ويندوز 10 بالإضافة إلى تطبيقات أوفيس. حيث من الممكن استخدام خدمة أوفيس 365 السحابية Office 365 أو حتى تطبيقات أوفيس التقليدية مع هذه الخدمة. الخطط الخاصّة بخدمة OneDrive لخدمة OneDrive عدّة خطط، منها المجّاني، ومنها المدفوع. انتقل إلى هذه الصفحة لترى العروض الخاصّة بخدمة OneDrive. كما هو واضح من الشكل السابق أنّ خدمة OneDrive تأتي بعدة خطط. لاحظ أنّ الخطّة المجانيّة تمنحك مساحة تخزين قدرها 5 جيغا بايت. يمكنك استخدام شريط التمرير، لمشاهدة باقي المزايا الخاصة بكل خطة. لاحظ أيضًا من الشكل السابق أنّنا نستعرض الخطط الشخصيّة Personal. يمكنك أن تلاحظ لسان تبويب اسمه Business وهو خاص بقطاع الأعمال، انقر عليه لمشاهدة الخطط المتوفّرة. لقطاع الأعمال. تجهيز OneDrive للاستخدام انقر زر ابدأ ثم اكتب OneDrive مباشرةً، سيؤدّي ذلك إلى عرض تطبيق OneDrive مباشرةً ضمن نتائج البحث. شغّل التطبيق لتحصل على نافذة شبيهة بما يلي، وذلك في حال لم تكن قد سجّلت الدخول من قبل إلى خدمة OneDrive على هذا الحاسوب. أدخل حساب مايكروسوفت الخاص بك. والذي يطابق الحساب المرتبط به أنت حاليًا ضمن ويندوز 10. ثم انقر زر "تسجيل الدخول". ستظهر نافذة أخرى تطلب منك كلمة المرور. أدخل كلمة المرور الخاصة بهذا الحساب، ثم تابع عملية تسجيل الدخول لتصل إلى النافذة التالية: تخبرنا النافذة السابقة أنّ عملية تسجيل الدخول قد نجحت، بالإضافة إلى عرض موقع التخزين الحالي الموجود فوق زر "التالي" مع إتاحة الامكانية لتغييره. تسمح خدمة OneDrive كما في جميع خدمات التخزين السحابية الأخرى بالمزامنة بين الملفات الموجودة محليًّا على حاسوبك الشخصي، وبين الملفات الموجودة ضمن حسابك في السحابة cloud. يعني ذلك فعليًّا أنّ الملفات ستكون موجودة فيزيائيًّا في مكانين منفصلين. المكان الأوّل هو ضمن مجلّد رئيسي موجود على القرص الصلب في حاسوبك الشخصي. أمّا المكان الثاني فهو ضمن خدمة التخزين السحابي. وعند إضافة ارتباط جديد من جهاز آخر إلى نفس خدمة OneDrive الخاصة بك، فسيتم مزامنة الملفات مجددًا مع الحاسوب الجديد، وبالتالي سيتكون الملفات فعليًّا موجود ضمن ثلاثة أماكن منفصلة، وهكذا دواليك. ولكن يجب أن يكون واضحًا أنّه على الرغم من وجود الملفات بشكل فيزيائي في عدّة أماكن مختلفة، إلّا أنّ أي تعديل على أيّ ملف مُزامَن ضمن أي جهاز متصل بخدمة OneDrive سيؤدّي ذلك إلى التعميم الفوري لهذا التعديل على جميع الأجهزة المتصلة بالحساب السحابيّ نفسه. يتيح ذلك كما هو واضح الوصول إلى نفس الملفات من أجهزة مختلفة، ومن مناطق جغرافية متنوّعة، طالما كانت هذه الملفات مُزامنة بخدمة OneDrive. لنكمل عملنا بالنقر على زر "التالي" من النافذة السابقة لنحصل على النافذة الخاصّة بمزامنة المحتوى مع المحتوى السحابي في OneDrive: تعرض هذه النافذة المجلّدات الموجودة حاليًا ضمن خدمة التخزين السحابي OneDrive الخاصّة بحسابك. تخيّرك النافذة بين مزامنة جميع الملفات والمجلّدات الموجودة في السحابة، وبين انتقاء مجلّدات محدّدة فقط، في حال لم ترد نسخ جميع الملفات السحابيّة إلى حاسوبك. سأترك الخيارات الافتراضيّة كما هي، ثم سأنقر زر "التالي". سيبدأ عندها تطبيق OneDrive ببدء عملية المزامنة التي تأخذ وقتًا يتناسب مع حجم المحتوى، وسرعة الاتصال بالانترنت. من الممكن أن تحصل على عرض للترقية إلى الخدمة المأجورة مع مميزات أكبر كما حدث معي. انظر الشكل التالي: انقر "ليس الآن"، يمكنك بالطبع تغيير ذلك في أيّ وقت مستقبلًا. ستحصل على شاشة ترحيبيّة تُخبرك بمزايا OneDrive الأساسيّة. يمكنك تصفّح هذه المزايا، ومن ثمّ اغلاق هذه النافذة. لقد أصبحنا جاهزين الآن لاستخدام OneDrive. البدء بمزامنة الملفات يمكنك الاطلاع على ملفاتك الموجودة حاليًا ضمن OneDrive من قائمة البداية، حيث سيعمل تطبيق OneDrive عند تثبيته على إضافة لوح tile خاص به ضمن هذه القائمة. في حال لم يظهر مثل هذا اللوح، يمكنك بعد نقر زر ابدأ أن تكتب مباشرةً OneDrive، سيعرض ويندوز نتيجتي بحث، الأولى للتطبيق نفسه، والثانية للمجلّد الخاص بتخزين الملفات. اختر المجلّد ليتم فتحه. يمكنك الآن بكلّ بساطة سحب أي ملف أو مجلّد إلى مجلّد OneDrive لتتم مزامنته تلقائيًّا. لاحظ أنّ في حال تمّت مزامنة أي ملف أو مجلّد فسيظهر رمز أخضر صغير على أيقونة الملف يُشير إلى انتهاء عمليّة التزامن، كما هو واضح من الشكل الأخير. ربط أجهزة متعدّدة بحساب OneDrive واحد يمكن بكلّ تأكيد الاستفادة من هذه الميزة كما أشرنا من قبل، إذ يدعم OneDrive حتى لحظة كتابة هذا المقال 6 منصات مختلفة يمكن من خلالها الربط مع حساب OneDrive واحد. تتضمّن هذه المنصّات بالطبع أجهزة Android وiPhone. يمكنك تنزيل التطبيق الخاص بأجهزة أندرويد من هنا. أمّا التطبيق الخاص بأجهزة iPhone فيمكنك تنزيله من هنا. كما يمكنك بالطبع الوصول إلى ملفاتك على OneDrive من موقع ويب الخاص بخدمة OneDrive مباشرةً دون الحاجة لتنصيب أيّ تطبيق. تحتاج فقط إلى تسجيل الدخول بحساب مايكروسوفت الخاص بك ضمن هذا الموقع. مشاركة الملفات والمجلّدات مع الآخرين يمكنك في أيّ وقت مشاركة ملفاتك الموجودة ضمن OneDrive مع الأصدقاء أو زملاء العمل. هناك العديد من الفوائد لهذه الميزة، من أبسطها إمكانية إرسال رسائل ذات حجم كبير للآخرين، لا يمكن رفعها كمرفق ضمن البريد الالكتروني. وأعتقد أنّ هذه مشكلة قد عانى منها جميعنا بشكل أو بآخر. لنرى الآن كم هو سهل إجراء عمليّة المشاركة مع الآخرين. افتح مجلّد OneDrive الموجود على حاسوبك. انقر بزر الفأرة الأيمن على الملف أو المجلّد الذي ترغب بمشاركته. ستحصل على شكل مماثل لما يلي: انقر على "مشاركة رابط OneDrive" وسيعمل تطبيق OneDrive على نسخ رابط المشاركة إلى حافظة ويندوز. يمكنك الآن إرسال هذا الرابط إلى من ترغب من الأشخاص، وسيستطيع الجميع الوصول إلى هذا الملف وتحميله. يمكن بالطيع مشاركة المجلّدات أيضًا، وضبط أذوناتها بحيث يستطيع الآخرون أن يضيفوا الملفات إليها. ستحتاج في هذه الحالة إلى ضبط المزيد من خيارات المشاركة وذلك عن طريق النقر على الخيار "المزيد من خيارات المشاركة في OneDrive" الموجود ضمن القائمة من الشكل الأخير. الخلاصة تعلّمنا في هذا المقال كيفيّة تفعيل خدمة OneDrive للتخزين السحابي، والتعامل معها ضمن ويندوز 10. تُعتبر هذه الخدمة من الخدمات الرائدة في مجال التخزين السحابي، ورغم تفوّق بعض الخدمات السحابيّة عليها في بعض الجوانب، إلّا أنّ تكاملها مع ويندوز 10 بالإضافة إلى تطبيقات أوفيس الأخرى يعطيها ميزة مهمة على الصعيدين الشخصي والعمليّ.
  9. أهلًا وسهلًا أخي. يسعدني سماع ذلك. في التمرين الثاني ستطلب من المستخدم إدخال نص عشوائي. هذا النص مكون من كلمات بطبيعة الحال. وظيفتك هنا هي إجراء إحصاء بسيط للعدد الإجمالي لمرات تكرار كل كلمة. مثلًا ليكن لدينا النص التالي: الطيور على أشكالها تقع، والطيور أشكالها جميلة. في هذه الحالة يجب أن يكون خرج البرنامج: الطيور: 2 على: 1 تقع: 1 أشكالها: 2 ... وهكذا..
  10. أهلًا أخي الكريم. أعتذر عن التأخر في الرد. بسبب أنّ الموقع لا يُشعرني عندما يتم إدراج تعليق مع الأسف. شكرًا لك ولكلامك اللطيف. أرجو من الله أن يكون المحتوى مفيدًا لك ولجميع الأخوة.
  11. أهلًا أخي الكريم. أعتذر عن التأخر في الرد. بسبب أنّ الموقع لا يُشعرني عندما يتم إدراج تعليق مع الأسف. بالنسبة إلى ما تفضلت به، فأنا لم أفهم تمامًا مالذي تقصده. ولك مني جزيل الشكر والتقدير.
  12. كلامك صحيح. ولكن هذا المقال هو مجرد مقدّمة مبسّطة جدا للمبتدئين.
  13. بالتوفيق أخي الكريم. مع الأسف لا توجد حاليًا قناة على يوتيوب. ولكن التوجه العام للأكاديمية نحو دعم الدورات التدريبية المعتمدة على الفيديو.
  14. سنتناول في هذا الدرس من سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms الجزء الثاني من تطبيق قارئ الخلاصات الخاص بموقع أكاديميّة حسوب. لقد بنينا في الجزء الأوّل تطبيق أساسي أسميناه BasicFeedReader وكانت وظيفته تنحصر في عرض خلاصات قسم مقالات البرمجة. سنطوّر هذه الفكرة من خلال إنشاء تطبيق جديد يعمل على إتاحة الإمكانية للمستخدم بأن يستعرض الخلاصات المتاحة من جميع أقسام الموقع. سيكون ذلك من خلال إضافة صفحة جديدة لعرض أقسام الموقع على شكل مجموعات. لنبدأ فورًا في بناء هذا التطبيق التي سيحتوي على بعض من المكوّنات المتطابقة مع سلفه. بناء تطبيق قارئ الخلاصات المحسّن أنشئ مشروعًا جديدًا من النوع Blank App (Xamarin.Forms Portable) وسمّه EnhancedFeedReader ثم أبق فقط على المشروعين EnhancedFeedReader (Portable) و EnhancedFeedReader.Droid كما وسبق أن فعلنا في هذا الدرس. رغم الشبه الكبير بين هذا التطبيق وسلفه إلًّا أنّني آثرت إعادة إدراج الشيفرة البرمجيّة للأجزاء المتشابهة، وذلك لكي يكون هذا التطبيق متكاملًا قائمًا بحد ذاته. أضف المجلّدين التاليين إلى المشروع EnhancedFeedReader (Portable) (عن طريق النقر بزر الفأرة الأيمن ثم اختيار Add ثم New Folder): Pages و Entities. الأصناف ضمن المجلّد Entities أضف الأصناف التالي إلى المجلّد Entities: FeedItem و Section و GroupSection. بالنسبة للصنف FeedItem فلقد تحدثنا عنه في الجزء الأوّل، وإليك الشيفرة البرمجيّة الخاصّة به: namespace EnhancedFeedReader.Entities { public class FeedItem { public string Link { get; set; } public string Title { get; set; } public string Description { get; set; } public override string ToString() { return Title; } } } الصنف Section هو صنف جديد تمامًا وهو يمثّل قسم من أقسام المحتوى الخاصّة بموقع أكاديميّة حسّوب. الشيفرة البرمجيّة للملف Section.cs هي: using System; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using System.Xml.Linq; namespace EnhancedFeedReader.Entities { public class Section { public string Name { get; set; } public string ResourceUrl { get; set; } public async Task<ObservableCollection<FeedItem>> GetFeedItems() { return await Task.Factory.StartNew(() => { XDocument doc = XDocument.Load(ResourceUrl); var feeds = from newsItem in doc.Descendants("item") select new FeedItem { Title = newsItem.Element("title").Value, Description = newsItem.Element("description").Value, Link = newsItem.Element("link").Value }; return new ObservableCollection<FeedItem>(feeds); }); } public override string ToString() { return Name; } } } يحتوي هذا الصنف على خاصيّتين: الاسم Name وعنوان المصدر ResourceUrl الذي سيتم جلب الخلاصات منه. يوجد أيضًا التابع GetFeedItems الذي سيجلب الخلاصات التابعة للقسم الحالي. هذا التابع هو البديل للتابع LoadFeeds الذي كان موجودًا في الصنف SectionFeedsPage وهو يقوم بنفس وظيفته مع ميزة استخدام البرمجة غير المتزامنة. وأخيرًا التابع ToString للحصول على تمثيل نصّي لكائن من النوع Section. أمّا بالنسبة للصنف GroupSection فهو يمثّل تصنيف لمجموعة من الأقسام. في الحقيقة يعمل موقع أكاديميّة حسوب على تقسيم الخلاصات ضمن مجموعات كل منها يحتوي على قسمين. انظر إلى الشيفرة الخاصّ بهذا الصنف: using System.Collections.ObjectModel; namespace EnhancedFeedReader.Entities { public class GroupSection : ObservableCollection<Section> { public string Name { get; set; } } } لاحظ كم هي بسيطة هذه الشيفرة. يحتوي هذا الصنف على خاصيّة واحدة هي خاصيّة الاسم Name له. مع الانتباه إلى أنّه يرث من الصنف العمومي ObservableCollection<Section>. وهذا إشارة إلى أنّه يمثّل مجموعة من الأقسام Section. سنرى سبب عمليّة الوراثة هذه بعد قليل. الواجهات ضمن المجلّد Pages يوجد لدينا ضمن هذا المجلّد ثلاث واجهات تتبع لثلاثة أصناف. صنفان منهما قديمان وهما: SectionFeedsPage و FeedDetailsPage وهما يمثّلان على الترتيب: الواجهة المسؤولة عن عرض خلاصات قسم محدّد من الأقسام المتوفّرة، ومحتوى الخلاصة التي اختارها المستخدم من الواجهة السابقة. أمّا الصنف الثالث فهو SectionsPage وهو يمثّل الواجهة الرئيسيّة الخاصة بعرض جميع الأقسام المتوفّرة ضمن موقع الأكاديميّة. انتقل إلى ملف الرماز SectionFeedsPage.xaml واحرص على أن تكون محتوياته على الشكل التالي: <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="EnhancedFeedReader.Pages.SectionFeedsPage"> <StackLayout> <ListView x:Name="lsvFeeds" ItemTapped="lsvFeeds_ItemTapped"/> </StackLayout> </ContentPage> ثم انتقل إلى ملف الشيفرة الموافق له وهو SectionFeedsPage.xaml.cs واحرص على أن تكون محتوياته على الشكل التالي: using EnhancedFeedReader.Entities; using Xamarin.Forms; namespace EnhancedFeedReader.Pages { public partial class SectionFeedsPage : ContentPage { public SectionFeedsPage(Section section) { InitializeComponent(); Title = section.Name; PopulateFeedsListView(section); } private async void PopulateFeedsListView(Section section) { lsvFeeds.ItemsSource = await section.GetFeedItems(); } private async void lsvFeeds_ItemTapped(object sender, ItemTappedEventArgs e) { FeedItem selectedFeed = (FeedItem)e.Item; FeedDetailsPage feedDetailsPage = new FeedDetailsPage(selectedFeed); await Navigation.PushAsync(feedDetailsPage); } } } الجديد في هذا الصنف هو التابع PopulateFeedsListView الذي يُمرّر إليه وسيط واحد من النوع Section حيث يتم الحصول على خلاصاته ومن ثمّ إسنادها إلى القائمة lsvFeeds لعرضها. لاحظ كيف يتمّ ذلك باستخدام البرمجة غير المتزامنة. انتقل بعد ذلك إلى ملف الرماز FeedDetailsPage.xaml واحرص على أن تكون محتوياته على الشكل التالي: <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="EnhancedFeedReader.Pages.FeedDetailsPage"> <StackLayout Orientation="Vertical"> <WebView x:Name="wvDescription" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"/> </StackLayout> </ContentPage> ثم انتقل إلى ملف الشيفرة البرمجيّة الموافق له وهو FeedDetailsPage.xaml.cs: using Xamarin.Forms; using EnhancedFeedReader.Entities; namespace EnhancedFeedReader.Pages { public partial class FeedDetailsPage : ContentPage { public FeedDetailsPage(FeedItem feedItem) { InitializeComponent(); this.Title = feedItem.Title; var descriptionHtmlSource = new HtmlWebViewSource(); descriptionHtmlSource.Html = @"<html dir='rtl'><body>" + feedItem.Description + "</body></html>"; wvDescription.Source = descriptionHtmlSource; } } } لم يطرأ في الحقيقة أيّ تعديل على هذا الصنف. انتقل أخيرًا إلى ملف الرماز SectionsPage.xaml الذي يمثّل واجهة العرض الأساسيّة، التي ستعرض جميع أقسام الخلاصات المتاحة في الأكاديميّة واحرص على أن تكون محتوياته كما يلي: <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="EnhancedFeedReader.Pages.SectionsPage"> <ListView x:Name="lsvSections" ItemTapped="lsvSections_ItemTapped" IsGroupingEnabled="True" GroupDisplayBinding="{Binding Name}" /> </ContentPage> واضح أنّ محتوياته بسيطة، فهي لا تتعدى عنصر القائمة الذي أسميته lsvSections. الأمر الملفت للنظر هنا هو وجود الخاصيتين IsGroupingEnabled و GroupDisplayBinding لعنصر القائمة. أسندنا القيمة True للخاصيّة IsGroupingEnabled وذلك للإشارة إلى وجوب أن تدعم هذه القائمة ميزة التجميع Grouping. أمّا الخاصيّة GroupDisplayBinding فقد أسندت لها القيمة {Binding Name} للإشارة إلى أنّني أرغب بأن يتم ربطها مع قيمة الخاصيّة Name للكائن GroupSection فهي تُحدّد النص المراد إظهاره كعنوان لكل مجموعة. لكي تتوضّح الأمور بشكل أفضل انظر إلى الواجهة في حالة العمل: انتقل الآن إلى ملف الشيفرة البرمجيّة الموافق وهو SectionsPage.xaml.cs لكي نتعرّف على طريقة الاستفادة من هذه الميزة، واحرص على أن تكون محتوياته على الشكل التالي: using System.Collections.Generic; using System.Collections.ObjectModel; using Xamarin.Forms; using EnhancedFeedReader.Entities; namespace EnhancedFeedReader.Pages { public partial class SectionsPage : ContentPage { public SectionsPage() { InitializeComponent(); Title = "قارئ خلاصات أكاديمية حسوب"; LoadGroupSections(); } private void LoadGroupSections() { int spacePos = 0; string tmp; GroupSection gs = null; Dictionary<string, string[]> groupSectionDic = new Dictionary<string, string[]>() { { "خلاصات ريادة الأعمال",new string[] { "https://academy.hsoub.com/entrepreneurship/?rss=1", "https://academy.hsoub.com/questions/rss/entrepreneurship-5.xml" } }, { "خلاصات العمل الحر",new string[] { "https://academy.hsoub.com/freelance/?rss=1", "https://academy.hsoub.com/questions/rss/freelance-8.xml" } }, { "خلاصات التسويق والمبيعات", new string[] { "https://academy.hsoub.com/marketing/?rss=1", "https://academy.hsoub.com/questions/rss/marketing-7.xml" } }, { "خلاصات البرمجة", new string[] { "https://academy.hsoub.com/programming/?rss=1", "https://academy.hsoub.com/questions/rss/programming-3.xml" } }, { "خلاصات التصميم", new string[] { "https://academy.hsoub.com/design/?rss=1", "https://academy.hsoub.com/questions/rss/design-4.xml" } }, { "خلاصات DevOps",new string[] { "https://academy.hsoub.com/devops/?rss=1", "https://academy.hsoub.com/questions/rss/devops-6.xml" } }, { "خلاصات البرامج والتطبيقات",new string[] { "https://academy.hsoub.com/apps/?rss=1", "https://academy.hsoub.com/questions/rss/apps-9.xml" } }, { "خلاصات الشهادات المتخصصة",new string[] { "https://academy.hsoub.com/certificates/?rss=1", "https://academy.hsoub.com/questions/rss/certificates-10.xml" } } }; ObservableCollection<GroupSection> groupSections = new ObservableCollection<GroupSection>(); foreach (var grp in groupSectionDic) { gs = new GroupSection() { Name = grp.Key }; spacePos = grp.Key.IndexOf(" "); tmp = grp.Key.Substring(spacePos + 1); gs.Add( new Section { Name = "مقالات " + tmp , ResourceUrl = grp.Value[0] } ); gs.Add( new Section { Name = "أسئلة " + tmp, ResourceUrl = grp.Value[1] } ); groupSections.Add(gs); } lsvSections.ItemsSource = groupSections; } private async void lsvSections_ItemTapped(object sender, ItemTappedEventArgs e) { Section selectedSection = (Section)e.Item; SectionFeedsPage sectionFeedsPage = new SectionFeedsPage(selectedSection); await Navigation.PushAsync(sectionFeedsPage); } } } هناك الكثير من المتعة في الشيفرة السابقة! تتمحور معظم الشيفرة حول التابع LoadGroupSections ويُستَخدم لتجهيز الأقسام المختلفة لمصادر الخلاصات في الأكاديمية ووضعها ضمن مجموعات منفصلة ضمن عنصر القائمة lsvSections. هذه الأقسام (كعناوين) موجودة في وضع عدم اتصال وقد نسختها يدويًا من موقع الأكاديميّة، وهي ضمن المتغير groupSectionDic الذي صرحنا عنه من نوع القاموس Dictionary ملف التطبيق App.cs انتقل إلى ملف التطبيق App.cs واحرص على أن تكون بانية الصنف App على الشكل التالي: public App() { // The root page of your application MainPage = new NavigationPage(new SectionsPage()); } احرص على استخدام فضاء الاسم Pages لكي تستطيع الوصول إلى الصفحة SectionsPage كما يلي: using EnhancedFeedReader.Pages; ستضع السطر السابق أوّل الملف App.cs كما هو معلوم. نفّذ البرنامج وتنقّل في أقسامه المختلفة. الخلاصة تناولنا في هذا الدرس الجزء الثاني من تطبيق قارئ الخلاصات الخاص بموقع أكاديميّة حسّوب. لقد أجرينا تحسينات مهمّة على هذا التطبيق من خلال السماح للمستخدم بتصفّح الخلاصات من جميع أقسام الموقع. حيث استخدمنا ميزة التجميع grouping لعنصر القائمة ListView وذلك لتجميع العناوين التابعة لنفس القسم معًا. نكون بذلك قد انتهينا من هذا التطبيق.
  15. سنتناول في هذا الدرس من سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms تطبيقًا عمليًا آخرًا وهو تطبيق قارئ الخلاصات من موقع أكاديمية حسوب. تندرج مثل هذه التطبيقات تحت النوع rss feed reader ولها مزايا كثيرة ومتنوّعة. سيكون تطبيقنا بسيطًا وعمليًّا ويوضّح مبدأ العمل كما جرت العادة. سننفّذ التطبيق على مرحلتين: المرحلة الأولى سيكون تطبيق لعرض الخلاصات الموجودة ضمن أحد أقسام الموقع، مع إمكانية اختيار أيّ خلاصة وعرض تفاصيل حولها، وهذا هو محتوى هذا الدرس. أمّا المرحلة الثانية فستكون تحسين للتطبيق المنجز في هذا الدرس حيث سنضيف إمكانيّة قراءة الخلاصات من جميع أقسام الموقع مع إضافة بعض التحسينات على أسلوب العرض بشكل عام، وسيكون ذلك في درس منفصل. ماهي الخلاصات؟ خلاصات موقع تكون عادةً عبارة عن مستند XML يحتوي على بيانات تمثّل آخر الأخبار التي يوفّرها الموقع. لا تمتلك جميع المواقع خلاصات بالطبع، ولكنّ من الجيّد دومًا أن يوفّر الموقع مثل هذه الخلاصات في حال كان يمتلك محتوىً متجدّدًا كما هو الحال في موقع أكاديميّة حسوب. بما أنّ الخلاصة تكون ضمن ملف XML فمن البديهي أن تكون البيانات منسّقة بتنسيق XML، أي على شكل عقد آباء وأبناء. انظر مثلًا إلى جزء من خلاصات قسم مقالات البرمجة في أكاديميّة حسوب كما ظهرت لي عند كتابة هذا المقال: لاحظ أنّني أستعرض هذه الخلاصات عن طريق متصفّح Chrome عن طريق الرابط: https://academy.hsoub.com/programming/?rss=1 وهو الرابط الذي توفّره الأكاديميّة للحصول على خلاصات مقالات البرمجة. من الواضح أنّ هذا الأسلوب غير عملي في الحصول على آخر الخلاصات، لذلك يلجأ المستخدمون عادةً إلى تطبيقات متنوّعة لعرض هذه الخلاصات بشكل مريح ومقروء. تطبيق قارئ الخلاصات سنبني في هذا الدرس تطبيق قارئ خلاصات وظيفته قراءة الخلاصات الموجودة في قسم مقالات البرمجة في موقع أكاديميّة حسّوب. وسنعمل في الدرس التالي على تحسين هذا التطبيق بإتاحة الإمكانيّة لتصفّح الخلاصات من جميع الأقسام. أنشئ مشروعًا جديدًا من النوع Blank App (Xamarin.Forms Portable) وسمّه BasicFeedReader ثم أبق فقط على المشروعين BasicFeedReader (Portable) و BasicFeedReader.Droid كما وسبق أن فعلنا في هذا الدرس. الصنف FeedItem من نافذة مستكشف الحل Solution Explorer انقر بزر الفأرة الأيمن على المشروع BasicFeedReader واختر من القائمة التي ستظهر الخيار Add ثم من القائمة الفرعية الخيار New Folder لإضافة مجلّد جديد. سمّ هذا المجلّد بالاسم Entities، وبعد أن يظهر في نافذة الحل Solution Explore انقر عليه بزر الفأرة الأيمن واختر الخيار Add ومن القائمة الفرعية اختر Class. ستظهر نافذة تسمح لك بتعيين اسم لهذا الصنف. اختر الاسم FeedItem له. هذا الصنف هو حجر البناء الأساسي لهذا البرنامج. احرص على جعل محتويات الملف FeedItem.cs كما يلي: namespace BasicFeedReader.Entities { public class FeedItem { public string Link { get; set; } public string Title { get; set; } public string Description { get; set; } public override string ToString() { return Title; } } } الخصائص Link و Title و Description في هذا الصنف تقابل العناصر link و title و description في مستند XML. أمّا التابع ToString فهو للحصول على تمثيل نصّي لأي كائن من النوع FeedItem. الواجهات أضف مجلّدًا جديدًا للمشروع BasicFeedReader كما فعلنا قبل قليل، وسمّه Pages. ثم أضف إليه صفحتي محتوى تعتمدان رماز XAML بحيث يكون اسم الصفحة الأولى هو FeedDetailsPage وهي الواجهة الرئيسيّة، واسم الصفحة الثانية SectionFeedsPage وهي واجهة التفاصيل. الصفحة SectionFeedsPage هي الواجهة التي ستعرض خلاصات قسم مقالات البرمجة في أكاديمّية حسوب. أمّا الواجهة FeedDetailsPage فهي لعرض الخلاصة التي يتم اختيارها من الواجهة SectionFeedsPage. الواجهة SectionFeedsPage انتقل إلى الملف SectionFeedsPage.xaml واحرص على أن تكون محتوياته على الشكل التالي: <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="BasicFeedReader.Pages.SectionFeedsPage"> <StackLayout> <ListView x:Name="lsvFeeds" ItemTapped="lsvFeeds_ItemTapped"/> </StackLayout> </ContentPage> لاحظ كم هو بسيط هذا الرماز، فهو لا يحتوي سوى عنصر قائمة lsvFeeds لعرض خلاصات قسم مقالات البرمجة، حيث سنربط الحدث ItemTapped الخاص بها بالمعالج lsvFeeds_ItemTapped. انتقل الآن إلى ملف الشيفرة البرمجيّة الموافق SectionFeedsPage.xaml.cs واحرص على أن تكون محتوياته على الشكل التالي: using BasicFeedReader.Entities; using System.Linq; using System.Xml.Linq; using Xamarin.Forms; namespace BasicFeedReader.Pages { public partial class SectionFeedsPage : ContentPage { public SectionFeedsPage() { InitializeComponent(); LoadFeeds("https://academy.hsoub.com/programming/?rss=1"); Title = "مقالات البرمجة"; } private async void lsvFeeds_ItemTapped(object sender, ItemTappedEventArgs e) { FeedItem selectedFeed = (FeedItem)e.Item; FeedDetailsPage feedDetailsPage = new FeedDetailsPage(selectedFeed); await Navigation.PushAsync(feedDetailsPage); } private void LoadFeeds(string resource) { XDocument doc = XDocument.Load(resource); var feeds = from newsItem in doc.Descendants("item") select new FeedItem { Title = newsItem.Element("title").Value, Description = newsItem.Element("description").Value, Link = newsItem.Element("link").Value }; lsvFeeds.ItemsSource = feeds; } } } عند يتم إنشاء كائن من هذه الصفحة لعرضها للمستخدم، يتم تنفيذ بانيتها. حيث يعمل التطبيق على استدعاء التابع LoadFeeds والذي يتطلّب وسيطًا واحدًا من النوع string ويمثّل عنوان المصدر المزوّد للخلاصات. في الحقيقة ما فعلناه هنا هو أمر غير جيّد من الناحية العمليّة، فلا ينبغي وضع مثل هذا الاستدعاء هنا في البانية، سيما وأنّ التابع LoadFeeds لا يستخدم تقنية البرمجة غير المتزامنة، مما سيسبب جمودًا مزعجًا في التطبيق عند أوّل تشغيله. سنحل هذه المشكلة لاحقًا في الجزء الثاني. انظر الآن إلى تعريف التابع LoadFeeds من الشيفرة السابقة. ستلاحظ أنّه يستخدم تقنيّة ممتازة يوفرها إطار العمل .NET من خلال الصنف XDocument الذي يمثّل مستند XML بشكل كائني، حيث يعمل السطر الأوّل من هذا التابع على إنشاء كائن جديد من الصنف XDocument من خلال تحميل مستند XML مباشرةً من الانترنت عن طريق التابع الساكن Load. بعد ذلك يتم إعراب مستند XML المحمّل من الإنترنت بسرعة وفعاليّة عاليتين. حيث تحتاج إلى عدد قليل من الأسطر البرمجيّة على شكل استعلام LINQ to XML لكي تقوم بالمطلوب. لقد اطلعنا على تقنيّة شبيهة في درس سابق حيث استخدمنا LINQ to Objects. يمكنك معرفة المزيد حول هذا الموضوع بقراءة هذا المقال. بعد استخلاص المعلومات من مستند XML المُحمّل، وإنشاء كائن من النوع FeedItem لكل خلاصة موجودة في هذا المستند، يتم إسناد المجموعة المنشأة من هذه الكائنات إلى الخاصيّة ItemsSource من القائمة lsvFeeds ليتم عرضها للمستخدم. أمّا بالنسبة لمعالج الحدث lsvFeeds_ItemTapped من الشيفرة السابقة. فوظيفته بسيطة، وهي تنحصر في الحصول على كائن FeedsItem الموجود ضمن العنصر الذي تمّ نقره (لمسه) ضمن القائمة lsvFeeds ومن ثمّ الانتقال إلى الصفحة FeedDetailsPage لعرض محتوى هذه الخلاصة. الواجهة FeedDetailsPage انتقل إلى الملف FeedDetailsPage.xaml واحرص على أن تكون محتوياته على الشكل التالي: <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="BasicFeedReader.Pages.FeedDetailsPage"> <StackLayout Orientation="Vertical"> <WebView x:Name="wvDescription" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"/> </StackLayout> </ContentPage> لاحظ مرّة أخرى كم هو بسيط هذا الرماز. حيث يقتصر على استخدام عنصر واحد، هو العنصر WebView ويُستخدم لعرض محتوى مستند HTML. وسبب استخدامي لهذا العنصر، هو أنّ الخلاصات التي ترد من موقع أكاديميّة حسّوب تحتوي على المحتوى كاملًا وهو منسّق بتنسيق HTML. وهذا أمر لا تجده في كثير من مزوّدات خدمة الخلاصات. لذلك فوجدت أنّ أفضل طريقة هو عرض هذا المحتوى مباشرةً ضمن عنصر WebView. انتقل الآن إلى ملف الشيفرة البرمجيّة الموافق FeedDetailsPage.xaml.cs واحرص على أن يكون كما في الشكل التالي: using Xamarin.Forms; using BasicFeedReader.Entities; namespace BasicFeedReader.Pages { public partial class FeedDetailsPage : ContentPage { public FeedDetailsPage(FeedItem feedItem) { InitializeComponent(); this.Title = feedItem.Title; var descriptionHtmlSource = new HtmlWebViewSource(); descriptionHtmlSource.Html = @"<html dir='rtl'><body>" + feedItem.Description + "</body></html>"; wvDescription.Source = descriptionHtmlSource; } } } كل الشيفرة البرمجيّة موجودة ضمن البانية التي تتطلّب وسيطًا واحدًا من النوع FeedItem الذي يحتوي على بيانات الخلاصة المراد عرض تفاصيلها. نعمل على وضع عنوان هذه الصفحة ليكون مطابقًا لعنوان الخلاصة، ثمّ ننشئ كائنًا من النوع HtmlWebViewSource نسنده ضمن المتغيّر descriptionHtmlSource الذي سيمثّل الكائن المحتوى للعنصر wvDescription (عنصر WebView الذي صرّحنا ضمن ملف الرماز). لاحظ كيف أسندنا للخاصيّة Html لهذا المتغيّر محتوى الخاصيّة Description لكائن الخلاصة، وهو كما أشرنا قبل قليل عبارة عن مستند HTML ينقصه فقط الوسمين و اللذان أضفناهما يدويًّا. ثمّ نُسند المتغيّر descriptionHtmlSource بدوره إلى الخاصيّة Source للعنصر wvDescription مما يؤدّي إلى ظهور مستند HTML كما هو مخطّط له. ملف التطبيق App.cs انتقل إلى ملف التطبيق App.cs واحرص على أن تكون بانية الصنف App على الشكل التالي: public App() { // The root page of your application MainPage = MainPage = new NavigationPage(new SectionFeedsPage()); } احرص على استخدام فضاء الاسم Pages لكي تستطيع الوصول إلى الصفحة SectionFeedsPage كما يلي: using BasicFeedReader.Pages; ستضع السطر السابق أوّل الملف App.cs كما هو معلوم. نفّذ البرنامج، ستحصل على شكل شبيه بما يلي: وهي الواجهة التي تحتوي على الخلاصات الموجودة ضمن قسم مقالات البرمجة. جرّب اختيار أحد هذه الخلاصات لتحصل على شكل شبيه بما يلي: لاحظ كيف تظهر الخلاصة كما لو أنّه يتم عرضها ضمن متصفّح الويب العادي. جرّب سحب الصفحة إلى الأسفل ليؤكّد ذلك هذه الملاحظة. الخلاصة تناولنا في هذا الدرس الجزء الأوّل من تطبيق قارئ الخلاصات الخاص بموقع أكاديميّة حسّوب. حيث نفّذنا بعض المهام الأساسيّة، والتي سنبني عليها في الجزء الثاني الذي سيتناول تطبيقًا محسّنًا لهذا التطبيق. حيث سنعمل على دعم عرض جميع الأقسام المتاحة في الأكاديميّة وليس قسم مقالات البرمجة فحسب.
  16. هذا الدرس هو الجزء الثالث والأخير من سلسلة دروس تُعنى بكيفيّة بناء تطبيق عملي بسيط لإدارة جهات اتصال ببيانات أوليّة وهو بطبيعة الحال جزء من سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms. ستحتاج إلى قراءة الجزأين الأوّل والثاني السابقين لكي تستطيع المتابعة في هذا الدرس. سنهتم في هذا الدرس ببناء واجهتي التطبيق: الواجهة الرئيسيّة التي يمكن من خلالها البحث عن جهات الاتصال حسب الاسم والكنية، وأيضًا إضافة جهة اتصال جديدة. الواجهة الخاصة بعرض تفاصيل جهة الاتصال التي تمّ اختيارها من الواجهة الرئيسيّة، ومن ثمّ إمكانيّة تعديل بياناتها أو حتى حذفها. بالإضافة إلى تعديل الصنف App لكي يصبح التطبيق قابل للعمل. الواجهة الرئيسيّة للتطبيق ContactsPage سنحتاج في البداية إلى إضافة مجلّد جديد سنسمّه Pages سنضع فيه أي صفحة جديدة للتطبيق، وهذا الإجراء هو من باب تنظيم مكوّنات التطبيق فحسب. من نافذة مستكشف الحل Solution Explorer انقر بزر الفأرة الأيمن على اسم المشروع ContactsApp (Portal) ثم اختر من القائمة التي ستظهر الخيار Add. من القائمة الفرعية، اختر New Folder ثمّ سمّه Pages. انقر بزر الفأرة الأيمن على المجلّد الذي أضفته توًا وهو Pages واختر من القائمة Add ثم اختر من القائمة الفرعية New Item لتظهر نافذة تسمح باختيار العنصر الجديد الذي تودّ إضافته. اختر صفحة محتوى تعتمد على الرماز كما وأن سبق لنا أن فعلنا ذلك في هذا الدرس. سمّ هذه الصفحة ContactsPage. انتقل الآن إلى الملف ContactsPage.xaml واحرص على أن تكون محتوياته على الشكل التالي: <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="ContactsApp.Pages.ContactsPage" Appearing ="ContactsPage_Appearing"> <StackLayout> <StackLayout Padding="5,25,5,5"> <StackLayout Orientation="Horizontal"> <Label Text="First Name" /> <Editor x:Name="txtFirstName" HorizontalOptions="FillAndExpand" TextChanged="Editor_TextChanged"/> </StackLayout> <StackLayout Orientation="Horizontal"> <Label Text="Last Name" /> <Editor x:Name="txtLastName" HorizontalOptions="FillAndExpand" TextChanged="Editor_TextChanged"/> </StackLayout> <Button Text="Find" x:Name="btnFind" Clicked="btnFind_Clicked"/> </StackLayout> <StackLayout> <ListView x:Name="lsvContacts" ItemTapped="lsvContacts_ItemTapped"/> </StackLayout> <Button Text="+ New Contact" HorizontalOptions="FillAndExpand" Clicked="btnNewContact_Clicked"/> </StackLayout> </ContentPage> لقد استخدمنا أربعة أحداث مختلفة في هذه الصفحة سنورد وصفًا قصيرًا لكل منها فيما يلي: حدث الظهور Appearing للصفحة ContactsPage وقد ربطناه بالمعالج ContactsPage_Appearing وذلك لتحديث بيانات الصفحة عند العودة من الصفحة المسؤولة عن عرض تفاصيل جهة الاتصال كما سنرى لاحقًا في هذا الدرس. حدث تغيّر النص TextChangedلكلّ من العنصرين txtFirstName و txtLastName وقد ربطناه بالمعالج Editor_TextChanged وذلك لمسح نتائج البحث التي تظهر ضمن القائمة lsvContacts عند أي تعديل يجريه المستخدم فيهما. حدث لمس المُدخل ضمن القائمة lsvContacts وربطناه بالمعالج lsvContacts_ItemTapped وذلك لكي ينتقل البرنامج إلى الواجهة المسؤولة عن عرض تفاصيل جهة الاتصال عند لمسها. حدث النقر Clicked لزر إضافة جهة اتصال جديدة وربطناه بالمعالج btnNewContact_Clicked. انتقل بعد ذلك إلى ملف الشيفرة البرمجيّة الموافق للملف السابق وهو ContactsPage.xaml.cs واحرص على أن تكون محتوياته على الشكل التالي: using System; using Xamarin.Forms; using ContactsApp.Entities; namespace ContactsApp.Pages { public partial class ContactsPage : ContentPage { public ContactsPage() { InitializeComponent(); } private async void DoFind() { string firstName = txtFirstName.Text == null ? "" : txtFirstName.Text; string lastName = txtLastName.Text == null ? "" : txtLastName.Text; lsvContacts.ItemsSource = await((App)Application.Current).ContactsRepository .GetContactsAsync(firstName, lastName); } private void btnFind_Clicked(object sender, EventArgs e) { DoFind(); } private void Editor_TextChanged(object sender, TextChangedEventArgs e) { if (lsvContacts.ItemsSource != null) lsvContacts.ItemsSource = null; } private async void lsvContacts_ItemTapped(object sender, ItemTappedEventArgs e) { Contact selectedContact = (Contact)e.Item; ContactDetailsPage ContactDetailsPage = new ContactDetailsPage(selectedContact); await Navigation.PushAsync(ContactDetailsPage); } private void ContactsPage_Appearing(object sender, EventArgs e) { DoFind(); } private async void btnNewContact_Clicked(object sender, EventArgs e) { ContactDetailsPage ContactDetailsPage = new ContactDetailsPage(null); await Navigation.PushAsync(ContactDetailsPage); } } } يحتوي هذا الملف على الصنف ContactsPage والذي يحتوي على معالجات الأحداث التي صرّحنا عنها في صفحة الرماز الموافقة له كما رأينا قبل قليل، بالإضافة إلى وجود تابع خدمي وهو DoFind ووظيفته إجراء عمليّة بحث وفقًا للمعايير التي يرغبها المستخدم (الاسم والكنية). الشيفرة البرمجيّة الموجودة ضمن معالجات الأحداث بسيطة وواضحة. ولكن أريد أن أتوقّف قليلًا عند الشيفرة البرمجيّة التي يستخدمها التابع الخدمي DoFind التي تنفّذ عمليّة البحث: string firstName = txtFirstName.Text == null ? "" : txtFirstName.Text; string lastName = txtLastName.Text == null ? "" : txtLastName.Text; lsvContacts.ItemsSource = await((App)Application.Current).ContactsRepository .GetContactsAsync(firstName, lastName); أوّل سطرين واضحان حيث يعملان على الحصول على معايير البحث التي يريدها المستخدم من مربّعي النص txtFirstName و txtLastName. أمّا السطر الأخير فهو يعمل على الاتصال بالمستودع لتنفيذ عمليّة البحث وإرجاع النتائج وذلك بإجراء استدعاء إلى التابع GetContactsAsync وتمرير معياري البحث إليه. انظر هذه العبارة: await((App)Application.Current).ContactsRepository .GetContactsAsync(firstName, lastName); تعمل الخاصية Application.Current على إرجاع كائن من النوع Application يمثّل التطبيق الحالي الذي نعمل من خلاله. والذي يحتاج بدوره إلى عملية تحويل cast باستخدام التحويل (App) إلى كائن من النوع App وهو الصنف الأساسي في التطبيق. في الحقيقة لقد صرّحت عن الخاصيّة ContactsRepository في الصنف App ليتم الوصول للمستودع من أيّ مكان من تطبيقنا. سنرى التصريح عن هذه الخاصيّة بعد قليل. واجهة تفاصيل جهة الاتصال ContactDetailsPage أضف هذه الواجهة بنفس الأسلوب الذي اتبعناه عند إضافة ملف الواجهة الرئيسيّة، أي إلى المجلّد Pages. على أن يكون اسمها ContactDetailsPage. سيصبح مستكشف الحل لديك شبيه بما يلي: انتقل إلى ملف الرماز ContactDetailsPage.xaml واحرص على أن تكون محتوياته على الشكل التالي: <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="ContactsApp.Pages.ContactDetailsPage"> <StackLayout Orientation="Vertical" Padding="5,25,5,5"> <Label Text="FirstName" /> <Entry x:Name ="txtFirstName"/> <Label Text="LastName" /> <Entry x:Name ="txtLastName"/> <Label Text="Tel" /> <Entry x:Name ="txtTel"/> <Label Text="EMail" /> <Entry x:Name ="txtEMail"/> <Label Text="Hobbies" /> <Editor x:Name ="txtHobbies"/> <StackLayout Orientation="Horizontal"> <Button Text="Save" x:Name="btnSave" Clicked="btnSave_Clicked"/> <Button Text="Delete" x:Name="btnDelete" Clicked="btnDelete_Clicked"/> </StackLayout> </StackLayout> </ContentPage> واضح أنّه ملف بسيط. هناك حدثان قد صرّحنا عنهما في هذه الصفحة وهما: حدث النقر لزر الحفظ Clicked وقد ربطناه بالمعالج btnSave_Clicked وهو مسؤول عن عمليتي الحفظ والإضافة. حدث النقر لزر الحذف Clicked وقد ربطناه بالمعالج btnDelete_Clicked وهو مسؤول عن حذف جهة الاتصال. انتقل إلى ملف الشيفرة البرمجيّة الموافق لملف الرماز السابق واسمه ContactDetailsPage.xaml.cs واحرص على أن تكون محتوياته على الشكل التالي: using System; using Xamarin.Forms; using ContactsApp.Entities; namespace ContactsApp.Pages { public partial class ContactDetailsPage : ContentPage { private Contact currentContact; public ContactDetailsPage(Contact contact) { InitializeComponent(); this.currentContact = contact; if (this.currentContact != null) { txtFirstName.Text = contact.FirstName; txtLastName.Text = contact.LastName; txtEMail.Text = contact.EMail; txtTel.Text = contact.Tel; txtHobbies.Text = contact.Hobbies; Title = contact.ToString() + " Details"; btnDelete.IsVisible = true; } else { Title = "New Contact"; btnDelete.IsVisible = false; } } private async void btnSave_Clicked(object sender, EventArgs e) { string firstName = txtFirstName.Text == null ? "" : txtFirstName.Text; string lastName = txtLastName.Text == null ? "" : txtLastName.Text; string tel = txtTel.Text == null ? "" : txtTel.Text; string email = txtEMail.Text == null ? "" : txtEMail.Text; string hobbies = txtHobbies.Text == null ? "" : txtHobbies.Text; if (this.currentContact != null) { this.currentContact.FirstName = firstName; this.currentContact.LastName = lastName; this.currentContact.EMail = tel; this.currentContact.Tel = email; this.currentContact.Hobbies = hobbies; await ((App)Application.Current).ContactsRepository .UpdateContactAsync(this.currentContact); } else { Contact contact = new Contact { FirstName = firstName, LastName = lastName, Tel = tel, EMail = email, Hobbies = hobbies, }; await ((App)Application.Current).ContactsRepository .AddContactAsync(contact); } await Navigation.PopAsync(); } private async void btnDelete_Clicked(object sender, EventArgs e) { var result = await DisplayAlert("Delete Confirmation", "Are you sure you want to delete this contact?", "Yes", "No"); if (result) { await ((App)Application.Current).ContactsRepository .DeleteContactAsync(this.currentContact); await Navigation.PopAsync(); } } } } كما وأوضحنا مسبقًا أنّ وظيفة هذه الواجهة هي عرض تفاصيل جهة اتصال وتعديلها، مع إمكانيّة حذفها، بالإضافة إلى استخدام هذه الواجهة في إضافة جهة اتصال جديدة أيضًا. تميّز هذه الواجهة الغرض المطلوب منها عن طريق كائن من النوع Contact يُمرّر كوسيط إلى بانيتها. إذا كان هذا الوسيط يحتوي على كائن صالح من النوع Contact فهذا يعني أنّنا نريد عرض جهة الاتصال التي يمثّلها هذا الكائن، ومن ثمّ تعديلها أو حذفها، ويقتضي ذلك بالطبع إظهار زر الحذف Delete. أمّا في حال تمّ تمرير null كوسيط إلى البانية، فهذا يعني أنّه تمّ استدعاء الصفحة لإنشاء جهة اتصال جديدة تمامًا، وبالتالي إخفاء زر الحذف Delete لأنّه لن يكون له معنى في هذه الحالة. يتم حفظ نسخة من الكائن الممرّر ضمن حقل خاص ضمن الصنف اسمه currentContact. ويتم تحديد الغاية من الواجهة ضمن البانية نفسها. انظر إلى تعريف معالج الحدث btnSave_Clicked من الشيفرة السابقة وانظر كيف يتعامل مع الحالتين السابقتين (تعديل أو إضافة). الصنف App انتقل إلى الملف App.cs واحرص على أن تكون محتوياته على الشكل التالي: using Xamarin.Forms; using ContactsApp.Abstract; using ContactsApp.Concrete; using ContactsApp.Pages; namespace ContactsApp { public class App : Application { public IContactsRepository ContactsRepository { get; set; } public App() { ContactsRepository = new MemoryContactsRepository(); // The root page of your application MainPage = new NavigationPage(new ContactsPage()); } protected override void OnStart() { // Handle when your app starts } protected override void OnSleep() { // Handle when your app sleeps } protected override void OnResume() { // Handle when your app resumes } } } لاحظ بدايةّ الخاصيّة ContactsRepository من النوع IContactsRepository الموجود ضمن تعريف الصنف App: public IContactsRepository ContactsRepository { get; set; } في الحقيقة ستمثّل هذه الخاصيّة المستودع الذي سنتبادل البيانات من خلاله. سنعمل على إنشاء كائن جديد من النوع MemoryContactsRepository ومن ثمّ نسنده إلى هذه الخاصيّة وذلك ضمن بانية الصنف App كما يلي: ContactsRepository = new MemoryContactsRepository(); وهذا الأمر جائز تمامًا لأنّ الصنف MemoryContactsRepositroy يحقّق الواجهة IContactsRepository فهو بمثابة وارث منها. بما أنّ هذه الخاصيّة عامّة public فسيكون بإمكان جميع أجزاء التطبيق الوصول للكائن ContactsRepository وبالتالي التعامل مع البيانات من خلال مكان واحد. لاحظ أيضًا من بانية الصنف App كيف أنشأنا كائن جديد من الصنف NavigationPage وأسندناه إلى الخاصيّة MainPage للصنف App. وذلك لأنّنا نريد أن يدعم تطبيقنا ميزة التنقّل بين الصفحات التي تحدثنا عنها في هذا الدرس. يمكنك الآن تنفيذ التطبيق وتجربة جميع المزايا التي يتمتّع بها. الخلاصة نكون بهذا الدرس قد أنهينا بناء تطبيق جهات الاتصال، حيث تحدثنا عن كيفيّة بناء واجهتي التطبيق، وكيفيّة التنقّل بين هاتين الواجهتين، وكيف تتصّلان بالمستودع عند الحاجة للتعامل مع مصدر البيانات الذي يكون في تطبيقنا هذا عبارة عن مجموعة تتكوّن من عناصر من النوع Contact موجودة في ذاكرة التطبيق.
  17. سنتابع في هذا الدرس من سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms العمل الذي بدأناه في الدرس السابق والمتمثّل ببناء تطبيق جهات الاتصال. قد أنهينا في الدرس السابق بناء نموذج المستودع من خلال التصريح عن الواجهة IContactsRepository وتحقيقها من خلال الصنف MemoryContactsRepository. كما أنشأنا الصنف Contacts الذي يمثّل حجر البناء الأساسي في التطبيق. سنضيف في هذا الدرس النواحي الوظيفيّة للصنف المستودع MemoryContactsRepository لكي يصبح تطبيقنا قابلًا للعمل. تجهيز النواحي الوظيفيّة للمستودع افتح الملف MemoryContactsRepository.cs واحرص على أن تكون محتوياته على الشكل التالي: using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Collections.ObjectModel; using ContactsApp.Abstract; using ContactsApp.Entities; namespace ContactsApp.Concrete { public class MemoryContactsRepository : IContactsRepository { private ObservableCollection<Contact> contacts; public MemoryContactsRepository() { contacts = new ObservableCollection<Contact>() { new Contact() { Id=1, FirstName = "Ahmad", LastName="Saeed", Tel="123456", EMail="admin@example.com", Hobbies="Swimming" }, new Contact() { Id=2, FirstName = "Mahmood", LastName="Maktabi", Tel="852136", EMail="info@example.com", Hobbies="Reading" }, new Contact() { Id=3, FirstName = "Mazen", LastName="Najem", Tel="987456", EMail="it@example.com", Hobbies="Swimming" }, new Contact() { Id=4, FirstName = "Sawsan", LastName="Hilal", Tel="741258", EMail="sales@example.com", Hobbies="Writing, Reading" }, new Contact() { Id=5, FirstName = "Musab", LastName="Aga", Tel="357159", EMail="admin@example.com", Hobbies="Sport" } }; } public async Task<ObservableCollection<Contact>> GetContactsAsync(string firstName, string lastName) { return await Task.Factory.StartNew(() => { IEnumerable<Contact> result = from contact in contacts where contact.FirstName .ToUpper() .Contains(firstName.ToUpper()) && contact.LastName .ToUpper() .Contains(lastName.ToUpper()) select contact; ObservableCollection<Contact> tmp = new ObservableCollection<Contact>(result); return tmp; }); } public async Task<bool> AddContactAsync(Contact contactToAdd) { return await Task.Factory.StartNew(() => { contactToAdd.Id = contacts.Count() + 1; contacts.Add(contactToAdd); return true; }); } public async Task<bool> UpdateContactAsync(Contact contactToUpdate) { return await Task.Factory.StartNew(() => { Contact result = (from contact in contacts where contact.Id == contactToUpdate.Id select contact).FirstOrDefault(); if (result != null) { contactToUpdate.FirstName = result.FirstName; contactToUpdate.LastName = result.LastName; contactToUpdate.EMail = result.EMail; contactToUpdate.Tel = result.Tel; contactToUpdate.Hobbies = result.Hobbies; return true; } else { return false; } }); } public async Task<bool> DeleteContactAsync(Contact contactToDelete) { return await Task.Factory.StartNew(() => { var result = (from contact in contacts where contact.Id != contactToDelete.Id select contact); if (result != null) { contacts = new ObservableCollection<Contact>(result); contactToDelete = null; return true; } else { return false; } }); } } } الجديد هنا أنّنا قد أسندنا شيفرة برمجيّة لكل من التوابع الأساسيّة الموجودة في المستودع. انظر إلى الفقرات التالية التي تشرح عمل الشيفرة البرمجيّة ضمن كل تابع. تابع البحث GetContactsAsync فيما يلي التابع GetContactsAsync والذي يتطلّب وسيطين من النوع string للبحث حسب الاسم والكنية لجهات الاتصال: public async Task<ObservableCollection<Contact>> GetContactsAsync(string firstName, string lastName) { return await Task.Factory.StartNew(() => { IEnumerable<Contact> result = from contact in contacts where contact.FirstName .ToUpper() .Contains(firstName.ToUpper()) && contact.LastName .ToUpper() .Contains(lastName.ToUpper()) select contact; ObservableCollection<Contact> tmp = new ObservableCollection<Contact>(result); return tmp; }); } واضح أنّ هذه الشيفرة تقوم بإنشاء مهمة جديدة (تابع على شكل تعبير lambda) عن طريق التابع Task.Factory.StartNew (ستحتاج إلى إنعاش ذاكرتك بهذا الدرس) وذلك باستخدام تقنية البرمجة غير المتزامنة لمنع جمود التطبيق كما نعلم. المتغيّر result الذي تراه في الشيفرة السابق هو من النوع IEnumerable<Contact> أي مجموعة قابلة للعد عناصرها من النوع Contact، وهو يحصل على هذه المجموعة من خلال استعلام LINQ To Objects بسيط: from contact in contacts where contact.FirstName .ToUpper() .Contains(firstName.ToUpper()) && contact.LastName .ToUpper() .Contains(lastName.ToUpper()) select contact; تعمل هذه الشيفرة ببساطة على الاستعلام عن جميع جهات الاتصال الموجودة ضمن المتغير contacts والتي تحتوي على عبارتي البحث الخاصّتين بالاسم والكنية بنفس الوقت. إذا كان لديك خبرة باستعلامات SQL فستجد LINQ to Objects مألوفة. لاحظ وجود عبارتي return ضمن هذا التابع GetContactsAsync. العبارة التي تأتي أولًا هي العبارة المسؤولة عن إرجاع كائن من النوع Task<ObservableCollection<Contact>> أمّا العبارة الثانيّة التي تأتي في الأسفل فهي المسؤولة عن إرجاع كائن من النوع Task<ObservableCollection<Contact>> من التابع الداخلي وهو عبارة عن تعبير lambda والذي يتم تنفيذه من خلال التابع Task.Factory.StartNew كما هو واضح. في آخر سطرين من التابع الداخلي (تعبير lambda) نعمل على تقديم نتيجة البحث على شكل مجموعة عموميّة وهي ObservableCollection<Contact> حيث يتم تحويلها ضمنيًّا إلى كائن من النوع Task<ObservableCollection<Contact>>. تابع إضافة جهة اتصال جديد AddContactAsync التابع AddContactAsync يتطلّب وسيطًا واحدًا فقط من النوع Contact ويُرجع كائن من النوع Task<bool> للإشارة إلى نجاح عمليّة الإضافة: public async Task<bool> AddContactAsync(Contact contactToAdd) { return await Task.Factory.StartNew(() => { contactToAdd.Id = contacts.Count() + 1; contacts.Add(contactToAdd); return true; }); } تعمل هذه الشيفرة على إضافة جهة اتصال جديدة إلى جهات الاتصال الموجودة مسبقًا ضمن المتغيّر contacts مع الانتباه إلى هذه العبارة البرمجيّة: contactToAdd.Id = contacts.Count() + 1; ما تفعله هذه العبارة غير موجود في أيّ تطبيق عمليّ حقيقي. فهي تُسند قيمة للخاصيّة Id لجهة الاتصال الممرّرة إلى التابع. لا ينبغي لأي تطبيق أن يقوم بهذا العمل، فهذا الرقم ينبغي أن يتم توليده تلقائيًّا عند إضافة جهة الاتصال إلى قاعدة البيانات. وبما أنّ تطبيقنا يعتمد على بيانات وهمية موجودة في الذاكرة فكان لزامًا علينا القيام بمثل هذا الأمر لتمييز جهات الاتصال المضافة حديثًا. تابع الحذف DeleteContactAsync التابع DeleteContactAsync يتطلّب وسيطًا واحدًا فقط من النوع Contact ويُرجع كائن من النوع Task<bool> للإشارة إلى نجاح عمليّة الحذف: public async Task<bool> DeleteContactAsync(Contact contactToDelete) { return await Task.Factory.StartNew(() => { var result = (from contact in contacts where contact.Id != contactToDelete.Id select contact); if (result != null) { contacts = new ObservableCollection<Contact>(result); contactToDelete = null; return true; } else { return false; } }); } تعمل الشيفرة السابقة في الواقع على فلترة جهة الاتصال المراد حذفها مما يعني ببساطة أنّ استعلام LINQ to Objects سيعمل على إرجاع جميع جهات الاتصال باستثناء تلك التي يكون قيمة الخاصية Id لها مطابقة لقيمة الخاصيّة Id لجهة الاتصال التي نرغب بحذفها. ومن ثمّ يتم إسناد النتيجة إلى المتغيّر contacts مما يعني فعليًّا أنّنا قد حذفنا جهة الاتصال هذه من الذاكرة. تابع التحديث UpdateContactAsync التابع UpdateContactAsync والذي يتطلّب وسيطًا واحدًا فقط من النوع Contact ويُرجع كائن من النوع Task<bool> للإشارة إلى نجاح عمليّة الحذف: public async Task<bool> UpdateContactAsync(Contact contactToUpdate) { return await Task.Factory.StartNew(() => { Contact result = (from contact in contacts where contact.Id == contactToUpdate.Id select contact).FirstOrDefault(); if (result != null) { contactToUpdate.FirstName = result.FirstName; contactToUpdate.LastName = result.LastName; contactToUpdate.EMail = result.EMail; contactToUpdate.Tel = result.Tel; contactToUpdate.Hobbies = result.Hobbies; return true; } else { return false; } }); } تخضع هذه الشيفرة البرمجيّة لنفس المبدأ: يبحث استعلام LINQ to Objects عن جهة الاتصال مطلوبة ضمن جهات الاتصال الموجودة ضمن المتغيّر contacts حسب قيمة الخاصيّة Id لجهة الاتصال، وبعد الحصول عليها، يتم تحديث قيم الخصائص الأخرى كما هو واضح. بهذه الطريقة أصبح نموذج المستودع جاهزًا لوضعه في الاستخدام. حيث ستتعامل معه جميع مكوّنات التطبيق لإنجاز أربعة أنواع مختلفة من العمليّات على البيانات: البحث، والإضافة، والتعديل، والحذف. الخلاصة تناولنا في هذا الدرس كيفيّة بناء نموذج المستودع الذي يمثّله الصنف MemoryContactsRepository والذي يحقّق كما نعلم الواجهة IContactsRepository حيث تعرّفنا على التوابع الأربعة ضمنه التي تسمح لمكوّنات التطبيق بالتعامل مع البيانات دون الاهتمام بمكان وجود هذه البيانات. اطلعنا أيضًا على كيفيّة توظيف تقنيّة الاستعلام LINQ to Objects ضمن التوابع الأربعة لتنفيذ المهام المطلوبة من هذا المستودع. سنبدأ في الدرس التالي ببناء واجهات التطبيق. حقوق الصورة البارزة محفوظة لـ Freepik
  18. سنبدأ في هذا الدرس من سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms ببناء تطبيق عملي بمعايير تقنيّة عالية. حيث سنستخدم المعارف التي حصلنا عليها من الدروس السابقة في بناء تطبيق جهات اتصال بسيط لكنّه يستخدم تقنيّات ومفاهيم متقدّمة نسبيًّا. سنتناول هذا التطبيق على ثلاثة أجزاء متتالية، إليك وصف مختصر لمحتوى كلّ منها: الجزء الأوّل: شرح الغاية من التطبيق، وتوضيح فكرة نموذج المستودع Repository في بناء التطبيقات، مع بناء الهيكل العام للتطبيق، وهذا هو محتوى هذا الدرس. الجزء الثاني: تجهيز النواحي الوظيفيّة للمستودع وجعله قابلًا للاستخدام. الجزء الثالث: تنفيذ واجهتي التطبيق الرئيسية والفرعيّة الخاصّة بعرض التفاصيل. وتنفيذ عمليّة التنقّل بين الواجهتين الغاية من التطبيق وكيف يعمل فكرة التطبيق بسيطة للغاية، تتلخّص بعرض جهات اتصال موجودة مسبقًا وإمكانية البحث ضمنها، مع إمكانيّة إضافة جهات اتصال جديدة وتحريرها وحذفها. يعتمد التطبيق على وجود واجهتين. الواجهة الأولى هي الواجهة الرئيسيّة وتحتوي على قسم خاص بالبحث حسب الاسم أو الكنية عن أيّ جهة اتصال موجودة مسبقًا، بالإضافة إلى قائمة لعرض جهات الاتصال الناتجة عن عمليّة البحث، وأخيرًا زر خاص بإضافة جهات اتصال جديدة. انظر الشكل التالي الذي ينتج عند ضغط زر البحث FIND عند عدم تحديد أي معيار للبحث: عندما يقوم المستخدم بنقر زر البحث FIND دون أن يحدّد أي معيار، سيقوم التطبيق بعرض جميع جهات الاتصال الموجودة لديه، والتي ستكون في هذه النسخة من البرنامج عبارة عن بيانات وهمية موجودة ضمن ذاكرة التطبيق. أمّا عند تحديد المستخدم للاسم أو الكنيّة فسيعمل التطبيق على البحث مستخدمًا منطق AND. أمّا الواجهة الثانية، فتظهر عندما يلمس المستخدم إحدى جهات الاتصال من القائمة السابقة، حيث تعرض هذه الواجهة بيانات تفصيليّة حول جهة الاتصال هذه: الاسم والكنية ورقم الهاتف وعنوان البريد الإلكتروني والهوايات. انظر إلى الشكل التالي: من الممكن تعديل أيّ من هذه البيانات ثم ينقر المستخدم زر الحفظ لحفظها، أو أن ينقر زر الرجوع إلى الواجهة السابقة الموجود في الأعلى بجانب أيقونة البرنامج في حال لم يرغب بتعديل البيانات. كما يمكن للمستخدم أن يحذف جهة الاتصال هذه بنقره على زر الحذف Delete كما يظهر من الشكل السابق. وهذه ببساطة فكرة التطبيق. نموذج المستودع Repository عندما تكبر التطبيقات وتتنوّع المهام المطلوبة منها تبرز الحاجة لوسيلة لتنظيم العمل داخل التطبيق. في الحقيقة توجد العديد من النماذج التي تدعمها Xamarin لهذه الغاية مثل نموذج MVVM الذي يستخدم بفعالية ضمن Xamarin لتنظيم وفصل الأجزاء المسؤولة عن الواجهات عن الأجزاء المسؤولة عن منطق العمل عن تلك المسؤولة عن التعامل مع مزودات البيانات البعيدة أو المحلية باختلاف أنواعها. من النماذج التي أفضلها شخصيًّا هو نموذج المستودع Repository الذي أستخدمه على نحو واسع في جميع أنواع التطبيقات التي أعمل عليها. فهو أسلوب جميل ومنطقي ويسمح بتطوير التطبيق بشكل سلس وسريع للعمل في مختلف أنواع البيئات، وهو متوافق للعمل مع نموذج MVVM. يسمح نموذج المستودع بعزل الشيفرة البرمجيّة المسؤولة عن التعامل مع البيانات عن منطق البرنامج business logic. وفي هذا الأمر عدة فوائد من أهمّها: تنظيم البرنامج، وجعله أكثر قابليّة للفهم والتطوير. إجراء تطوير على أسلوب التعامل مع البيانات دون إجراء أي تغيير في منطق عمل البرنامج. إمكانيّة إجراء تغيير جذري لنوع الخدمة التي نستخدمها لتخزين البيانات دون تغيير يُذكر في منطق العمل. سأخوض مباشرةً في كيفية اعتماد هذا النموذج في تطبيقنا هذا. حيث سنحتاج إلى استخدام واجهة واحدة Interface مع صنف واحد يُحقّقها. لتنعش ذاكرتك حول الواجهات انظر هذا الدرس. لنبدأ الآن في بناء هذا التطبيق وذلك في الفقرة التالية. بناء التطبيق ابدأ بإنشاء مشروع جديد من النوع Blank App (Xamarin.Forms Portable) وسمّه ContactsApp ثم أبق فقط على المشروعين ContactsApp (Portable) و ContactsApp.Droid كما وسبق أن فعلنا في هذا الدرس. من نافذة مستكشف الحل Solution Explorer انقر بزر الفأرة الأيمن على المشروع ContactsApp واختر من القائمة التي ستظهر الخيار Add ثم من القائمة الفرعية الخيار New Folder لإضافة مجلّد جديد. سمّ هذا المجلّد بالاسم Entities، وبعد أن يظهر في نافذة الحل Solution Explore انقر عليه بزر الفأرة الأيمن واختر الخيار Add ومن القائمة الفرعية اختر Class. ستظهر نافذة تسمح لك بتعيين اسم لهذا الصنف. اختر الاسم Contact له. هذا الصنف هو حجر البناء الأساسي لهذا البرنامج والذي يمثّل منطق العمل فيه. احرص على جعل محتويات الملف Contact.cs كما يلي: namespace ContactsApp.Entities { public class Contact { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Tel { get; set; } public string EMail { get; set; } public string Hobbies { get; set; } public override string ToString() { return string.Concat(FirstName, " ", LastName); } } } يحتوي الصنف Contact كما يظهر من الشكل السابق على البيانات الأساسيّة التي تحتاجها أيّة جهة اتصال، بالإضافة إلى خاصيّة الهوايات Hobbies التي قد تبدو غريبة قليلًا بالنسبة لجهة اتصال. انقر مرّة أخرى بزر الفأرة الأيمن على المشروع ContactsApp ثم اختر من القائمة التي ستظهر الخيار Add ثم من القائمة الفرعية الخيار New Folder لإضافة مجلّد جديد. سمّ هذا المجلّد بالاسم Abstract، وبعد أن يظهر في نافذة الحل Solution Explore انقر عليه بزر الفأرة الأيمن واختر الخيار Add ومن القائمة الفرعية اختر New Item. ستظهر نافذة تسمح لك بتعيين نوع العنصر المراد إضافته. اختر واجهة Interface وعيّن الاسم IContactsRepository لها. واحرص على أن تكون محتويات الملف IContactsRepository.cs كما يلي: using System.Threading.Tasks; using System.Collections.ObjectModel; using ContactsApp.Entities; namespace ContactsApp.Abstract { public interface IContactsRepository { Task<ObservableCollection<Contact>> GetContactsAsync(string firstName, string lastName); Task<bool> AddContactAsync(Contact contactToAdd); Task<bool> UpdateContactAsync(Contact contactToUpdate); Task<bool> DeleteContactAsync(Contact contactToDelete); } } تُستَخدَم الواجهات عمومًا عندما نرغب بتجريد Abstraction الأمور وجعلها عموميّةً وفي ذلك فائدة كبيرة في جعل الشيفرة البرمجيّة أكثر قابليّة للفهم ولإعادة الاستخدام. وهذا سبب إضافة هذه الواجهة إلى المجلّد Abstract. لا تحتوي الواجهات على أيّة شيفرة برمجيّة كما نعلم، فكل ما تحتويه هو عبارة عن تصاريح لتوابع يجب تحقيقها ضمن أيّ صنف يرغب بتحقيق هذه الواجهة. تحتوي هذه الواجهة باختصار على العمليّات الأساسيّة التي يحتاجها تطبيقنا لإنجاز المهام المنوطة به وهي: الحصول على جهات الاتصال حسب الاسم والكنية GetContactsAsync، وإضافة جهة اتصال جديدة AddContactAsync، وتحديث جهة اتصال موجودة مسبقًا UpdateContactAsync، وحذف جهة اتصال DeleteContactAsync. أمّا سبب وجود الكلمة Async في كلّ من هذه التوابع فهو للإشارة إلى أنّه يُفترض بها أن تستخدم تقنيّة البرمجة غير المتزامنة Asynchronous Programming التي تحدثنا عنها في هذا الدرس. المثير في الأمر أنّ هذه الواجهة لا تهتم بمكان وجود البيانات أو كيفيّة الحصول عليها والتعامل معها. إنّما تهتم فقط بما يحتاجه التطبيق وبشكل مجرّد. سنكرّر الآن نفس العمليّة لإضافة مجلّد جديد ضمن المشروع ContactsApp.cs واسمه Concrete وهو الذي سيحتوي على الصنف الذي سيحقّق الواجهة IContactsRepository السابقة. انقر بزر الفأرة الأيمن على هذا المجلّد واختر Add. ومن القائمة الفرعية اختر Class. سمّ هذا الصنف بالاسم MemoryContactsRepository واحرص على أن تكون محتوياته كما يلي: using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Collections.ObjectModel; using ContactsApp.Abstract; using ContactsApp.Entities; namespace ContactsApp.Concrete { public class MemoryContactsRepository : IContactsRepository { private ObservableCollection<Contact> contacts; public MemoryContactsRepository() { contacts = new ObservableCollection<Contact>() { new Contact() { Id=1, FirstName = "Ahmad", LastName="Saeed", Tel="123456", EMail="admin@example.com", Hobbies="Swimming" }, new Contact() { Id=2, FirstName = "Mahmood", LastName="Maktabi", Tel="852136", EMail="info@example.com", Hobbies="Reading" }, new Contact() { Id=3, FirstName = "Mazen", LastName="Najem", Tel="987456", EMail="it@example.com", Hobbies="Swimming" }, new Contact() { Id=4, FirstName = "Sawsan", LastName="Hilal", Tel="741258", EMail="sales@example.com", Hobbies="Writing, Reading" }, new Contact() { Id=5, FirstName = "Musab", LastName="Aga", Tel="357159", EMail="admin@example.com", Hobbies="Sport" } }; } public async Task<ObservableCollection<Contact>> GetContactsAsync(string firstName, string lastName) { throw new System.NotImplementedException(); } public async Task<bool> AddContactAsync(Contact contactToAdd) { throw new System.NotImplementedException(); } public async Task<bool> UpdateContactAsync(Contact contactToUpdate) { throw new System.NotImplementedException(); } public async Task<bool> DeleteContactAsync(Contact contactToDelete) { throw new System.NotImplementedException(); } } } الأمر الملفت للنظر هنا أنّ بيانات جهات الاتصال موجودة ضمن هذا الصنف بالفعل وتحديدًا ضمن بانيته. وهي مخزّنة ضمن المتغيّر contacts وهو معرّف على مستوى الصنف ومن النوع العمومي ObservableCollection الذي سنتحدّث عنه في الدرس التالي. يكفي الآن أن تعرف أنّه عبارة عن مجموعة عناصرها كائنات من النوع Contact وهي تُفيد في التطبيقات التي تُستخدَم فيها البرمجة غير المتزامنة. من غير الواقعي بكل تأكيد وجود البيانات مخزّنة في الصنف بهذه الطريقة، فالمفترض أن تكون ضمن قاعدة بيانات محليّة أو بعيدة أو حتى ضمن ملف عادي. في الواقع تبرز هنا قوّة نموذج المستودع Repository في عزل أسلوب الحصول على البيانات عن البرنامج الفعلي. من الواضح أيضًا أنّ التوابع الموجودة هنا تحتوي في الحقيقة على شيفرة برمجيّة تؤدّي إلى رمي الاستثناء NotImplementedException وذلك لتذكرينا بعدم جاهزيتها بعد. سيبدو مستكشف الحل في نهاية المطاف شبيهًا بالشكل التالي: الخلاصة هذا الدرس هو المقدّمة لتطبيق جهات الاتصال الذي سنتابع بناءه على مدى الدرسين التاليين. تناولنا في هذا الدرس فكرة التطبيق الأساسيّة، وتوضيح فكرة نموذج المستودع Repository من خلال بناء واجهة تمثّله بالإضافة إلى صنف يحقّقها. سيمكننا من خلال هذا الصنف (صنف المستودع) التعامل مع بيانات موجودة ضمن ذاكرة التطبيق فقط. ورغم كون هذا الأسلوب غير واقعي، إلَّا أنّه ضروري في تبسيط الأمور وجعلها أسهل للفهم. كما أنشأنا صنف يمثّل جهة الاتصال في التطبيق. ورأينا ماهية العلاقة بينه وبين صنف المستودع، من خلال الاستدعاءات إلى التوابع الموجودة ضمن الصنف الأخير. حقوق الصورة البارزة محفوظة لـ Freepik
  19. تُعتبر التحويلات الهندسيّة Transforms من المفاهيم الرياضيّة الضروريّة في عالم البرمجة الرسوميّة. هناك ثلاثة أنواع من التحويلات الهندسيّة: الانسحاب Translation الدوران Rotation التحاكي Scale تعتمد التحويلات الهندسيّة في الأساس على المصفوفات Matrices. وهي بنى رياضيّة مهمّة تُعتبر العمود الفقري لأيّ تحويل هندسي. لحسن الحظ تبسّط Xamarin الأمر، وتجعل من استخدام التحويلات الثلاثة السابقة أمرًا يسيرًا. سنتحدث في هذا الدرس من سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms عن كلّ نوع من الأنواع الثلاثة السابقة وكيفيّة تطبيقه ضمن مثال عملي بسيط. الانسحاب Translation الانسحاب هو الانتقال دون التغيير في حجم الجسم، أو إجراء أي عمليّة تدوير له. يتم تدوير أي عنصر من الصنف VisualElement عن طريق الخاصيّتين TranslationX و TranslationY. عند إسناد قيمة موجبة للخاصيّة TranslationX فإنّ ذلك سيؤدّي إلى نقل الجسم أفقيًّا إلى اليمين (بالنسبة إلى موقعه الحالي). وعند إسناد قيمة موجبة للخاصيّة TranslationY فإنّ ذلك سيؤدّي إلى نقل الجسم عاموديًّا إلى الأسفل (بالنسبة إلى موقعه الحالي). لنبدأ باختبار هذا النوع من التحويلات. ابدأ بإنشاء مشروع جديد من النوع Blank App (Xamarin.Forms Portable) وسمّه TransformsApp، ثم أبق فقط على المشروعين TransformsApp (Portable) و TransformsApp.Droid كما وسبق أن فعلنا في هذا الدرس. بعد ذلك سنضيف صفحة محتوى تعتمد على رُماز XAML كما وسبق أن فعلنا في هذا الدرس سنسمّها TranslationPage. احرص على أن تكون محتويات هذه الصفحة على الشكل التالي: <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="TransformsApp.TranslationPage"> <StackLayout Padding="20, 10"> <Frame x:Name="frame" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" OutlineColor="Accent"> <Label Text="TEXT" FontSize="Large" /> </Frame> <Slider x:Name="xSlider" Minimum="-200" Maximum="200" Value="{Binding Source={x:Reference frame}, Path=TranslationX}" /> <Label Text="{Binding Source={x:Reference xSlider}, Path=Value, StringFormat='TranslationX = {0:F0}'}" HorizontalTextAlignment="Center" /> <Slider x:Name="ySlider" Minimum="-200" Maximum="200" Value="{Binding Source={x:Reference frame}, Path=TranslationY }" /> <Label Text="{Binding Source={x:Reference ySlider}, Path=Value, StringFormat='TranslationY = {0:F0}'}" HorizontalTextAlignment="Center" /> </StackLayout> </ContentPage> يستخدم الرماز السابق تقنية ربط البيانات التي تحدثنا عنها في هذا الدرس. حيث يتحكّم بموقع عنصر frame يحتوي على لصيقة ضمنه، وذلك عن طريق عنصري Slider. يتحكم العنصر العلوي بالانسحاب الأفقي، أمّا العنصر السفلي فيتحكم بالانسحاب الشاقولي. تتم هذه العملية من خلال ربط الخاصيّة Value من عنصر Slider المسمى xSlider بالخاصيّة TranslationX لعنصر frame. وكذلك الأمر بالنسبة لعنصر Slider المسمى ySlider حيث ترتبط الخاصية Value له بالخاصية TranslationY لعنصر frame. عدّل بانية الصنف App الموجودة في الملف App.cs لتصبح على الشكل التالي: public App() { // The root page of your application MainPage = new TranslationPage(); } نفّذ البرنامج لتحصل على خرج شبيه بما يلي: أجر بعض التجارب ولاحظ الانسيابية في هذه الحركة. الدوران Rotation يمكن تدوير أي عنصر مرئي في Xamarin وذلك بتحديد مركز الدوران وزاوية الدوران. يتم تحديد زاوية الدوران بالدرجات، وتشير القيم الموجبة لزاوية الدوران إلى الدوران باتجاه عقارب الساعة. يتم تحديد مركز دوران أي عنصر عن طريق الخاصيتين AnchorX و AnchorY له. كما يمكن تحديد زاوية الدوران من خلال الخاصيّة Rotation. إذا لم يتم تحديد قيمة للخاصيتين AnchorX و AnchorY فسيكون مركز الدوران هو نفسه مركز العنصر المرئي بشكل افتراضي. لنرى كيف يعمل ذلك عن طريق مثال بسيط. أضف إلى المشروع الحالي صفحة محتوى تعتمد على رُماز XAML كما وسبق أن فعلنا في هذا الدرس سنسمّها RotationPage. احرص على أن تكون محتويات هذه الصفحة على الشكل التالي: <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="TransformsApp.RotationPage"> <StackLayout Padding="20, 10"> <Frame x:Name="frame" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" OutlineColor="Accent"> <Label Text="TEXT" FontSize="Large" /> </Frame> <Slider x:Name="rotationSlider" Maximum="360" Value="{Binding Source={x:Reference frame}, Path=Rotation}" /> <Label Text="{Binding Source={x:Reference rotationSlider}, Path=Value, StringFormat='Rotation = {0:F0}'}" HorizontalTextAlignment="Center" /> <StackLayout Orientation="Horizontal" HorizontalOptions="Center"> <Stepper x:Name="anchorXStepper" Minimum="-1" Maximum="2" Increment="0.25" Value="{Binding Source={x:Reference frame}, Path=AnchorX}" /> <Label Text="{Binding Source={x:Reference anchorXStepper}, Path=Value, StringFormat='AnchorX = {0:F2}'}" VerticalOptions="Center"/> </StackLayout> <StackLayout Orientation="Horizontal" HorizontalOptions="Center"> <Stepper x:Name="anchorYStepper" Minimum="-1" Maximum="2" Increment="0.25" Value="{Binding Source={x:Reference frame}, Path=AnchorY}" /> <Label Text="{Binding Source={x:Reference anchorYStepper}, Path=Value, StringFormat='AnchorY = {0:F2}'}" VerticalOptions="Center"/> </StackLayout> </StackLayout> </ContentPage> يعتمد البرنامج السابق على تدوير عنصر frame يحتوي على لصيقة. سنستخدم لهذا الغرض عنصر Slider اسمه rotationSlider للتحكم بزاوية الدوران (عن طريق الربط مع الخاصية Rotation لعنصر frame). وسنستخدم أيضًا عنصري Stepper وهما anchorXStepper و anchorYStepper للتحكم بإحداثيي مركز الدوران (عن طريق الربط مع الخاصيّتين AnchorX و AnchorY لعنصر frame). لتنفيذ هذا البرنامج اذهب إلى بانية الصنف App الموجودة ضمن الملف App.cs واحرص على أن تكون على الشكل التالي: public App() { // The root page of your application MainPage = new RotationPage(); } نفّذ البرنامج لتحصل على شكل شبيه بما يلي: أجر بعض التجارب واستمتع بالبرنامج! التحاكي Scale التحاكي هو تحويل هندسي يؤدّي إلى التغيير في الأحجام. يمكن استخدام التحاكي للتحكم بأحجام العناصر المرئيّة عن طريق الخاصية Scale لها. لهذه الخاصيّة القيمة الافتراضيّة 1. عند استخدام أي قيمة أصغر من 1 يعني ذلك أنّنا سنعمل على تصغير الحجم. وعند استخدام أي قيمة أكبر من 1 يعني ذلك أنّنا سنكبّر الحجم. فمثًل القيمة 3 تعني أنّنا سنكبّر الحجم 3 مرات، وهكذا. القيمة 0 للخاصيّة Scale مسموحة ولكن ستؤدّي إلى اختفاء العنصر. كما يمكن استخدام القيم السالبة للخاصيّة Scale ولكن سيؤدّي ذلك إلى قلب العنصر مع بقاء المفهوم السابق على ما هو عليه. أي أنّ القيمة -1 ستؤدّي إل قلب العنصر لكن مع بقاء الحجم نفسه. لتجربة التحاكي أضف إلى المشروع الحالي صفحة محتوى تعتمد على رُماز XAML كما وسبق أن فعلنا في هذا الدرس سنسمّها ScalePage. احرص على أن تكون محتويات هذه الصفحة على الشكل التالي: <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="TransformsApp.ScalePage"> <StackLayout Padding="20, 10"> <Frame x:Name="frame" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" OutlineColor="Accent"> <Label Text="TEXT" FontSize="Large" /> </Frame> <Slider x:Name="scaleSlider" Minimum="-10" Maximum="10" Value="{Binding Source={x:Reference frame}, Path=Scale}" /> <Label Text="{Binding Source={x:Reference scaleSlider}, Path=Value, StringFormat='Scale = {0:F1}'}" HorizontalTextAlignment="Center" /> </StackLayout> </ContentPage> اذهب إلى بانية الصنف App الموجودة ضمن الملف App.cs واحرص على أن تكون على الشكل التالي: public App() { // The root page of your application MainPage = new ScalePage(); } نفّذ البرنامج لتحصل على شكل شبيه بما يلي: الخلاصة تحدثنا في هذا الدرس عن التحويلات الهندسية الأساسيّة: الانسحاب Translation والدوران Rotation والتحاكي Scale وكيفية التعامل معها من خلال Xamarin. في الحقيقة تكمن الحاجة لمثل هذه التحويلات غالبًا في تطبيقات الألعاب أو تلك التي تعتمد على الجانب الرسومي. سنعمل على تطبيق بعض من هذه التحويلات في الدروس القادمة من هذه السلسلة.
  20. تتكوّن تطبيقات الأجهزة المحمولة عادةً من صفحات منفصلة يتنقّل بينها المستخدم لاستفادة من الإمكانيات التي يقدمها التطبيق. بالنسبة لتطبيقات أندرويد فإنّ زر الرجوع إلى الخلف يُعتبر أساسيًا في عمليّة التنقّل هذه. سنتعرّف في هذا الدرس من سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms على كيفيّة التنقّل بين صفحات التطبيق. سنتحدّث أولًا عن مفهوم التنقّل بين الصفحات في التطبيق الواحد، ثمّ سنتحدّث عن أنواع صفحات المحتوى المستخدمة في التنقّل وذلك عن طريق مثال عملي بسيط. مفهوم التنقّل بين صفحات التطبيق يشبه التنقّل بين صفحات التطبيق مبدأ عمل المكدّس Stack إلى حدّ كبير. والمكدّس كما هو معلوم هو بنية معطيات تدعم مفهوم LIFO (الذي يدخل أخيرًا يخرج أولًا). فعند الانتقال من الصفحة A إلى الصفحة B، تُدفع pushed الصفحة B إلى أعلى المكدّس مما يؤدّي إلى ظهورها أمام المستخدم. وكذلك الأمر عند الانتقال من الصفحة B إلى الصفحة C يتم دفع الصفحة C إلى المكدّس ليتم إظهارها إلى المستخدم. أمّا عندما نريد العودة إلى الصفحة A الأصلية فيجب عندها أن تُخرج popped الصفحة C من المكدّس فتصبح الصفحة B أعلى المكدّس (أي تظهر للمستخدم) ثم تُخرج الصفحة B من المكدّس فتصبح الصفحة A أعلى المكدّس (أي تظهر للمستخدم). انظر الشكل التالي لتوضيح هذه الفكرة: صفحات Modal و Modeless يحتوي على كل تطبيق على صفحة رئيسيّة main page (ستكون من الصنف NavigationPage) تُعتبر العقدة الرئيسيّة التي يمكن الوصول من خلالها إلى جميع الصفحات الأخرى مهما كان عددها ومستواها. كما تميّز Xamarin بين نوعين من صفحات المحتوى التي تُستَخدم ضمن بنية التنقّل هذه وهي: الصفحات الجامدة Modal Pages والصفحات غير الجامدة Modeless Pages. الفرق بين هذين النوعين بالنسبة لتطبيقات أندرويد بسيط. وهو أنّه في الصفحات من النوع Modal لن يتم عرض عنوان الصفحة في الأعلى كما سنرى في المثال بعد قليل. أمّا في الصفحة من النوع Modeless فسيتم عنوان الصفحة في الأعلى في حال تمّ تحديده باستخدام الخاصيّة Title لصفحة المحتوى. لمعاينة الفرق بين هذه الأنواع لننشئ تطبيق عملي بسيط يوضّح هذا الأمر. ابدأ بإنشاء مشروع جديد من النوع Blank App (Xamarin.Forms Portable) وسمّه ModelessAndModal، ثم أبق فقط على المشروعين ModelessAndModal (Portable) و ModelessAndModal.Droid كما وسبق أن فعلنا في هذا الدرس. بعد ذلك سنضيف ثلاث صفحات محتوى عادية (Forms ContentPage) وهي: MainPage و ModalPage و ModelessPage. عدّل محتويات الملف MainPage ليكون مماثلًا لما يلي: 1 using Xamarin.Forms; 2 3 namespace ModelessAndModal 4 { 5 public class MainPage : ContentPage 6 { 7 public MainPage() 8 { 9 Title = "Main Page"; 10 11 Button gotoModelessButton = new Button 12 { 13 Text = "Go to Modeless Page", 14 HorizontalOptions = LayoutOptions.Center, 15 VerticalOptions = LayoutOptions.CenterAndExpand 16 }; 17 18 gotoModelessButton.Clicked += async (sender, args) => 19 { 20 await Navigation.PushAsync(new ModelessPage()); 21 }; 22 23 Button gotoModalButton = new Button 24 { 25 Text = "Go to Modal Page", 26 HorizontalOptions = LayoutOptions.Center, 27 VerticalOptions = LayoutOptions.CenterAndExpand 28 }; 29 30 gotoModalButton.Clicked += async (sender, args) => 31 { 32 await Navigation.PushModalAsync(new ModalPage()); 33 }; 34 35 Content = new StackLayout 36 { 37 Children = { gotoModelessButton, gotoModalButton } 38 }; 39 } 40 } 41 } ستعرض الصفحة الرئيسية MainPage زرّين فقط. الزر الأوًل هو gotoModelessButton ووظيفته إنشاء صفحة غير جامدة modeless والانتقال اليها. أمّا الزر الثاني فهو gotoModalButton ووظيفته إنشاء صفحة جامدة modal والانتقال إليها. بالنسبة للزر الأوّل gotoModelessButton انظر إلى الأسطر من 11 حتى 21: Button gotoModelessButton = new Button { Text = "Go to Modeless Page", HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.CenterAndExpand }; gotoModelessButton.Clicked += async (sender, args) => { await Navigation.PushAsync(new ModelessPage()); }; ننشئ في البداية كائنًا من النوع Button ونسنده إلى المتغيّر gotoModelessButton ثمّ نعيّن معالج لحدث النقر Clicked وهو عبارة عن تعبير lambda بسيط يمثّل تابع يحتاج إلى وسيطين sender و e وهو مسبوق بالكلمة المحجوزة async كما هو واضح من الشيفرة السابقة. سبب وجود الكلمة async هو أنّنا سنستخدم استدعاءً غير متزامنًا ضمن معالج الحدث هذا وهو: await Navigation.PushAsync(new ModelessPage()); يعمل التابع PushAsync المُستدعى من الخاصيّة Navigation للصفحة الحالية على دفع صفحة جديدة ضمن المكدّس الخاص بالتنقّل بين الصفحات، بمعنى آخر، سيعمل هذا التابع على إظهار صفحة جديدة من النمط modeless. في السطر السابق سيتم إنشاء صفحة جديدة من النوع ModelessPage ومن ثمّ تمريرها إلى التابع PushAsync. أنصحك بمراجعة هذا الدرس لكي تنعش ذاكرتك حول موضوع الاستدعاءات غير المتزامنة. نفس الأمر سيجري تمامًا بالنسبة للزر الخاص بالانتقال إلى الصفحة الجامدة مع فارق بسيط. وهو أنّ الاستدعاء هذه المرة سيكون من خلال التابع PushModalAsync (السطر 32) وذلك للانتقال إلى صفحة جامدة (ستكون من الصنف ModalPage). في كلّ من الحالتين السابقتين كان من الممكن أن نجعل معالجي حدثي النقر ضمن تابعين مستقلين وليس كما هو الحال من خلال تعبيري Lambda. الأمر الجدير بالملاحظة بالنسبة للصنف MainPage أيضًا هو تعيين الخاصيّة Title (السطر 9). في الحقيقة لم يكن لهذه الخاصيّة أي معنى في جميع البرامج التي أنشأناها في هذه السلسلة حتى الآن. إذ تعيين هذه الخاصيّة من عدمه لن يُحدث أيّ فرق! الجديد هنا هو في كيفيّة إنشاء الصفحة MainPage بحد ذاتها، والتي سننشئها كم جرت العادة ضمن الصنف App. انتقل إلى الملف App.cs واحرص على أن تكون بانيته مطابقة لما يلي: public App() { // The root page of your application MainPage = new NavigationPage(new MainPage()); } لاحظ معي الأمر الجديد هنا. نحن لا ننشئ صفحة محتوى ونسندها للخاصيّة MainPage مباشرةً كما كنّا نفعل من قبل. إنّما ننشئ صفحة محتوى (في مثالنا هي من الصنف MainPage) ثم نمرّر هذه الصفحة كوسيط إلى بانية الصنف NavigationPage. أي أنّنا في الواقع ننشئ صفحة محتوى تدعم التنقّل navigation. وهذا ما سيجعل عنوان الصفحة الرئيسيّة المُعيّن باستخدام الخاصيّة Title يظهر أعلى الصفحة كما سنرى بعد قليل. يمكننا الآن أن نجرّب هذا التطبيق. نفّذ التطبيق لتحصل على شكل شبيه بما يلي: أوقف تنفيذ البرنامج لنبدأ بالمرحلة الأخيرة وهي تجهيز صفحتي المحتوى ModalPage و ModelessPage. انتقل إلى الملف ModalPage.cs واحرص على أن تكون محتوياته مطابقة لما يلي: using Xamarin.Forms; namespace ModelessAndModal { public class ModalPage : ContentPage { public ModalPage() { Title = "Modal Page"; Button goBackButton = new Button { Text = "Back to Main", HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center }; goBackButton.Clicked += async (sender, args) => { await Navigation.PopModalAsync(); }; Content = goBackButton; } } } ثمّ انتقل إلى الملف ModelessPage.cs واحرص على أن تكون محتوياته كما يلي: using Xamarin.Forms; namespace ModelessAndModal { public class ModelessPage : ContentPage { public ModelessPage() { Title = "Modeless Page"; Button goBackButton = new Button { Text = "Back to Main", HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center }; goBackButton.Clicked += async (sender, args) => { await Navigation.PopAsync(); }; Content = goBackButton; } } } محتويات كلّ من الصفحتين السابقتين متطابقة. فكل منهما يحتوي على زر اسمه goBackButton هدفه العودة إلى الصفحة السابقة (التي سببت ظهور الصفحة الحالية). هناك فرق بسيط وحيد بين معالجي حدثي النقر للزرين في الصفحتين السابقتين. بالنسبة للصفحة من النمط الجامد modal تم استخدام الاستدعاء غير المتزامن Navigation.PopModalAsync للعودة إلى الصفحة السابقة. أمّا في حالة الصفحة ذات النمط غير الجامد modeless فقد تمّ استخدام الاستدعاء غير المتزامن Navigation.PopAsync للعودة إلى الصفحة السابقة. ثمة فرق آخر عند تنفيذ البرنامج، وهو أنّه في حالة الانتقال من الصفحة الرئيسية إلى الصفحة ModelessPage (الصفحة غير الجامدة) سيظهر عنوان الصفحة في الأعلى مع سهم صغير يسمح لنا بالعودة إلى الصفحة السابقة. أمّا عند الانتقال من الصفحة الرئيسية إلى الصفحة ModePage (الصفحة الجامدة) فلن يظهر عنوان الصفحة أبدًا (رغم تعيين الخاصيّة Title لها)، والوسيلة الوحيدة للرجوع إلى الصفحة السابقة هي بنقر زر الرجوع الموجود ضمن الصفحة أو بنقر زر العودة إلى الوراء الذي يزوّدنا به نظام التشغيل. أجرِ بعض التجارب على التطبيق ولاحظ الفرق بين الصفحتين. الخلاصة تناولنا في هذا الدرس آلية التنقّل بين الصفحات في تطبيقات أندرويد، وهو موضوع مهمّ بالطبع. حيث تعرّفنا إلى الفرق بين الصفحات من النمط modal والنمط modeless. كما تعلّمنا كيفية إنشاء الصفحة الرئيسيّة التي تُعتبر حجر البناء الأساسي في عمليّة الانتقال بين الصفحات، وذلك من خلال إنشاء الصفحة الرئيسيّة لتكون من النوع NavigationPage.
  21. سنتعرّف في هذا الدرس من ضمن سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms على تقنيّة متقدّمة بعض الشيء، وهي البرمجة غير المتزامنة Asynchronous Programming. وهي تقنيّة مهمّة تسمح للمبرمجين ببناء تطبيقات مرنة وذات استجابة عالية عند الاستخدام. سيتناول هذا الدرس الحاجة إلى البرمجة غير المتزامنة، ويقدّم تطبيق عملي بسيط يعمل على توضيح فكرة البرمجة غير المتزامنة من خلال تطبيق بسيط للغاية. الحاجة إلى البرمجة غير المتزامنة تسلك التطبيقات نفس السلوك في معالجة مُدخلات المستخدم التي قد تكون عبارة عن نقرة فأرة أو لمسة على الشاشة أو ضغط على مفتاح من لوحة المفاتيح. إذ يجب أن تُعالج هذه المدخلات بشكل متسلسل حسب ترتيب وقوعها. ولا يتم الانتقال من مُدخل إلى مُدخل آخر إلّا بعد الانتهاء من معالجة التعليمات البرمجيّة التي سبّبها المُدخل الحالي. فإذا فرضنا مثلًا وجود زرّين على الشاشة، فإذا نقرت (لمست) الزرّين بشكل متتال وبسرعة، فإنّ التعليمات الموجودة في معالج حدث النقر للزر الذي لُمسَ أولًا سيتم تنفيذها بالكامل، وبعد ذلك ينتقل البرنامج لتنفيذ مجموعة التعليمات البرمجيّة الموجودة في معالج حدث النقر للزر الثاني. بمعنى آخر، لن يتم تنفيذ التعليمات البرمجيّة للزرّين معًا، حتى وإن بدا للمستخدم أنّه قد نقرهما (لمسهما) معًا. وهذا أمر طبيعي تمامًا ويجري في جميع التطبيقات التي تعمل على أنظمة التشغيل المختلفة. السبب في هذا الأمر، هو أنّه وبشكل افتراضي يعمل التطبيق ضمن ما يُسمّى بمسار تنفيذ Thread رئيسي. يضمن مسار التنفيذ هذا أن يتم التنفيذ بالصورة التي أوضحناها قبل قليل. وفي الحقيقة يُسمّى مسار التنفيذ الرئيسي أحيانًا بمسار التنفيذ الخاص بواجهة المستخدم UI Thread وذلك لأنّ جميع العناصر المرئيّة يتم التعامل معها حصرًا من خلاله. تكمن المشكلة في أنّ بعض التطبيقات قد تحتاج إلى زمن طويل نسبيًا في تنفيذ التعليمات البرمجيّة الموجودة -ولنقل- في أحد معالجات الأحداث. فقد ينقر (يلمس) المستخدم زرًا يؤدّي مثلًا إلى جلب بعض البيانات من الإنترنت، وهي عمليّة قد تتطلّب في بعض الأحيان زمنًا طويلًا نسبيًّا وذلك لأسباب متنوّعة لسنا بمعرض الحديث عنها حاليًّا. سيعني هذا بكلّ تأكيد أنّ واجهة التطبيق ستبقى جامدة ولا تستجيب حتى تنجح عملية جلب البيانات أو تفشل لسبب ما. السيناريو السابق غير مرغوب بكل تأكيد، فلا بدّ من وجود طريقة ما تسمح بجلب البيانات دون التأثير على واجهة التطبيق الأساسيّة، أو بمعنى أدق، دون التأثير على مسار التنفيذ الرئيسي UI Thread. تُوفّر العديد من لغات البرمجة تقنيّة مهمّة لحل هذه المشكلة تتمثّل في استخدام مسارات تنفيذ أخرى (نسميها مسارات التنفيذ العاملة Worker Threads) يتم من خلالها تنفيذ المهام المتنوّعة التي يتطلّبها التطبيق والتي قد تستغرق زمنًا طويلًا نسبيًّا وذلك دون التأثير على مسار التنفيذ الرئيسي UI Thread. تُسمّى هذه التقنيّة بالبرمجة ذات مسارات التنفيذ المتعدّدة Multi-Threading Programming وهي من التقنيّات البرمجيّة المتقدّمة، وليس من السهل العمل معها. توفّر معظم لغات البرمجة بما فيها سي شارب حلول مبسّطة تُعفي المستخدم من مغبّة التورّط -إن صحّ التعبير- في موضوع متقدّم كهذا. الحل الذي تقدّمه سي شارب هو في البرمجة غير المتزامنة Asynchronous Programming حيث تعمل هذه التقنيّة على تنفيذ المهام البرمجيّة التي تتطلّب وقتًا طويلًا نسبيًّا ضمن ما يشبه مسارات تنفيذ منفصلة عن مسار التنفيذ الرئيسي، بحيث يمكن القول أنّ التعليمات البرمجيّة الموجودة ضمن معالجات أحداث مختلفة يصبح من الممكن تنفيذها بشكل متوازٍ بدلًا من الشكل المتسلسل الذي تحدثنا عنه. انظر إلى الشكل التالي الذي يوضّح الفرق العام بين التطبيقات التي تستخدم مسار التنفيذ الرئيسي فقط، وبين التطبيقات التي تستخدم مسارات تنفيذ متعدّدة. تطبيق العدّاد المحسّن مع استدعاء غير متزامن تذكر معي تطبيق العدّاد المحسّن الذي تناولناه في هذا الدرس. سنجري تعديلًا عليه بحيث سنعمل على إضافة زر جديد لإجراء استدعاء غير متزامن يعمل على محاكاة عمليّة برمجيّة تستغرق 5 ثانية، بالإضافة إلى لصيقة تقع أسفل الزر السابق لعرض رسالة بعد الانتهاء من عمليّة الاستدعاء غير المتزامن. أثناء تنفيذ هذه العمليّة البرمجيّة سنضغط على زرّي الزيادة والإنقاص، وسيتابع التطبيق العمل بشكل طبيعي دون حدوث أيّ جمود على واجهة المستخدم. بعد انقضاء العمليّة الناتجة عن الاستدعاء غير المتزامن بعد 5 ثانية، سيعرض التطبيق رسالة "Hello From Async." ضمن لصيقة تقع أسفل الزر للإشارة إلى انتهاء هذه العمليّة. انظر الشكل التالي لمعاينة الشكل الجديد لذلك التطبيق: أنشئ مشروعًا جديدًا من النوع Blank App (Xamarin.Forms Portable) وسمّه AsyncCounterApp، ثم أبق فقط على المشروعين AsyncCounterApp (Portable) و AsyncCounterApp.Droid كما وسبق أن فعلنا في هذا الدرس. بعد ذلك أضف صفحة محتوى وسمّها AsyncEnhancedCounterPage. احرص على أن تكون محتويات هذه الصفحة على الشكل التالي: 1 using System; 2 using System.Threading.Tasks; 3 using Xamarin.Forms; 4 5 namespace AsyncCounterApp 6 { 7 public class AsyncEnhancedCounterPage : ContentPage 8 { 9 Label lblDisplayAsync; 10 11 public AsyncEnhancedCounterPage() 12 { 13 int counter = 0; 14 15 Label lblDisplay = new Label 16 { 17 Text = "0", 18 TextColor = Color.Accent, 19 HorizontalOptions = LayoutOptions.CenterAndExpand, 20 FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) 21 }; 22 23 Button btnIncrement = new Button 24 { 25 Text = "+", 26 HorizontalOptions = LayoutOptions.CenterAndExpand, 27 FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) 28 }; 29 btnIncrement.Clicked += (s, e) => 30 { 31 counter++; 32 lblDisplay.Text = counter.ToString(); 33 }; 34 35 Button btnDecrement = new Button 36 { 37 Text = "-", 38 HorizontalOptions = LayoutOptions.CenterAndExpand, 39 FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) 40 }; 41 btnDecrement.Clicked += (s, e) => 42 { 43 if (counter == 0) 44 { 45 DisplayAlert("تحذير", "لا يمكن لقيمة العدّاد أن تكون أصغر من الصفر", "موافق"); 46 } 47 else 48 { 49 counter--; 50 lblDisplay.Text = counter.ToString(); 51 } 52 }; 53 54 Button btnAsyncCall = new Button 55 { 56 Text = "Async Call", 57 HorizontalOptions = LayoutOptions.CenterAndExpand, 58 FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) 59 }; 60 btnAsyncCall.Clicked += BtnAsyncCall_Clicked; ; 61 62 lblDisplayAsync = new Label 63 { 64 TextColor = Color.Green, 65 HorizontalOptions = LayoutOptions.CenterAndExpand, 66 FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) 67 }; 68 69 Content = new StackLayout 70 { 71 Children = { 72 new StackLayout 73 { 74 Orientation = StackOrientation.Horizontal, 75 Padding = new Thickness(0,64,0,64), 76 Children = 77 { 78 btnIncrement, 79 btnDecrement 80 } 81 }, 82 lblDisplay, 83 btnAsyncCall, 84 lblDisplayAsync 85 } 86 }; 87 } 88 89 private async void BtnAsyncCall_Clicked(object sender, EventArgs e) 90 { 91 //simulate long process execution for 5 seconds 92 string msg = await Task<string>.Run(() => 93 { 94 DateTime d = DateTime.Now; 95 96 while (DateTime.Now.Second - d.Second < 5) ; 97 98 return "Hello from Async."; 99 }); 100 101 lblDisplayAsync.Text = msg; 102 } 103 } 104 } لقد تناولنا الشيفرة السابقة من قبل. لذلك سنتحدّث عن عمليّة الاستدعاء غير المتزامن فحسب. لقد أسندنا لحدث نقر الزر btnAsyncCall معالج حدث BtnAsyncCall_Clicked وهو موجود في الأسطر من 89 حتى 102. الجديد في معالج الحدث هذا هو وجود الكلمة المحجوزة async (السطر 89) قبل نوع القيمة المعادة مباشرةً. تُشير هذه الكلمة المحجوزة إلى أنّ عملية الاستدعاء غير المتزامن ستجري ضمن التابع BtnAsyncCall_Clicked. انظر الآن إلى الأسطر من 92 إلى 99: string msg = await Task<string>.Run(() => { DateTime d = DateTime.Now; while (DateTime.Now.Second - d.Second < 5) ; return "Hello from Async."; }); لاحظ التابع الساكن Run من الصنف العمومي Task<string>. يعمل هذا التابع على استدعاء أيّ تابع مُمرّر إليه ضمن مسار تنفيذ منفصل عن مسار التنفيذ الأساسي، وبالتالي لا يُشغل مسار التنفيذ الأساسي المرتبط بواجهة المستخدم. يجب أن يُسبق الاستدعاء غير المتزامن بالكلمة المحجوزة await. لقد مرّرنا إلى التابع Run تعبير Lambda يحتوي التعليمات البرمجيّة التي نريد تنفيذها على مسار تنفيذ مستقل (للمزيد حول تعابير Lambda انظر هنا). من الواضح أنّنا قد كتبنا شيفرة برمجيّة لا تقوم بعمل مفيد بكل تأكيد، إنما الغاية الوحيدة منها هي توضيح فكرة الاستدعاء غير المتزامن، حيث أجريت تأخيرًا زمنيًّا باستخدام حلقة while يستغرق 5 ثواني. سنكتفي بهذه المقدّمة حول البرمجة غير المتزامنة، مع التأكيد على أنّنا سنتوسّع في هذا الموضوع حينما نتناول تطبيقًا عمليًّا مفيدًا لاحقًا في هذه السلسلة. الخلاصة تحدثنا في هذا الدرس عن مفهوم البرمجة غير المتزامنة Asynchronous Programming والحاجة إليها في التطبيقات التي نصمّمها لضمان أنّ العمليات البرمجيّة التي قد تستغرق وقتًا طويلًا نسبيًّا لن تؤدّي إلى جمود في واجهة المستخدم. ثمّ أجرينا تعديلًا بسيطًا على تطبيق بنيناه في درس سابق بحيث نجري استدعاءً غير متزامنًا يستغرق وقتًا لا بأس به حتى ينتهي، ورغم ذلك استطاع المستخدم متابعة العمل على التطبيق دون أيّ تأثير على واجهة التطبيق. لن نكتفي بكلّ تأكيد بما وصلنا إليه هنا، سنتوسّع بالحديث عن هذا الموضوع المهم لاحقًا حينما نبدأ بتنفيذ تطبيقات عمليّة باستخدام Xamarin.
  22. سنتحدّث في هذا المقال من سلسلة المقالات حول التعامل مع ويندوز 10 عن المتصفّح الجديد Microsoft Edge، وهو موجود بشكل افتراضي ضمن ويندوز 10. عملت مايكروسوفت على بناء هذا المتصفّح من الصفر وذلك كبديل للمتصفّح الشهير (سيّء الصيت) Internet Explorer. وضعت مايكروسوفت إمكانيات كبيرة للخروج بمتصفّح Edge بهذه الصورة، وذلك للدخول في سباق المتصفّحات المحموم للفوز ولو بحصّة معقولة من هذا السوق. دمجت مايكروسوفت بعض وظائف المساعد الشخصي Cortana مع Edge ولكنّنا لن نتكلّم في هذه السلسلة مع الأسف عن Cortana وذلك لأنّه غير مدعوم حتى هذه اللحظة مع النسخة العربية لويندوز 10. سنتناول في هذا المقال بعض مزايا هذا المتصفّح الجديد والتي وجدتها مثيرة للاهتمام. وضع ملاحظات مباشرةً على صفحة ويب وهي ميزة مهمة وجميلة في Edge حيث يمكن وضع ملاحظات مباشرةً ضمن أيّ صفحة ويب نرغب بها وذلك على أيّ مكان في الصفحة. افتح متصفّح Edge لديك وانتقل إلى الموقع http://academy.hsoub.com لتظهر الصفحة الرئيسية كما في الشكل التالي. لاحظ الأيقونة المحاطة بإطار أحمر والموجودة في الأعلى. انقر على هذه الأيقونة ليظهر شريط أدوات الملاحظات في الأعلى. كما في الشكل التالي. بالنسبةإلي، اخترت أداة القلم وقمت برسم شكل مغلق حول جزء أعجبني من الصفحة، كما اخترت أداة التعليقات ووضعت تعليقًا أيضًا على هذه الصفحة كما في الشكل التالي. بعد أن نفرغ من تدوين الملاحظات يمكن نقر أيقونة الحفظ الموجودة في الجهة اليسرى، أو نقر أيقونة المشاركة الموجودة بجوارها. المثير في الأمر أنّه في حال نقرت أيقونة الحفظ سيخيرك متصفّح Edge بطريقة حفظ هذه الملاحظات. حيث سيظهر ضمن إحدى هذه الخيارات استخدام تطبيق OneNote لتدوين الملاحظات والذي تحدثنا عنه في المقال السابق وذلك لمزامنة أيّ ملاحظات ستسجّلها على هذه الصفحة، وبالتالي يمكنك الوصول إلى هذه الملاحظات في أي وقت ومن خلال أي جهاز ترغبه. اختر OneNote لحفظ الملاحظات ثم انقر زر "حفظ" سيخبرك Edge أنّ ملاحظاتك قد تمّ حفظها ضمن تطبيق OneNote وبالتالي أصبح من الممكن الوصول إليها من أيّ مكان. يمكنك التأكّد من ذلك بفتح تطبيق OneNote ومشاهدة الملاحظات التي تمّ تدوينها على الصفحة الرئيسية للموقع. إنشاء قائمة قراءة بسيطة تُعتبر ميزة "قائمة القراءة" الموجودة في متصفّح Edge من المزايا المفيدة التي يحتاجها الكثير من المستخدمين. حيث يمكننا إنشاء قائمة خاصّة للصفحات التي نودّ مراجعتها بترتيب منطقي متسلسل. يمكن وضع أي صفحة ويب ضمن قائمة القراءة بالنقر على أيقونة المفضّلة (رمز النجمة) الموجودة بجوار شريط العنون، ثم اختر أن تُوضع هذه الصفحة ضمن قائمة القراءة وليس ضمن المفضّلة. يمكن بعد ذلك الوصول لقائمة القراءة بالنقر على أيقونة "الموزّع" وهي على شكل ثلاثة خطوط أفقيّة متوازية، ثم النقر على أيقونة قائمة القراءة كما يظهر من الشكل التالي: يمكنك ملاحظة أنّني قد أضفت عدّة صفحات لمراجعتها ضمن الترتيب الزمني الذي أضفتها فيه. توجد بالطبع العديد من الإضافات الخارجيّة التي توفّر لنا هذه الميزة وربما بطريقة احترافية أكثر. ولكن في حال أردنا فقط وسيلة بسيطة لتنظيم ما نودّ قراءته لاحقًا فلا حاجة للجوء لمثل هذه الإضافات والاكتفاء بما يوفّره Edge. مشاركة المحتوى أثناء التصفّح يمتلك متصفّح Edge أسلوب سهل لمشاركة المحتوى مع الآخرين فيمكنك النقر على أيقونة "المشاركة" (ثلاث دوائر صغيرة تقع على محيط دائرة أكبر). عند النقر على هذه الأيقونة سيعرض لك متصفّح Edge قائمة بالتطبيقات التي تسمح بالمشاركة والتي قمت بتفعيلها عن طريقه، أو تلك التي مفعّلة بشكل تلقائي من قِبَل Edge. يمكنك زيادة عدد هذه التطبيقات من خلال تنصيب المزيد منها عن طريق متجر ويندوز Windows Store. قد يختلف لون أرضية القائمة التي تظهر في الشكل السابق عن تلك التي تظهر عندك وذلك بسبب اختلاف إعدادات الألوان الافتراضيّة المعتمدة لديك. تثبيت صفحات الويب ضمن قائمة البداية من الممكن في حال وجدت أنّ صفحة ويب ما أنّها مهمة أو أنّك تزورها باستمرار، أن تثبّتها ضمن قائمة البداية. فقط عليك زيارة صفحة ويب المطلوبة ثم تنقر زر "المزيد" من الأعلى (ثلاث نقاط متجاورة أفقيًّا) انقر خيار "تثبيت هذه الصفحة بشاشة البدء" بعد نقرك على هذا الخيار، يمكنك الانتقال فورًا إلى شاشة البدء لتلاحظ ظهور لوح tile جديد يسمح لك بالوصول السريع لصفحة الويب هذه. انظر الشكل التالي: المزايا الأمنية تم بناء متصفّح Edge مع الأخذ بعين الاعتبار الثغرات الكبيرة التي كانت تعتري المتصفّح القديم Internet Explorer (الذي ما يزال موجودًا بشكل افتراضي في نظام التشغيل). أصبح Edge يمنع استخدام عناصر ActiveX أو النصوص البرمجيّة المكتوبة بلغة VBScript والتي كان من الممكن استخدامها للقيام بالعديد من الخروقات الأمنيّة التي تصيب جهاز المستخدم. أصبح متصفّح Edge يعتمد فقط على HTML5 بالإضافة إلى النصوص البرمجيّة المكتوبة بلغة JavaScript. وبالتالي فإنّ أي موقع لا يزال يستخدم تقنيات قديمة مثل ActiveX لن يتمّ عرضه بصورة صحيحة في Edge. توجد في الحقيقة العديد من المزايا الأمنية الأخرى التي يتمتّع بها Edge مثل التشغيل في وضع العزل Sandboxing. وهي ميزة مهمّة تسمح بتشغيل الجزء البرمجي الذي يعرض الصفحة ويعالج محتواها ضمن حاوية برمجيّة عازلة، مما يمنع أي شيفرة برمجيّة ضارة من الاستفادة من موارد الحاسوب الذي تعمل عليه. يتمتّع Edge أيضًا بنوع من الذكاء الاصطناعي في توقّع الأخطاء قبل حدوثها. حيث اعتمدت مايكروسوفت على المنطق الضبابي Fuzzy Logic في توقّع الأخطاء والمشاكل المحتملة قبل حدوثها وذلك بالاستناد إلى تجارب سابقة تتخطى 400 مليون تجربة في تحليل ومعالجة صفحات HTML، مما يجعل Edge أكثر قدرة على تفادي المشاكل قبل وقوعها قدر الإمكان. الخلاصة تعرّفنا في هذا المقال على بعض المزايا الجديدة والمفيدة التي يتمتّع بها متصفّح الويب Edge. ذلك المتصفّح المجّاني والجديد من مايكروسوفت. لقد رأينا كيف نستطيع وضع ملاحظات مباشرة على صفحة الويب، ومن ثمّ حفظها ومشاركتها بأساليب مختلفة. كما تعلّمنا كيفيّة بناء قائمة للقراءة، وكيف نثبّت صفحة ويب مهمّة كلوح ضمن قائمة البداية. وتعرّفنا في النهاية على المزايا الأمنيّة الجديدة التي يدعمها Edge.
  23. نتابع رحلتنا في سلسلة المقالات حول التعامل مع ويندوز 10 مع هذا الدرس الذي يتحدّث عن بدء العمل مع ويندوز 10 من خلال التعرّف على بعض المزايا الأساسيّة البسيطة التي تسهّل المهام اليوميّة. أصبح ويندوز 10 أكثر قابليّة وسهولة للتخصيص، سنتحدّث عن كيفيّة تخصيص الألواح Tiles في شاشة البدء، بالإضافة إلى كيفيّة تثبيت أيقونات التطبيقات على شريط المهام. كما سنتعرّف على منطقة الإشعارات، والفائدة التي يمكن أن نجنيها منها. الألواح Tiles اللوح Tile هو من المزايا الجديدة التي بدأت بالظهور منذ ويندوز 8 وقد شهدت تحسينًا في ويندوز 10. تتوضّع الألواح ضمن شاشة البدء على شكل مربّعات صغيرة قد تحتوي على محتوى متحرّك، وتعرض معلومات مفيدة للمستخدم. تتنوّع هذه المعلومات من حالة الطقس، آخر الأخبار المتوفرة حاليًّا، أسعار العملات، إلى آخر رسائل البريد الإلكتروني، وغيرها من المعلومات المختصرة والمفيدة بنفس الوقت. يمكنك إضافة لوح جديد إلى شاشة البدء عن طريق خطوتين بسيطتين. انتقل أولًا إلى شاشة البدء عن طريق نقر زر ابدأ، ثم اختر التطبيق الذي ترغب بتثبيته كلوح ضمن شاشة البدء. لاحظ أنّ التطبيقات مصنّفة ضمن مجموعات مرتّبة أبجديًّا. يمكنك أن تنتقي التطبيق الذي تريده بسهولة من هذه القائمة، أو حتى يمكنك الوصول إليه مباشرةً عن طريق كتابة اسمه على لوحة المفاتيح، وسيقوم ويندوز 10 بالبحث عن التطبيق أثناء الكتابة حيث يعرض عليك نتائج البحث على شكل قائمة تختار منها التطبيق المناسب. بصرف النظر عن الأسلوب الذي استخدمته للوصول إلى تطبيقك، انقر على أيقونة التطبيق المطلوب بزر الفأرة الأيمن لكي تظهر قائمة منبثقة، اختر منها البند "تثبيت بشاشة البدء". كما يظهر من الشكل التالي فقد اخترت تطبيق الرسام الذي يأتي ضمن التطبيقات الملحقة بويندوز. ستلاحظ ظهور أيقونة تطبيق الرسام ضمن شاشة البدء مباشرةً. إذا أمعنت النظر في شاشة البدء بعد إضافة تطبيق الرسام كلوح إليها، ستجد أنّ اللوح الذي يمثّل هذا التطبيق سيظهر كما لو أنّه متطرّف قليلًا عن باقي الألواح. يعود السبب في ذلك إلى أنّ ويندوز يعمل على إضافة هذا اللوح ضمن مجموعة منفصلة. إذ أنّ الألواح تُصنّف في الواقع ضمن مجموعات لكي يتمكّن المستخدم من تنظيم تطبيقاته ضمن مجموعات منطقيّة تجعل عمليّة الوصول إليها سهلة نسبيًّا. حرّك مؤشّر الفأرة أعلى لوح تطبيق الرسام مباشرةً، ستلاحظ ظهور النص "تسمية المجموعة" وهو نص قابل للتعديل يمثّل عنوان هذه المجموعة من الألواح. إذا نقرت على هذا النص يمكنك إدخال الاسم الذي يناسبك، كما يمكنك إضافة أي عدد من الألواح لهذه المجموعة بنفس الأسلوب السابق. يمكنك أيضًا نقل لوح من مجموعة إلى أخرى، وذلك بالضغط بزر الفأرة الأيسر عليه وسحبه ومن ثمّ إفلاته ضمن المجموعة المطلوبة. كما يمكنك أيضًا إزالة لوح من شاشة البدء وذلك بأن تنقر عليه بزر الفأرة الأيمن، ثمّ تختار "إزالة التثبيت من شاشة البدء". شريط المهام Task Bar هو الشريط الذي يمتد على كامل عرض الشاشة من الأسفل، ويبدأ بزر ابدأ وينتهي بمنطقة الإشعارات من الجهة اليسرى. أي نافذة أو برنامج يتم فتحها في ويندوز 10 ستُوضع لها أيقونة في هذا الشريط، أمّا عند إغلاق هذه النافذة أو التطبيق تختفي هذه الأيقونة. قد نرغب أحيانًا بتثبيت أيقونات بعض التطبيقات بشكل دائم بهدف الوصول السريع لها. يمكن ذلك من خلال اختيار التطبيق المطلوب من شاشة البدء (كما فعلنا في الفقرة السابقة) والنقر بزر الفأرة الأيمن عليه. نختار البند "تثبيت إلى شريط المهام" ليعمل ويندوز إلى تثبيت اختصار مباشر لهذا التطبيق ضمن شريط المهام. منطقة الإشعارات يمكن الوصول إلى هذه المنطقة من خلال النقر على الأيقونة الصغيرة التي تظهر بجوار الساعة. توجد العديد من المميزات المفيدة في هذه المنطقة. في البداية يمكنك الاطلاع على رسائل البريد الإلكتروني الجديدة (على فرض أنّك قد ربطت حساب مايكروسوفت بنسخة ويندوز 10 التي لديك كما فعلنا في الدرس السابق). كما يمكنك الوصول إلى إعدادات الحاسوب لديك، وإلى مركز الصيانة الذي سنتحدّث عنه لاحقًا، ويمكنك أيضًا إجراء عمليات ضبط سريعة للحاسوب لديك كما يظهر من الشكل التالي: توجد العديد من الاختصارات السريعة كما يظهر من الشكل السابق والتي سنتحدّث عن كلّ منها بشكل مختصر: يفيد الزر "وضع الكومبيوتر اللوحي" في جعل حاسوبك يتصرّف كما لو أنّه جهاز لوحي. وهذه ميزّة مهمّة إذا كان حاسوبك هو لوحيّ فعلًا (كما في سلسلة Surface مثلًا). أمّا زر "تأمين التدوير" فهو مفيد أيضًا في حال كان حاسوبك لوحيًّا. اختصار "مفكرة" يؤدّي إلى تشغيل تطبيق "OneNote" وهو تطبيق ملحق بمجموعة Office، ولكنّه مضمّن في ويندوز 10 بشكل افتراضي، وهو يسمح للمستخدم بتدوين ملاحظات احترافية يمكنك مزامنتها عبر الانترنت (في حال كانت نسخة ويندوز لديك مرتبطة بحساب مايكروسوفت). يفيد زر "كل الإعدادات" في الوصول إلى لوحة إعدادات الحاسوب. يؤدّي تفعيل زر "الموقع" إلى السماح للتطبيقات بمعرفة الموقع الذي يعمل منه الحاسوب. يمكنك النقر على هذا الزر لتفعيل هذه الميزة أو إلغاء تفعيلها. يؤدّي الضغط على زر "ساعات الهدوء" إلى تفعيل هذه الميزة، والتي تتمثّل في منع الحاسوب من إصدار أي تنبيه أو إشعار بين منتصف الليل والساعة السادسة صباحًا. على فرض أنّ الحاسوب في وضع تشغيل خلال هذه الساعات. ويمكنك بالطبع الضغط على هذا الزر مرّة أخرى لإلغاء هذه الميزة. زر VPN ينقلك إلى الإعدادات الخاصة بالشبكات الظاهرية الخاصة Virtual Private Networks التي يستخدمها الحاسوب. زر "عرض"، وهو مفيد عندما نستخدم جهاز إسقاط ضوئي Projector، حيث يمكن التحكم بمجموعة من خيارات العرض المختلفة، كالتحكّم فيما إذا كان العرض على شاشة الحاسوب فقط، أو على شاشة جهاز الإسقاط الضوئي فقط، أو على سطح مكتب ممتد عبر الشاشة وجهاز الإسقاط، أو عرض مكرّر على الشاشة وجهاز الإسقاط. يسمح زر "اتصال" بالاتصال لاسلكيًّا بالأجهزة التي تتمتّع بميزة Miracast (بما فيها حاسوبك الشخصي). زر "الشبكة" يسمح بعرض حالة الشبكة الحالية، والانتقال إلى إعدادات الشبكات. الخلاصة هناك الكثير مما يمكننا التحدّث عنه حول ويندوز 10. هذا النظام الذي يُعتبر قفزة نوعيّة في أنظمة التشغيل التي تنتجها مايكروسوفت. لقد بدأنا في هذا الدرس بمعرفة كيفيّة التعامل مع المزايا الأساسيّة التي ستصادفها مرارًا أثناء استخدامك اليومي لويندوز. حيث تعرّفنا على ماهية الألواح Tiles وكيفيّة استخدامها، وكيفيّة تثبيت اختصارات للتطبيقات التي كثيرًا ما تحتاجها ضمن شريط المهام. كما تعرّفنا على منطقة الإشعارات التي تحتوي على الكثير من الميزات التي قد يحتاجها المستخدم في عمله في ويندوز 10.
  24. بعد أن انتهينا من تنصيب ويندوز 10 في الدرس السابق سنعمل في هذا الدرس من سلسلة المقالات حول التعامل مع ويندوز 10 على تنفيذ بعض الإجراءات الضروريّة قبل البدء باستخدام ويندوز 10. تشتمل هذه الإجراءات على القيام بتحديثين ضروريين، وهما التحديث الخاص ببرنامج الحماية المرفق مع ويندوز وهو Windows Defender بالإضافة إلى التحديث الخاص بنظام التشغيل نفسه. كما سنعمل على ربط نسخة ويندوز 10 بحساب حساب مايكروسوفت Microsoft Account للاستفادة القصوى من المزايا التي يوفّرها نظام التشغيل ويندوز 10. إجراء التحديثات اللازمة قد تستغرب في البداية أنّني لست مقتنعًا بنظام الحماية Windows Defender المضمّن بشكل مجانيّ مع ويندوز 10. أمّا سبب شرحي حول كيفيّة تحديثه لضمان أمن الحاسوب، فالجواب ببساطة لأنّه مجّانيّ وموجود سلفًا في ويندوز، وبالتالي يُعتبر كأحد مزايا نظام التشغيل. برأيي الشخصي هناك بدائل أخرى أفضل من Windows Defender وهي مجانيّة أيضًا مثل تطبيق Avira الذي أنصحك بالاطلاع عليه. أمّا في حال كنت مستعدًّا لدفع بعض الدولارات فيمكنك استخدام Norton Symantec أو Kaspersky. لإجراء التحديث الخاص بنظام الحماية Windows Defender انقر زر ابدأ لتظهر قائمة البداية. ثم انقر بعد ذلك زر الإعدادات الصغير الموجود في الجهة اليمنى من الأسفل، كما يظهر في الشكل التالي: ستظهر نافذة الإعدادات بشكلها الجديد. اختر من هذه النافذة بند "التحديث والأمان" كما في الشكل التالي: ربما ستحتاج إلى استخدام شريط التمرير ان لم يكن هذا البند ظاهرًا. بعد ظهور الصفحة الخاصة بالتحديث والأمان، اختر من القائمة التي تظهر في الجهة اليمنى العنصر Windows Defender لتظهر الصفحة الخاصة بـ Windows Defender كما في الشكل التالي: انقر الزر "فتح Windows Defender" كما يظهر من الشكل السابق، ليعمل ويندوز على فتح نافذة هذا التطبيق. سيعرض التطبيق رسالة ترحيبيّة توضّح مزايا Windows Defender. انقر الزر إغلاق للوصول إلى النافذة الرئيسيّة للتطبيق. انقر اللسان "تحديث" الذي ستجده في الأعلى للانتقال إلى القسم الخاص بتحديث التعريفات الخاصة بالفيروسات. بعد ذلك، انقر زر "تحديث التعريفات" لتبدأ هذه العمليّة التي قد تأخذ بعض الوقت حسب سرعة الاتصال التي لديك. بعد الانتهاء من تحديث تعريفات الفيروسات أغلق نافذة تطبيق Windows Defender. سيظل التطبيق يعمل في الخلفيّة ليؤمّن الحماية المطلوبة. حان الوقت الآن لتحديث نظام التشغيل، وهو أمر مهمّ جدًّا بالنسبة لويندوز 10. فهناك العديد من التحديثات التي تجري تباعًا، سواءً لإضافة مزايا جديدة، أو لتلافي ثغرات أمنيّة أو مشاكل تقنيّة. من نفس صفحة "التحديث والأمان" اختر من القائمة التي تظهر في الجهة اليمنى البند "Windows Update" لتظهر الصفحة الخاصة بتحديثات ويندوز. انقر زر "التحقّق من وجود تحديثات" كما في الشكل التالي: قد يستغرق الأمر بعضًا من الوقت بحسب سرعة الاتصال لديك، بالإضافة إلى الوقت اللازم لتطبيق هذه التحديثات على نظام التشغيل. قد تبدو العمليّة مملّة لأنّها قد ستستغرق وقتًا طويلًا للمرّة الأولى، وقد تتضمّن إعادة تشغيل الحاسوب. الربط مع حساب مايكروسوفت من الممكن ربط نسخة ويندوز 10 التي لدينا بحساب مايكروسوفت التابع لك. وحساب مايكروسوفت قد يكون عبارة عن حساب بريد إلكتروني عادي تمتلكه على بريد هوتميل Hotmail مثلًا. إذا لم تكن تمتلك مثل هذا الحساب، انتقل إلى صفحة هوتميل www.hotmail.com لتظهر لك صفحة خاصّة بتسجيل الدخول كما في الشكل التالي: انقر الرابط Create one الموجود أسفل الزر Next كما هو واضح من الشكل السابق. سينتقل بك المتصفّح إلى الصفحة الخاصة بإنشاء حساب مايكروسوفت جديد. أدخل البيانات الخاصّة بك، ثم تابع التسجيل حتى تحصل على حساب جديد. انقر الآن زر ابدأ، ثم انتقل إلى الإعدادات كما فعلنا من قبل. من الصفحة الرئيسية للإعدادات انقر "الحسابات": اختر من صفحة "الحسابات" البند "البريد الإلكتروني وحسابات التطبيق" من القائمة الموجودة في الجهة اليمنى لتظهر الصفحة الموافقة كما يلي: بعد أن تظهر هذه الصفحة، انقر الزر + الصغير الذي يظهر في وسط الصفحة بجوار عبارة إضافة حساب كما في الشكل السابق. سيؤدي ذلك إلى فتح نافذة صغيرة تخيّرك بين أنواع متعدّدة للحسابات التي يقبل ويندوز 10 أن يضمّها. سنختار من هذه النافذة البند الخاص بحسابات مايكروسوفت وهو Outlook.com كما في الشكل التالي: وهو يتضمّن طيفًا واسعًا من حسابات البريد الإلكتروني التابعة لمايكروسوفت. بعد أن تختار هذا البند سيطلب منك ويندوز 10 تزويده بمعلومات هذا الحساب. أدخل البريد الإلكتروني وكلمة المرور في المربّعين المناسبين ثم انقر زر "تسجيل الدخول". سيعرض ويندوز 10 لك نافذة توضّح الإجراءات التي سيقوم ويندوز 10 بتطبيقها عند ربط نسخة ويندوز التي لديك بحساب مايكروسوفت. كما سيطلب التحقّق من شخصيتك بأن تكتب كلمة المرور الحالية لنسخة ويندوز. إذا لم تُعيّن أي كلمة مرور سابقة لنسخة ويندوز، يمكنك ترك هذا الحقل فارغًا. انقر زر التالي ليبدأ ويندوز 10 عملية الربط التي قد تأخذ القليل من الوقت. بعد أن تنتهي عمليّة الربط يجب أن تحصل على رسالة تخبرك بأنّ العمليّة تمّت بنجاح، ثمّ سيتم إضافة الحساب الخاص بك إلى قائمة الحسابات المعتمدة. يمكنك الآن إغلاق نافذة الإعدادات. الفائدة المباشرة لموضوع الربط هذا، هو أنّ بريدك الإلكتروني سيتم ربطه بشكل تلقائي مع برنامج البريد الافتراضي في ويندوز 10، وإذا كنت قد ربطت حسابًا قديمًا لك مع نسخة ويندوز هذه، ستلاحظ بدء مزامنة رسائل البريد الإلكتروني، حيث ستبدأ الإشعارات تظهر لك في منطقة الإشعارات الموجودة في الزاوية اليسرى السفلى (بجوار الساعة). انقر على أيقونة الإشعارات كما في الشكل التالي لترى رسائل البريد الجديدة: إذا لم تتم عملية المزامنة مباشرةً، فيمكنك الذهاب فورًا إلى تطبيق البريد الإلكتروني الافتراضي عبر النقر على زر ابدأ، وبعد ظهور قائمة البداية، اكتب مباشرةً باستخدام لوحة المفاتيح كلمة "البريد" ليعمل ويندوز على البحث عن تطبيق البريد الإلكتروني ومن ثمّ إظهاره لك في نتائج البحث ضمن نفس القائمة. انقر أيقونة التطبيق، لتبدأ عمليّة مزامنة البريد الإلكتروني فورًا. توجد في الواقع الكثير من الفوائد لربط نسخة الويندوز بحساب مايكروسوفت. عاينّا أحد هذه الفوائد قبل قليل، توجد العديد من الفوائد الأخرى كربط خدمة One Drive الخاصة بمايكروسوفت والتي تسمح لك بالتخزين السحابي، كما يمكنك الاستفادة من إمكانية الوصول إلى متجر ويندوز وتنزيل أو شراء التطبيقات التي تحتاجها. سنعاين العديد من هذه المزايا لاحقًا في هذه السلسلة. الخلاصة تعلّمنا من خلال هذا الدرس كيفيّة إجراء التحديثات اللازمة لويندوز، ولبرنامج الحماية الخاص به وهو Windows Defender. كما تعلّمنا كيفيّة ربط نسخة ويندوز 10 التي لديك، بحساب مايكروسوفت تمتلكه مسبقًا، أو حساب مايكروسوفت تنشئه بشكل جديد تمامًا. سنتعرّف في الدروس التالية في هذه السلسلة على كيفيّة الاستفادة من مزايا الربط مع حساب مايكروسوفت، بالإضافة إلى التعرّف إلى العديد من المزايا المفيدة التي يوفّرها ويندوز 10 للمستخدمين.
×
×
  • أضف...