الاستجابة لأحداث النقر في Xamarin


حسام برهان

تعاملنا في الدروس السابقة في هذه السلسلة مع عناصر مرئيّة وظيفتها الأساسيّة عرض البيانات بشكل مناسب إلى المستخدم. في الحقيقة يوجد نوع آخر من العناصر المرئيّة، يتضمّن تلك العناصر التي يمكن أن يتفاعل المستخدم معها لتنفيذ أمر أو مهمّة معيّنة. سنتناول في هذا الدرس الممتع عنصر الزر Button وهو عنصر مرئي يسمح للمستخدم عند نقره (أو بالأحرى لمسه) بأن ينفّذ أمرًا معيّنًا.

xamarin-009.png

تطبيق العدّاد

وهو تطبيق بسيط، الغرض منه فهم كيفيّة التعامل مع الأزرار في Xamarin.Forms. تتكوّن واجهة هذا التطبيق من زرّين بالإضافة إلى لصيقة. فكرة التطبيق بسيطة، فعندما ينقر المستخدم أحد الزرّين يزداد العدد المعروض على اللصيقة بمقدار واحد، وعندما ينقر على الزر الآخر ينقص هذا العدد بمقدار واحد أيضًا.
أنشئ تطبيقًا جديدًا من النوع Blank App (Xamarin.Forms Portable) كما هو معتاد وسمّه CounterApp، وأبق فقط على المشروعين CounterApp.Droid و CounterApp (Portable) ضمنه. أضف صفحة محتوى ContentPage جديدة سمّها CounterPage. احرص على أن يكون محتوى الملف CounterPage.cs على الشكل التالي:

 
1	using System;
2	using Xamarin.Forms;
3
4	namespace CounterApp
5	{
6	    public class CounterPage : ContentPage
7	    {
8	        private int counter = 0;
9	        private Label lblDisplay;
10
11	        public CounterPage()
12	        {
13	            Button btnIncrement = new Button
14	            {
15	                Text = "+",
16	                HorizontalOptions = LayoutOptions.CenterAndExpand,
17	                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
18	            };
19	            btnIncrement.Clicked += btnIncrement_Clicked;
20
21	            Button btnDecrement = new Button
22	            {
23	                Text = "-",
24	                HorizontalOptions = LayoutOptions.CenterAndExpand,
25	                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
26	            };
27	            btnDecrement.Clicked += BtnDecrement_Clicked;
28
29	            lblDisplay = new Label
30	            {
31	                Text = "0",
32	                TextColor = Color.Accent,
33	                HorizontalOptions = LayoutOptions.CenterAndExpand,
34	                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
35	            };
36
37	            Content = new StackLayout
38	            {
39	                Children = {
40	                    new StackLayout
41	                    {
42	                        Orientation = StackOrientation.Horizontal,
43	                        Padding = new Thickness(0,64,0,64),
44	                        Children =
45	                        {
46	                            btnIncrement,
47	                            btnDecrement
48	                        }
49	                    },
50	                    lblDisplay
51	                }
52	            };
53	        }
54
55	        private void BtnDecrement_Clicked(object sender, EventArgs e)
56	        {
57	            counter--;
58	            lblDisplay.Text = counter.ToString();
59	        }
60
61	        private void btnIncrement_Clicked(object sender, EventArgs e)
62	        {
63	            counter++;
64	            lblDisplay.Text = counter.ToString();   
65	        }
66	    }
67	}

ملاحظة
تذكّر أنّنا نضيف صفحة محتوى جديدة بالنقر بزر الفأرة الأيمن على المشروع CounterApp (Portable) ثم نختار Add وبعدها New Item، ومن النافذة التي تظهر، تختار Cross-Platform من القسم الأيسر، ومن القسم الأيمن نختار Forms ContentPage

لقد صادفنا العديد من التقنيّات المستخدمة في هذا التطبيق وذلك في الدروس السابقة. مع وجود بعض الأمور الجديدة. فمثلًا ولأوّل مرّة وضعنا مخطّط مكدّس ضمن آخر، وهذا أمر شائع كثيرًا في تصميم الواجهات.
صرّحنا في السطر 8 عن الحقل الخاص counter وهو العدّاد الذي سيحتفظ بالقيمة الحالية للعدد المعروض ضمن اللصيقة، وأسندنا له القيمة الابتدائيّة 0. كما صرّحنا في السطر 9 عن الحقل الخاص lblCounter الذي سيمثّل اللصيقة التي سنعرض ضمنها قيمة العدّاد Counter. سنحتاج إلى كلّ من الحقلين السابقين ضمن توابع مختلفة من الصنف CounterPage لذلك وضعناهما على شكل حقلين خاصّين بهذه الصورة.
صرّحنا ضمن البانية CounterPage عن المتغيّر btnIncrement من النوع Button وأسندنا إليه كائن جديد من نوع زر Button حيث أسندنا قيم الخصائص مباشرةً عند الإنشاء، ووظيفة هذا الزر زيادة قيمة المتغيّر counter بمقدار واحد وعرض النتيجة ضمن اللصيقة كما سنرى لاحقًا. لاحظ أنّنا في السطر 19 قد أسندنا معالج الحدث Clicked لهذا الزر. اسم هذا المعالج btnIncrement_Clicked وقد صرّحنا عنه في الأسفل في الأسطر من 61 حتى 65. تكرّر نفس الأمر من أجل الزر btnDecrement (الأسطر من 21 حتى 27) ومعالج الحدث الخاص به btnDecrement_Clicked (الأسطر من 55 حتى 59) ووظيفة هذا الزر هي إنقاص قيمة المتغيّر counter بمقدار واحد وعرض النتيجة ضمن اللصيقة.
إذا انتقلنا إلى الخاصيّة Content للصنف CounterPage (السطر 37)، فنجد أنّه يتم إسناد مخطّط مكدّس جديد وهو يمتلك اتجاهًا رأسيًّا افتراضيًّا كما وسبق أن أوضحنا في درس سابق. سنُسند الخاصيّة Children له فحسب (السطر 39). تصرّح هذه الخاصيّة عن وجود ابنين لهذا المخطّط، الابن الأوّل هو مخطّط مكدّس آخر (الأسطر من 40 حتى 49)، والثاني هو اللصيقة lblDisplay التي ستعرض العدد الحالي:

 
Children = {
    new StackLayout
    {
        Orientation = StackOrientation.Horizontal,
        Padding = new Thickness(0,64,0,64),
        Children =
        {
            btnIncrement,
            btnDecrement
        }
    },
    lblDisplay
}

بالنسبة لمخطّط المكدّس الابن كما يظهر من الشيفرة الأخيرة، لاحظ أنّنا نضبط خاصيّة الاتجاه Orientation له لتكون أفقيّة StackOrientation.Horizontal، كما وضعنا حشوة Padding مناسبة من الأعلى والأسفل لمحتواه، وأخيرًا أسندنا الخاصيّة Children له بحيث تحتوي على ابنين هنا زرّي الزيادة btnIncrement والإنقاص btnDecrement كما هو واضح.
إذًا سيحتوي المخطّط المكدّس الابن (الداخلي) على زرّين متموضّعين في الوسط أفقيًّا، وسيحتوي المخطّط المكدّس الأب (الخارجي) على مخطّط مكدّس ابن، وعلى لصيقة وهما متموضّعان رأسيًّا.
انتقل إلى الملف App.cs واحرص على أن تكون بانية الصنف App على الشكل التالي:

 
public App()
{
    // The root page of your application
    MainPage = new CounterPage();
}

عند تنفيذ البرنامج باستخدام F5 ستحصل على شكل شبيه بما يلي، علمًا أنّني أجريت عدّة نقرات على كلّ من الزرّين:

fig01.png

تحسين تطبيق العدّاد

سنُجري بعض التحسينات البسيطة على تطبيق العدّاد السابق. حيث سنعيد هيكلة الشيفرة البرمجيّة بحيث نستخدم تعابير Lambda كمعالجات أحداث، بدلًا من توابع مستقلّة ضمن الصنف، وفي ذلك فائدة كبيرة، حيث يجعل ذلك الشيفرة البرمجيّة سهلة القراءة والصيانة إلى حدٍّ كبير، كما يمكننا عند ذلك أن نجعل الحقلين counter و lblDisplay عبارة عن متغيّرين محليّين ضمن بانية الصنف. سنضيف ميّزة بسيطة أخرى إلى هذا التطبيق تتمثّل في أنّ البرنامج سيرفض جعل قيمة العدّاد سالبة، حيث سيعرض رسالة بهذا الخصوص، ولا يُغيّر قيمة العدّاد في هذه الحالة.
أضف صفحة محتوى جديدة سمّها EnhancedCounterPage واحرص على أن تكون محتويات الملف EnhancedCounterPage.cs على الشكل التالي:

1	using Xamarin.Forms;
2
3	namespace CounterApp
4	{
5	    public class EnhancedCounterPage : ContentPage
6	    {
7	        public EnhancedCounterPage()
8	        {
9	            int counter = 0;
10	
11	            Label lblDisplay = new Label
12	            {
13	                Text = "0",
14	                TextColor = Color.Accent,
15	                HorizontalOptions = LayoutOptions.CenterAndExpand,
16	                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
17	            };
18	
19	            Button btnIncrement = new Button
20	            {
21	                Text = "+",
22	                HorizontalOptions = LayoutOptions.CenterAndExpand,
23	                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
24	            };
25	            btnIncrement.Clicked += (s, e) =>
26	            {
27	                counter++;
28	                lblDisplay.Text = counter.ToString();
29	            };
30	
31	            Button btnDecrement = new Button
32	            {
33	                Text = "-",
34	                HorizontalOptions = LayoutOptions.CenterAndExpand,
35	                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
36	                };
37	                btnDecrement.Clicked += (s, e) =>
38	                {
39	                    if (counter == 0)
40	                    {
41	                    DisplayAlert("تحذير", "لا يمكن لقيمة العدّاد أن تكون أصغر من الصفر", "موافق");
42	                }
43	                else
44	                {
45	                    counter--;
46	                    lblDisplay.Text = counter.ToString();
47	                }
48	            };
49	
50	            Content = new StackLayout
51	            {
52	                Children = {
53	                    new StackLayout
54	                    {
55	                        Orientation = StackOrientation.Horizontal,
56	                        Padding = new Thickness(0,64,0,64),
57	                        Children =
58	                        {
59	                            btnIncrement,
60	                            btnDecrement
61	                        }
62	                    },
63	                    lblDisplay
64	                }
65	            };
66	        }
67	    }
68	}

جعلنا كل من الحقلين counter وlblDisplay عبارة عن متغيّرين محليّين (السطرين 9 و11). كما تجدر الملاحظة أنّ معالجات الأحداث التقليديّة قد اختفت، وحلّ محلّها تعابير Lambda. انظر إلى الزر btnIncrement في الأسطر من 25 حتى 29:

 
btnIncrement.Clicked += (s, e) =>
{
    counter++;
    lblDisplay.Text = counter.ToString();
};

صرّحنا عن تعبير Lambda يقبل وسيطين s و e، ويعمل على زيادة قيمة المتغيّر counter بمقدار 1 ويعرض النتيجة ضمن اللصيقة. نفس الأمر تمامًا يسري على الزر btnDecrement. انظر إلى الأسطر من 37 حتى 48:

 
btnDecrement.Clicked += (s, e) =>
{
    if (counter == 0)
    {
    DisplayAlert("تحذير", "لا يمكن لقيمة العدّاد أن تكون أصغر من الصفر", "موافق");
}
else
{
    counter--;
    lblDisplay.Text = counter.ToString();
}
};

الفرق الوحيد هنا أنّنا نختبر قيمة المتغيّر counter في حال كان يساوي الصفر قبل إنقاصه، وبالتالي عرض رسالة مناسبة في حال كان كذلك من خلال التابع DisplayAlert (وهو من الصنف ContentPage وكان يمكن أن نصل إليه عن طريق الكلمة المحجوزة this أيضًا). يحتاج التابع DisplayAlert في أحد أشكاله (وهو الشكل المستخدم هنا) إلى ثلاثة وساط هي: عنوان الرسالة، والنص المعروض ضمنها، والنص المعروض على زر الإلغاء، على الترتيب. توجد أشكال أخرى سنتناولها تباعًا ضمن هذه السلسلة.
انتقل إلى الملف App.cs وتأكّد أنّ بانية الصنف App على الشكل التالي:

 
public App()
{
    // The root page of your application
    MainPage = new EnhancedCounterPage();
}

نفّذ البرنامج وانقر الزر (-) مباشرةً أي عندما تكون القيمة الظاهرة على اللصيقة هي صفر، مما سيؤدّي إلى ظهور رسالة التنبيه كما في الشكل التالي:

fig02.png

الخلاصة

تناولنا في هذا الدرس مبادئ التعامل مع الأزرار في Xamarin.Forms من خلال تطبيقين أساسيّين يتفاعلان مع المستخدم. بالإضافة إلى الحديث عن كيفيّة عرض رسائل مخصّصة للمستخدم باستخدام التابع DisplayAlert. هناك العديد من المزايا التي تتمتّع بها الأزرار في Xamarin.Forms. سنستعرض لاحقًا في هذه السلسلة للمزيد من المزايا الإضافيّة للأزرار بالإضافة إلى عناصر مرئيّة أخرى يمكن للمستخدم أن يتفاعل معها.





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن