نماذج ويندوز: نموذجك الأول لسطح المكتب
يبدأ هذا الدرس الجزء الخاص بلغة C# من المعمل. ستبني نافذة حقيقية لسطح المكتب في Visual Studio: تسحب عناصر التحكم (controls) إلى نموذج (form)، وتضبط خصائصها (properties)، وتكتب الأسطر القليلة من الشيفرة التي تعمل عندما ينقر المستخدم زرا أو يختار عنصرا من قائمة. بني كل برنامج في هذا الدرس وشغل على ويندوز، وكل لقطة شاشة أدناه مأخوذة من تشغيل تلك البرامج.
الأهداف
بنهاية هذا الدرس ينبغي أن تكون قادرا على:
- شرح ماهية تطبيق نماذج ويندوز (Windows Forms application)، وماهية النموذج وعنصر التحكم.
- إنشاء مشروع نماذج ويندوز، وتحديد مكان مصمم النماذج (Form Designer) ومستكشف الحلول (Solution Explorer) وصندوق الأدوات (Toolbox) ونافذة الخصائص (Properties window).
- بناء نموذج "Hello World" بوضع Label وتغيير خاصيته Text.
- إضافة عناصر التحكم الشائعة (GroupBox وLabel وTextBox وListBox وRadioButton وCheckBox وButton)، وإعطاء كل منها اسما واضحا في الخاصية Name.
- شرح الحدث (event) ومعالج الحدث (event handler)، وإنشاء معالج بالنقر المزدوج على عنصر التحكم.
- كتابة معالج لـListBox يعرض العنصر المختار، ومعالج لـButton يقرأ ما كتبه المستخدم.
- ملء TreeView بالعقد (nodes)، وعرض صورة في PictureBox.
الجزء 1: ماهية تطبيق نماذج ويندوز
تطبيق نماذج ويندوز برنامج يعمل على حاسوب سطح المكتب. يعرض نافذة واحدة أو أكثر تسمى النماذج، ويحتوي النموذج عادة على مجموعة من عناصر التحكم مثل التسميات (labels) ومربعات النص (text boxes) ومربعات القوائم (list boxes) والأزرار (buttons).
تبين شاشة دخول بسيطة الأدوار الثلاثة الأكثر شيوعا لعنصر التحكم:

- التسميات تصف عناصر التحكم المجاورة لها. وهي هنا تخبر المستخدم أن أحد مربعي النص لاسم المستخدم والآخر لكلمة المرور.
- مربعات النص تحفظ ما يكتبه المستخدم: اسم المستخدم وكلمة المرور.
- الزر ترتبط به شيفرة. النقر على Login يشغل تلك الشيفرة، مثلا للتحقق من اسم المستخدم وكلمة المرور.
كل ما على النموذج كائن في C#
يتيح لك المصمم بناء نموذج دون كتابة شيفرة، لكن لا شيء على النموذج يحدث بالسحر. فخلف سطح التصميم (design surface) شيفرة C# عادية:
| ما تفعله في المصمم | ما يقابله في C# |
|---|---|
| نموذجك، Form1 | صنف (class) يرث من الصنف Form في System.Windows.Forms. والصنف Form يعرف مسبقا كيف يرسم شريط العنوان وأزرار التصغير والتكبير والإغلاق، وكيف يغير حجمه. |
| اسحب عنصر تحكم إلى النموذج | حقل (field) خاص (private) جديد من صنف عنصر التحكم ذلك (مثل Label)، وكائن (object) جديد يخزن فيه |
| غير قيمة في نافذة الخصائص | ضبط خاصية لذلك الكائن، مثل خاصيته Text |
| انقر نقرا مزدوجا على عنصر تحكم | دالة (method) جديدة تعمل عندما يقع أحد أحداث ذلك الكائن |
احتفظ بهذا الجدول في ذهنك: كل خطوة في هذا الدرس تضيف بضعة أسطر من C# أو تغيرها، وسترى تلك الأسطر.
الجزء 2: Hello World
الخطوة 1: أنشئ المشروع
- شغل Visual Studio واختر من القائمة New, Project.
- اختر نوع المشروع Windows Forms Application: انقر خيار Windows في الجانب الأيسر، ثم Windows Forms Application. (تسمي الإصدارات الحديثة من Visual Studio هذا القالب (template) Windows Forms App، ويظهره المرشح Desktop.)
- أعط المشروع اسما، وهو هنا DemoApplication، ومكانا لحفظه.
- انقر OK (أو Create) لكي ينشئ Visual Studio المشروع.
ما يفتحه Visual Studio
| النافذة | الغرض منها |
|---|---|
| مصمم النماذج | سطح التصميم الذي تبني عليه النموذج |
| مستكشف الحلول | ملفات المشروع: Form1.cs وProgram.cs |
| صندوق الأدوات | كل عنصر تحكم يمكنك إضافته إلى نموذج: Label وTextBox وButton وغيرها كثير |
| نافذة الخصائص | خصائص عنصر التحكم المختار (انقر بالزر الأيمن على عنصر التحكم واختر Properties) |
ملفا الشيفرة في مستكشف الحلول هما:
- Form1.cs، وهو النموذج. يحتوي على شيفرة تطبيق نماذج ويندوز، مثل معالجات الأحداث التي ستكتبها.
- Program.cs، وهو البرنامج الرئيسي: شيفرة بدء التطبيق ككل. تعمل دالته
Mainأولا وتفتح النموذج الأول:
namespace DemoApplication
{
internal static class Program
{
[STAThread]
static void Main()
{
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}
}ينشئ Application.Run(new Form1()) كائنا من Form1 ويعرضه. وهذا النموذج الأول هو النموذج الرئيسي: عندما يغلقه المستخدم ينتهي التطبيق.
إذا وسعت Form1.cs في مستكشف الحلول فستجد أيضا Form1.Designer.cs. فالصنف Form1 معرف بوصفه صنفا جزئيا (partial)، لذا يمكن أن توزع شيفرته على ملفين يدمجهما المترجم (compiler) في صنف واحد: Form1.cs للشيفرة التي تكتبها، وForm1.Designer.cs للشيفرة التي يكتبها المصمم لك. ولا ينبغي أن تعدل ملف المصمم يدويا إلا نادرا جدا.
الخطوة 2: أضف تسمية
- من صندوق الأدوات اختر عنصر التحكم Label واسحبه إلى النموذج.
- انقر بالزر الأيمن على التسمية واختر Properties.
- في نافذة الخصائص ابحث عن Text وأدخل
Hello World. - شغل البرنامج بالزر Start.
لكل عنصر تحكم مجموعة من الخصائص التي تصفه، وكل قيمة تضبطها في نافذة الخصائص تصبح سطرا من C# في Form1.Designer.cs. هذه شيفرة المصمم لبرنامج Hello World:
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(150, 110);
this.label1.Name = "label1";
this.label1.TabIndex = 0;
this.label1.Text = "Hello World";
//
// Form1
//
this.ClientSize = new System.Drawing.Size(400, 250);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
private System.Windows.Forms.Label label1;اقرأها وجدول الجزء 1 في ذهنك: ينشئ new System.Windows.Forms.Label() كائن التسمية، وكل سطر this.label1.Something = ... قيمة واحدة من نافذة الخصائص، ويضع this.Controls.Add(this.label1) التسمية على النموذج. ويستدعي باني (constructor) النموذج في Form1.cs الدالة InitializeComponent()، لذا يعمل كل هذا عند إنشاء النموذج.
ويكتب Visual Studio 2022 على .NET 8 الشيفرة نفسها بصيغة أقصر: label1 = new Label(); وlabel1.Location = new Point(150, 110);، دون this. في البداية ودون أسماء النطاقات (namespaces)، ويضيف سطر label1.Size يحمل الحجم المقيس للنص. فإذا بدا ملف Form1.Designer.cs لديك هكذا، فمعناه هو نفسه تماما.
يعرض تشغيل البرنامج النموذج وعليه "Hello World":

الجزء 3: بناء نموذج بيانات المستخدم (User Details)
الآن نبني نموذجا واحدا فيه عناصر تحكم أكثر. يتيح هذا النموذج للمستخدم أن:
- يدخل اسما وعنوانا.
- يختار المدينة التي يسكن فيها.
- يختار الجنس.
- يختار المقررات التي يريد تعلمها: C# وASP.Net.
هذا هو النموذج مكتملا، يعمل على ويندوز:

GroupBox
يجمع مربع المجموعة (group box) عناصر التحكم في قسم واحد. فالاسم والعنوان من بيانات شخص واحد، لذا يوضعان معا في قسم خاص بهما من النموذج.
- اسحب GroupBox من صندوق الأدوات إلى النموذج.
- في نافذة الخصائص غير قيمة Text إلى
User Details.
Label
تعرض التسمية نصا أو رسالة للمستخدم. وتستخدم عادة مع عنصر تحكم آخر لتخبر المستخدم بما يملؤه: فالتسمية المجاورة لمربع نص تبين الغرض منه.
- اسحب Label إلى النموذج مرتين، مرة للاسم وأخرى للعنوان.
- اجعل قيمة Text للأولى
NameوللثانيةAddress.
TextBox والخاصية Name
يتيح مربع النص للمستخدم إدخال نص.
- اسحب عنصري تحكم TextBox إلى النموذج، أحدهما للاسم والآخر للعنوان.
- في نافذة الخصائص اجعل قيمة الخاصية Name لكل منهما اسما ذا معنى:
txtNameوtxtAddress.
الخاصية Name هي اسم متغير عنصر التحكم في شيفرتك. اختر الأسماء وفق اصطلاح تسمية (naming convention): بادئة (prefix) قصيرة لنوع عنصر التحكم، وكلمة تدل على وظيفته. هذا يجعل استخدام عناصر التحكم في الشيفرة لاحقا أسهل كثيرا. الأسماء المستخدمة في هذا الدرس:
| عنصر التحكم | البادئة | مثال |
|---|---|---|
| TextBox | txt | txtName وtxtAddress |
| ListBox | lst | lstCity |
| RadioButton | rd | rdMale وrdFemale |
| CheckBox | chk | chkC وchkASP |
| Button | btn | btnSubmit |
ListBox
يعرض مربع القائمة قائمة من العناصر على النموذج. ويخزن مربعنا أسماء المدن.
- اسحب ListBox إلى النموذج.
- في نافذة الخصائص غير قيمة Name إلى
lstCity. - انقر الخاصية Items (تظهر فيها "(Collection)"). فتظهر نافذة String Collection Editor.
- أدخل أسماء المدن، اسما في كل سطر:
MumbaiوBangaloreوHyderabad. - انقر OK.
يحول المحرر أسطرك إلى عبارة واحدة في ملف المصمم:
this.lstCity.Items.AddRange(new object[] {
"Mumbai",
"Bangalore",
"Hyderabad"});RadioButton
يعرض زر الاختيار (radio button) قائمة من الخيارات يستطيع المستخدم أن يختار منها خيارا واحدا فقط. نضيف زرين، للذكر والأنثى.
- اسحب عنصري تحكم RadioButton إلى النموذج.
- اجعل قيمة Text لهما
MaleوFemale. - اجعل قيمة Name لهما
rdMaleوrdFemale.
CheckBox
تتيح خانة الاختيار (check box) للمستخدم أن يختار عدة خيارات معا. نضيف خانتين، ليختار المستخدم C# أو ASP.Net أو كليهما.
- اسحب عنصري تحكم CheckBox إلى النموذج.
- اجعل قيمة Text لهما
C#وASP.Net. - اجعل قيمة Name لهما
chkCوchkASP.
يهمك هذا الفرق عند تصميم نموذج: اختر RadioButton عندما تستبعد الإجابات بعضها بعضا (الجنس)، وCheckBox عندما يجوز للمستخدم أن يختار أكثر من خيار (المقررات).
Button
يتيح الزر للمستخدم بدء معالجة النموذج. وزرنا يرسل كل ما أدخله المستخدم.
- اسحب Button إلى النموذج.
- اجعل قيمة Text له
Submitوقيمة Name لهbtnSubmit.
أصبح لديك الآن أول نموذج ويندوز أساسي.
تفاعلي: مصمم النماذج
الأداة أدناه مصمم نماذج صغير. اسحب عناصر التحكم من صندوق الأدوات إلى النموذج، وغير Name وText في لوحة الخصائص، وراقب تغير ملفي الشيفرة: كل فعل تقوم به في المصمم هو بضعة أسطر من C#. انقر نقرا مزدوجا على عنصر تحكم لإضافة معالج الحدث الخاص به، ثم انتقل إلى تبويب التشغيل لترى الأحداث التي تقع. ويبني زر بدء العرض نموذج الدخول من الجزء 1 خطوة بعد خطوة.
الجزء 4: الأحداث
الحدث شيء يقع عند تنفيذ فعل ما، وأشهر الأحداث النقر على زر. أما معالج الحدث فدالة تعمل عندما يقع حدثها: في نماذج ويندوز تضيف شيفرة تنفذ أفعالا معينة، مثلا عند النقر على زر.
النقر المزدوج ينشئ معالجا
انقر نقرا مزدوجا على ListBox في مصمم النماذج. يفتح Visual Studio الملف Form1.cs ويضيف لك دالة فارغة:
private void lstCity_SelectedIndexChanged(object sender, EventArgs e)
{
}ويضيف أيضا سطرا واحدا إلى Form1.Designer.cs يربط الدالة بحدث ListBox:
this.lstCity.SelectedIndexChanged += new System.EventHandler(this.lstCity_SelectedIndexChanged);لا داعي للقلق الآن بشأن اسم الدالة أو معاملاتها (parameters). المهم أن هذه الدالة تعمل الآن كلما اختير أي عنصر في مربع القائمة. ينشئ النقر المزدوج معالج الحدث الافتراضي (default event) لعنصر التحكم، أي الحدث الذي تحتاج إليه غالبا مع ذلك العنصر. ولرؤية كل الأحداث الأخرى لعنصر تحكم، انقر زر البرق في نافذة الخصائص.
قرأنا الأحداث الافتراضية من نماذج ويندوز نفسها ببرنامج قصير شغلناه على ويندوز:
| عنصر التحكم | الحدث الافتراضي |
|---|---|
| Button وLabel | Click |
| TextBox | TextChanged |
| ListBox | SelectedIndexChanged |
| CheckBox وRadioButton | CheckedChanged |
| النموذج نفسه | Load |
وأعطى التشغيل نفسه حجم عنصر التحكم المنشأ حديثا: TextBox بحجم 100 في 23 بكسل، وButton بحجم 75 في 23، وListBox بحجم 120 في 96. وتفصيل آخر قسناه: عندما يختار المستخدم Female بينما Male مختار، يطلق كلا زري الاختيار الحدث CheckedChanged، أولا rdMale (الذي ألغي اختياره)، ثم rdFemale.
مثال محلول: عرض المدينة المختارة
أضف الآن الشيفرة التي تعرض المدينة المختارة في مربع رسالة (message box):
private void lstCity_SelectedIndexChanged(object sender, EventArgs e)
{
string text = lstCity.GetItemText(lstCity.SelectedItem);
MessageBox.Show(text);
}- الدالة هي معالج الحدث الذي أنشأه Visual Studio عندما نقرت نقرا مزدوجا على مربع القائمة.
lstCity.SelectedItemهو العنصر الذي اختاره المستخدم. تذكر أنlstCityهو اسم ListBox لدينا. تجلبGetItemTextالنص الفعلي لذلك العنصر، ونخزنه في المتغيرtext.- تعرض
MessageBox.Show(text)القيمة للمستخدم.
توقع ما يظهر عندما ينقر المستخدم Bangalore، ثم قارن بالتشغيل:

اختيار عنصر أطلق الحدث SelectedIndexChanged، فقرأ المعالج العنصر المختار وعرضه.
مثال محلول: الزر Submit
يتبع الزر الفكرة نفسها. انقر نقرا مزدوجا على الزر في مصمم النماذج لتحصل على معالج الحدث Click الخاص به، ثم أضف:
private void btnSubmit_Click(object sender, EventArgs e)
{
string name = txtName.Text;
string address = txtAddress.Text;
MessageBox.Show(name + address);
}- الدالة هي المعالج الذي أنشأه Visual Studio عندما نقرت نقرا مزدوجا على الزر.
- القيم التي كتبها المستخدم موجودة في الخاصية Text لكل مربع نص. ننسخها إلى متغيرين،
nameوaddress. - تعرض
MessageBox.Showالاسم والعنوان.
توقع: يكتب المستخدم Student اسما وMansoura عنوانا، ثم ينقر Submit. ماذا يقول مربع الرسالة بالضبط؟

الرسالة هي StudentMansoura، بلا مسافة: فالعامل + يربط سلسلتين نصيتين (strings) كما هما تماما. وللفصل بينهما أضف مسافة في الوسط: MessageBox.Show(name + " " + address);. ويختبر التمرين 2 ذلك.
يجب أن يطابق الاسم في الشيفرة قيمة الخاصية Name
الخاصية Name هي اسم المتغير. افترض أنك سميت مربع الاسم txtUser في نافذة الخصائص، لكن المعالج ما زال يقرأ txtName.Text. توقع ما يحدث عند البناء (build).
لا يبنى البرنامج أصلا. هذه رسالة المترجم من ذلك البناء (مع اختصار مسار الملف):
Form1.cs(21,27): error CS0103: The name 'txtName' does not exist in the current contextالسطر 21، العمود 27 من Form1.cs هو txtName في string name = txtName.Text;. لا يوجد حقل اسمه txtName، لأن المصمم أنشأ حقلا اسمه txtUser. والحل أن تستخدم الاسم نفسه في الموضعين: أعد تسمية عنصر التحكم إلى txtName في نافذة الخصائص، أو غير الشيفرة إلى txtUser.Text.
الجزء 5: TreeView وPictureBox
TreeView
يسرد عنصر الشجرة (tree control) العناصر على هيئة شجرة. وأشهر مثال عليه بنية المجلدات في مستكشف ويندوز (Windows Explorer).
- اسحب TreeView من صندوق الأدوات إلى النموذج.
- في نافذة الخصائص انقر الخاصية Nodes. فتفتح نافذة TreeNode Editor.
- انقر Add Root، وغير Text للعقدة إلى
Root، ثم انقر OK. هذا يضيف العقدة الجذرية (root node). - اختر Root وانقر Add Child، ثم غير Text للعقدة الفرعية (child node). كرر ذلك لتحصل على ثلاث عقد فرعية:
LabelوButtonوCheckbox. - انقر OK.
يكتب المصمم الشجرة على هيئة كائنات TreeNode. تنشأ العقد الفرعية أولا، ثم تستقبلها العقدة الجذرية في مصفوفة (array):
System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("Label");
System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("Button");
System.Windows.Forms.TreeNode treeNode3 = new System.Windows.Forms.TreeNode("Checkbox");
System.Windows.Forms.TreeNode treeNode4 = new System.Windows.Forms.TreeNode("Root", new System.Windows.Forms.TreeNode[] {
treeNode1,
treeNode2,
treeNode3});ثم يضيف العقدة الجذرية لاحقا إلى الشجرة بـthis.treeView1.Nodes.AddRange(...). عند تشغيل البرنامج تظهر في الشجرة العقدة Root وبجوارها علامة زائد؛ انقرها لتوسيع العقدة الجذرية ورؤية العقد الفرعية الثلاث.
PictureBox
يضيف مربع الصورة (picture box) صورة إلى النموذج.
- اسحب PictureBox من صندوق الأدوات إلى النموذج.
- انقر الخاصية Image له. تظهر نافذة جديدة.
- انقر Import واختر الصورة في مربع الحوار.
- انقر OK.
تظهر الصورة الآن على النموذج. ويمكن أيضا ضبط الخاصية Image بالشيفرة، مثل أي خاصية أخرى. ويحمل برنامج المعمل صورته من ملف بجوار البرنامج، في باني النموذج:
pictureBox1.Image = Image.FromFile(Path.Combine(AppContext.BaseDirectory, "picture.png"));هذا هو النموذج مكتملا وقد ملئت فيه مدخلات المستخدم (مع اختيار Male وC#):

البرنامج كاملا
ثلاثة ملفات تكون برنامج بيانات المستخدم كله. الملف Program.cs هو المعروض في الجزء 2. ويحتوي Form1.cs على معالجي الحدثين:
namespace DemoApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// The designer's Import button attaches a picture to the Image property.
// Here the same property is set from the picture file next to the program.
pictureBox1.Image = Image.FromFile(Path.Combine(AppContext.BaseDirectory, "picture.png"));
}
private void lstCity_SelectedIndexChanged(object sender, EventArgs e)
{
string text = lstCity.GetItemText(lstCity.SelectedItem);
MessageBox.Show(text);
}
private void btnSubmit_Click(object sender, EventArgs e)
{
string name = txtName.Text;
string address = txtAddress.Text;
MessageBox.Show(name + address);
}
}
}ويحتوي Form1.Designer.cs على كل ما فعلناه في المصمم. اقرأه قسما بعد قسم: سطر new واحد لكل عنصر تحكم، وكتلة واحدة من أسطر الخصائص لكل عنصر تحكم، ثم النموذج نفسه.
namespace DemoApplication
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("Label");
System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("Button");
System.Windows.Forms.TreeNode treeNode3 = new System.Windows.Forms.TreeNode("Checkbox");
System.Windows.Forms.TreeNode treeNode4 = new System.Windows.Forms.TreeNode("Root", new System.Windows.Forms.TreeNode[] {
treeNode1,
treeNode2,
treeNode3});
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.txtName = new System.Windows.Forms.TextBox();
this.txtAddress = new System.Windows.Forms.TextBox();
this.lstCity = new System.Windows.Forms.ListBox();
this.rdMale = new System.Windows.Forms.RadioButton();
this.rdFemale = new System.Windows.Forms.RadioButton();
this.chkC = new System.Windows.Forms.CheckBox();
this.chkASP = new System.Windows.Forms.CheckBox();
this.btnSubmit = new System.Windows.Forms.Button();
this.treeView1 = new System.Windows.Forms.TreeView();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
//
this.groupBox1.Controls.Add(this.label1);
this.groupBox1.Controls.Add(this.label2);
this.groupBox1.Controls.Add(this.txtName);
this.groupBox1.Controls.Add(this.txtAddress);
this.groupBox1.Location = new System.Drawing.Point(20, 15);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(240, 100);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "User Details";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(15, 30);
this.label1.Name = "label1";
this.label1.TabIndex = 0;
this.label1.Text = "Name";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(15, 63);
this.label2.Name = "label2";
this.label2.TabIndex = 2;
this.label2.Text = "Address";
//
// txtName
//
this.txtName.Location = new System.Drawing.Point(90, 27);
this.txtName.Name = "txtName";
this.txtName.Size = new System.Drawing.Size(130, 23);
this.txtName.TabIndex = 1;
//
// txtAddress
//
this.txtAddress.Location = new System.Drawing.Point(90, 60);
this.txtAddress.Name = "txtAddress";
this.txtAddress.Size = new System.Drawing.Size(130, 23);
this.txtAddress.TabIndex = 3;
//
// lstCity
//
this.lstCity.Items.AddRange(new object[] {
"Mumbai",
"Bangalore",
"Hyderabad"});
this.lstCity.Location = new System.Drawing.Point(20, 130);
this.lstCity.Name = "lstCity";
this.lstCity.Size = new System.Drawing.Size(120, 94);
this.lstCity.TabIndex = 1;
this.lstCity.SelectedIndexChanged += new System.EventHandler(this.lstCity_SelectedIndexChanged);
//
// rdMale
//
this.rdMale.AutoSize = true;
this.rdMale.Location = new System.Drawing.Point(290, 25);
this.rdMale.Name = "rdMale";
this.rdMale.TabIndex = 2;
this.rdMale.Text = "Male";
//
// rdFemale
//
this.rdFemale.AutoSize = true;
this.rdFemale.Location = new System.Drawing.Point(290, 55);
this.rdFemale.Name = "rdFemale";
this.rdFemale.TabIndex = 3;
this.rdFemale.Text = "Female";
//
// chkC
//
this.chkC.AutoSize = true;
this.chkC.Location = new System.Drawing.Point(290, 100);
this.chkC.Name = "chkC";
this.chkC.TabIndex = 4;
this.chkC.Text = "C#";
//
// chkASP
//
this.chkASP.AutoSize = true;
this.chkASP.Location = new System.Drawing.Point(290, 130);
this.chkASP.Name = "chkASP";
this.chkASP.TabIndex = 5;
this.chkASP.Text = "ASP.Net";
//
// btnSubmit
//
this.btnSubmit.Location = new System.Drawing.Point(290, 175);
this.btnSubmit.Name = "btnSubmit";
this.btnSubmit.Size = new System.Drawing.Size(90, 28);
this.btnSubmit.TabIndex = 6;
this.btnSubmit.Text = "Submit";
this.btnSubmit.Click += new System.EventHandler(this.btnSubmit_Click);
//
// treeView1
//
this.treeView1.Location = new System.Drawing.Point(430, 20);
this.treeView1.Name = "treeView1";
treeNode1.Name = "Node1";
treeNode1.Text = "Label";
treeNode2.Name = "Node2";
treeNode2.Text = "Button";
treeNode3.Name = "Node3";
treeNode3.Text = "Checkbox";
treeNode4.Name = "Node0";
treeNode4.Text = "Root";
this.treeView1.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
treeNode4});
this.treeView1.Size = new System.Drawing.Size(170, 110);
this.treeView1.TabIndex = 7;
//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(430, 150);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(120, 60);
this.pictureBox1.TabIndex = 8;
this.pictureBox1.TabStop = false;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(630, 245);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.lstCity);
this.Controls.Add(this.rdMale);
this.Controls.Add(this.rdFemale);
this.Controls.Add(this.chkC);
this.Controls.Add(this.chkASP);
this.Controls.Add(this.btnSubmit);
this.Controls.Add(this.treeView1);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "User Details";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox txtName;
private System.Windows.Forms.TextBox txtAddress;
private System.Windows.Forms.ListBox lstCity;
private System.Windows.Forms.RadioButton rdMale;
private System.Windows.Forms.RadioButton rdFemale;
private System.Windows.Forms.CheckBox chkC;
private System.Windows.Forms.CheckBox chkASP;
private System.Windows.Forms.Button btnSubmit;
private System.Windows.Forms.TreeView treeView1;
private System.Windows.Forms.PictureBox pictureBox1;
}
}لاحظ عناصر التحكم الأربعة داخل مربع المجموعة: تضاف بـthis.groupBox1.Controls.Add(...)، لا إلى النموذج، وبهذه الطريقة يسجل المصمم أنها داخل المجموعة.
فحص سريع
- تحتاج إلى أن يختار المستخدم مستوى دراسيا واحدا بالضبط من أربعة مستويات. هل تستخدم RadioButton أم CheckBox؟
- أي خاصية تحفظ ما كتبه المستخدم في TextBox؟
- أي خاصية هي الاسم الذي تستخدمه لعنصر التحكم في شيفرتك؟
- ماذا تفعل في المصمم لتحصل على معالج للحدث Click لزر ما؟
- في نموذج بيانات المستخدم، أي دالة تعمل عندما يختار المستخدم Hyderabad؟
تمارين
نحو 30 دقيقة. ابن كل نموذج في Visual Studio (أو خطط له في أداة مصمم النماذج أولا)، ثم شغله. الإجابات في النهاية.
التمرين 1: نموذج الدخول (نحو 10 دقائق)
ابن نموذج الدخول من الجزء 1:
| عنصر التحكم | Text | Name |
|---|---|---|
| Label | User Name | label1 |
| Label | Password | label2 |
| TextBox | (فارغ) | txtUser |
| TextBox | (فارغ) | txtPassword |
| Button | Login | btnLogin |
اجعل قيمة Text للنموذج Login. عندما ينقر المستخدم Login، اعرض مربع رسالة يقول Welcome متبوعا باسم المستخدم. ماذا يعرض مربع الرسالة عندما يكون اسم المستخدم admin؟
التمرين 2: توقع الرسالة (نحو 4 دقائق)
نموذج فيه مربعا نص، txtName وtxtAddress، وثلاثة أزرار. يقرأ كل معالج أولا string name = txtName.Text; وstring address = txtAddress.Text;، ثم:
// button A
MessageBox.Show(name + " " + address);
// button B
MessageBox.Show("Name: " + name);
// button C
MessageBox.Show(address + name);يكتب المستخدم Student اسما وCairo عنوانا. اكتب الرسالة الدقيقة التي يعرضها كل زر.
التمرين 3: قائمة مقررات (نحو 8 دقائق)
ابن نموذجا عنوانه Courses فيه Label نصه Choose a course، وListBox اسمه lstCourse وعناصره C# وASP.Net وOperating Systems، وButton اسمه btnShow وقيمة Text له Show. عندما ينقر المستخدم Show، اعرض You chose متبوعا بالمقرر المختار. استخدم GetItemText وSelectedItem كما في معالج lstCity.
- ماذا يعرض مربع الرسالة بعد أن يختار المستخدم Operating Systems وينقر Show؟
- ماذا يعرض إذا نقر المستخدم Show قبل أن يختار أي شيء؟
التمرين 4: اعثر على الخطأ (نحو 4 دقائق)
بنى طالب نموذج التمرين 3، وسمى ListBox فيه lstCourse، وكتب هذا المعالج:
private void btnShow_Click(object sender, EventArgs e)
{
string course = lstCourses.GetItemText(lstCourses.SelectedItem);
MessageBox.Show("You chose " + course);
}هل يعمل؟ وإن لم يعمل، فماذا يبلغ المترجم، وكيف تصلحه؟
التمرين 5: اختر عناصر التحكم (نحو 4 دقائق)
خطط لنموذج تسجيل طالب. لكل معلومة، اختر عنصر التحكم وقيمة Name تتبع اصطلاح التسمية: الاسم الكامل للطالب؛ والمستوى الدراسي (واحد بالضبط من أربعة)؛ والهوايات (أي عدد من أربع)؛ والمدينة (واحدة من قائمة مدن)؛ وزر يحفظ النموذج.
الإجابات
فحص سريع
- RadioButton: يختار المستخدم خيارا واحدا بالضبط من عدة خيارات. أما CheckBox فيسمح بعدة اختيارات.
- Text، مثل
txtName.Text. - Name، مثل
lstCity. - انقر نقرا مزدوجا على الزر في مصمم النماذج. يضيف Visual Studio دالة المعالج ويربطها بالحدث Click للزر.
lstCity_SelectedIndexChanged، وهي معالج الحدث SelectedIndexChanged لعنصر ListBox.
التمرين 1
الملف Form1.cs:
namespace DemoApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnLogin_Click(object sender, EventArgs e)
{
string user = txtUser.Text;
MessageBox.Show("Welcome " + user);
}
}
}جزء المصمم الخاص بالزر (تتبع التسميات ومربعات النص النمط نفسه المستخدم في نموذج بيانات المستخدم):
this.btnLogin.Location = new System.Drawing.Point(110, 105);
this.btnLogin.Name = "btnLogin";
this.btnLogin.Size = new System.Drawing.Size(90, 28);
this.btnLogin.TabIndex = 4;
this.btnLogin.Text = "Login";
this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);مع اسم المستخدم admin يعرض مربع الرسالة Welcome admin:

تأتي المسافة من السلسلة النصية "Welcome " التي تنتهي بمسافة.
التمرين 2
| الزر | الشيفرة | الرسالة |
|---|---|---|
| A | name + " " + address | Student Cairo |
| B | "Name: " + name | Name: Student |
| C | address + name | CairoStudent |
الرسائل الثلاث من التشغيل:


يربط العامل + السلاسل النصية كما هي تماما وبالترتيب المكتوب: لا يضاف بينها شيء، لذا يعطي الزر C النتيجة CairoStudent.
التمرين 3
private void btnShow_Click(object sender, EventArgs e)
{
string course = lstCourse.GetItemText(lstCourse.SelectedItem);
MessageBox.Show("You chose " + course);
}You chose Operating Systems:

- عند عدم اختيار أي شيء تكون
SelectedItemفارغة، وتعيدGetItemTextسلسلة نصية فارغة، لذا يعرض مربع الرسالةYou choseفقط:

التمرين 4
لا يبنى البرنامج. يبلغ المترجم (مع اختصار مسار الملف):
Form1.cs(12,29): error CS0103: The name 'lstCourses' does not exist in the current context
Form1.cs(12,52): error CS0103: The name 'lstCourses' does not exist in the current contextهناك خطآن لأن الاسم الخطأ استخدم مرتين في السطر 12، عند العمودين 29 و52. قيمة Name لعنصر ListBox هي lstCourse، لذا أنشأ المصمم حقلا اسمه lstCourse، ولا يوجد شيء اسمه lstCourses. استخدم الاسم نفسه الموجود في الخاصية Name: lstCourse.GetItemText(lstCourse.SelectedItem). وهذا هو الخطأ نفسه الذي رأيناه في مثال txtUser وtxtName في الجزء 4.
التمرين 5
| المعلومة | عنصر التحكم | Name |
|---|---|---|
| الاسم الكامل | TextBox | txtName |
| المستوى الدراسي، واحد بالضبط | RadioButton (أربعة أزرار) | مثلا rdLevel1 إلى rdLevel4 |
| الهوايات، أي عدد | CheckBox (أربع خانات) | مثلا chkReading وchkSport |
| مدينة من قائمة | ListBox | lstCity |
| الحفظ | Button | btnSave |
وضع Label بجوار مربع النص، وGroupBox حول كل مجموعة من عناصر التحكم المترابطة، يساعد المستخدم على قراءة النموذج. والأسماء المعقولة الأخرى مقبولة، ما دامت لكل منها البادئة الصحيحة وتدل على الغرض من عنصر التحكم.