khaledbelal
03-22-2010, 04:10 PM
الدرس الحادي عشر
دوارة While
في الدرس الرابع تعرفنا على هيكل من هياكل التكرار في لغة C# وهو دوارة for
والحقيقة أن هناك هياكل أخرى من هياكل التكرار أهمها هي دوارة While
وهي تشبة إلى حد كبير دوارة for بإختلاف أنها لا تحتوي على عداد Counter كما كنا نعرف i في دوارة for
والهيكل الأساسي لدوارة While يشبة إلى حد كبير هيكل for بإختلاف أشياء بسيطة :
while (شرط التكرار)
{
كود الدوارة
}
تقوم جملة while بتكرار كود الدوارة ما دام شرط التكرار متحققاً , مثلاً :
int n=0;
while (n<5)
{
MessageBox.Show("من داخل الدوارة ");
n++;
}
الدوارة السابقة تقوم بإظهار الرسالة خمس مرات
حيث عرفنا متغير من نوع رقم n وأسندنا له قيمة إبتدائية 0
وشرط التكرار في الدوارة هو أن تكون قيمة المتغير n أصغر من 5
في المرة الأولى ستكون قيمة n هي صفر , وبالتالي فشرط التكرار متحقق , لأن الصفر أقل من 5
يتم تنفيذ كود إظهار الرسالة , والكود n++ يعني إضافة واحد إلى قيمة n أي أن n سيحمل الآن القيمة 1
يعود المعالج لبداية جملة while ويختبر شرط التكرار مرة أخرى ثم ينفذ كود إظهار الرسالة ويزيد واحد لقيمة n
وهكذا حتى تصبح قيمة n=5 عندها لن يتحقق شرط التكرار لأن 5 لسيت أقل من 5
وبالتالي يقفز المعالج إلى نهاية كود الدوارة ويواصل تنفيذ التعليمات بعدها
يستخدم هذا النوع من الدوارات حين لا نعرف كم بالضبط سنكرر كود الدوارة
وسنستخدمها في درس اليوم حيث لدينا معلومات الألبوم ولا نعرف عدد الملفات في الألبوم كما سنشرح بالتفصيل لا حقا
ملفات XML
من اهم أنظمة الحاسوب التي استفادة منها الإنسانية منذ ظهور الحاسوب هي أنظمة قواعد البيانات
وأنظمة قواعد البيانات هي برمجيات تستخدم مع لغات البرمجة بغرض خزن وإسترجاع أنواع متعددة من البيانات
ويتم خزن هذه البيانات بطرق مرتبة ومنهجية بحيث يسهل إسترجاع بيانات محددة مهما كبير كان حجم البيانات
حيث يتم ترتيب البيانات في وحدات متجانسة تسمى جداول Tables والتي تحتوي على حقول Fields لكل حقل نوع محدد من البيانات
ويمكن للجدول الواحد أن يحتوي على عدة حقول من أنواع بيانات مختلفة
قد ترتبط الجداول مع بعضها بواسطة علاقات Relationships حيث تعتمد بيانات من جدول على بيانات من جدول آخر
أنظمة قواعد البيانات تقسم إلى قسمين , نظام الخزن , ونظام المعالجة
أما نظام الخزن فهو المسئول عن خزن البيانات في ملفاتها المحددة بغض النظر عن ترتيبها أو أماكنها
ونظام المعالجة هو المسئول عن تحديد أماكن البيانات الصحيحة و إسترجاعها والقيام بالعمليات عليها
النظام الأول -نظام الخزن- يتكفل به نظام التشغيل ولا يحتاج لبرمجيات أو برامج خاصة
أما النظام الثاني فيتطلب برمجيات محددة لنظام قواعد البيانات
معظم أنظمة قواعد البيانات تستخدم النظام الثاني , مثل قواعد الأكسس و الأوراكل و غيرها
هناك أنواع أخرى لا تتطلب برمجيات مخصصة للتعامل معها ومنها نظام قواعد البيانات عبر ملفات XML
وهذا هو محور درسنا اليوم , حيث لا يحتاج هذا النظام لبرمجيات متخصصة للتعامل معه
وإنما ملفاته عبارة عن ملفات نصية يمكن فتحها وتعديلها بأي محرر نصوص
وسنستخدم ملفات XML في تطبيقنا لخزن بيانات الألبومات أو قوائم التشغيل
صيغة هذه الملفات النصية تشبة إلى حد كبير صيغة ملفات HTML
حيث يعتمد على وسوم Tags ترتب البيانات في هياكل مترابطة
وكل جزء من البيانات يحتوي على وسم بداية ووسم نهاية وله إسم محدد
فمثلاً هذا الكود :
<msg>رسالة</msg>
هذا جزء من كود ملف XML حيث يحتوي على جزء لخزن البيانات إسمه msg
يحتوي هذا الجزء على بيانات مخزنة هو كلمة "رسالة" لاحظ أن الجزء يحتوي على وسمين
وسم البداية حيث يحتوي على إسم الجزء بين علامتي أصغر وأكبر من
ووسم النهاية وهو مشابه تماما لوسم البداية بزيادة الشرطة المائلة / قبل إسم الجزء في وسم النهاية
وبين الوسمين توجد البيانات
وتسمى الأجزاء في ملفات XML بالعقد Nodes فالكود السابق يحتوي على عقدة إسمها msg
سميت بالعقد لأنه يمكن لأي جزء من البيانات أن يحتوي على أجزاء أخرى :
<albumes>
<albume1>
</albume1>
</albumes>
الكود السابق يحتوي على عقدة رئيسية إسمها albumes تحتوي بدورها على عقدة فرعية إسمها albume1
يمكن أن تحتوي العقدة على عدة عقد فرعية :
<albumes>
<albume1>
</albume1>
<albume2>
</albume2>
</albumes>
لعقدة الرئيسية albumes تحتوي على عقدتين فرعيتين albume1 و albume2
يمكن أيضاً للعقدة الفرعية أن تحتوي على عقد فرعية أخرى:
<albumes>
<albume1>
<file>sound.mp3</file>
<file>wave.rm</file>
</albume1>
<albume2>
<file>real.wav</file>
</albume2>
</albumes>
العقدة الرئيسية albumes تحتوي على عقدتين فرعيتين albume1 و albume2
العقدة الفرعية albume1 تحتوي على عقدتين فرعيتين بنفس الإسم file
كل عقدة من عقدتي file بيانات نصية sound.mp3 و wave.rm
والعقدة الفرعية albume2 تحتوي على عقدة فرعية file
الكود السابق يمثل ملف XML يحتوي على بيانات مرتبة في عقد , ولكن ينقصة شيئ مهم
نوع التكويد في المف , ورقم إصدار كود XML , والتكويد هو أسلوب خزن البيانات النصية في الملف
عادة ما نستخدم تكويد UTF-8 , وسطر نوع التكويد يجب أن يكون في بداية الملف:
<?xml version="1.0" encoding="utf-8"?>
<albumes>
<albume1>
<file>sound.mp3</file>
<file>wave.rm</file>
</albume1>
<albume2>
<file>real.wav</file>
</albume2>
</albumes>
هذا السطر لا يتغير في معظم ملفات XML
هذا هو هيكل الملف الذي سيقوم بخزن بيانات الألبومات وقوائم التشغيل
يتم التعامل مع ملف XML في البرنامج من خلال كائن XmlDocument الموجود في فضاء الأسماء System.XML:
XmlDocument doc = new XmlDocument();
الكود السابق عرفنا من خلالة كائن إسمه doc من نوع XmlDocument
الكائن doc يقوم بتحميل المف عن طريق الإجراء Load
doc.Load("c://albumes.xml");
الكود السابق يقوم بتحميل الملف albumes.xml الموجود في القرص c إلى الكائن doc
يتم الوصول إلى العقد الموجوده في المف عن طريق ذكر إسم العقدة الرئيسية متبوعة بقوسين مربعين يحتويان إسم العقدة الفرعية
أما إذا أردنا الوصول إلى العقد الرئيسية المسماه albumes فنكتب إسم الكائن doc متبوعاً بقوسين مربعين يحتويان إسم العقدة :
doc["albumes"];
ويتم الوصول إلى البيانات في العقدة بواسطة الخاصية InnerText :
MessageBox.Show(doc["albumes"].InnerText);
الكود السابق يقوم بإظهار رسالة تحتوي على البيانات المخزنة في العقدة albumes
ويتم الوصول لإسم العقدة عن طريق الخاصية :Name
MessageBox.Show(doc["albumes"].Name);
الكود السابق يظهر رسالة تحتوي على إسم العقدة albumes
ويتم الوصول إلى العقد الفرعية بإضافة قوسين مربعين يحتويان إسم العقدة
فمثلاً للوصول إلى العقدة الفرعية albume1 الموجود في العقدة albumes :
doc["albumes"]["albume1"]
وللوصول إلى العقدة الأعمق file :
doc["albumes"]["albume1"]["file"]
التطبيق
افتح تطبيق الدرس السابق , من نافذة مستعرض المشروع, أنقر بالزر الأيمن على إسم المشروع
ومن القائمة الناتجة إختر Add ثم New Item :
http://absba7.absba.org/teamwork8/455943/89.jpg
ستظهر نافذة إضافة ملف جديدة للمشروع , من القائمة في اليسار إختر misc
ثم إختر Empty XML file , وفي صندوق إسم الملف أكتب الإسم التالي albumes.xml , وإختر OK
http://absba7.absba.org/teamwork8/455943/90.jpg
إذهب إلى مجلد المشروع وأنسخ الملف albumes.xml إلى مجلد Debug الموجود داخل مجلد bin
حيث يصبح الملف موجود بجانب ملفات المشروع الأخرى
الآن قم بفتح تصميم نافذة الألبومات وسحب ثلاثة أزرار إلى النافذة وغير الأسماء فيها إلى
ألبوم جديد
حفظ الألبوم
حذف الألبوم
ومن صندوق الأدوات إسحب كائن القائمة المنسدلة إلى نافذة الالبومات :
http://absba7.absba.org/teamwork8/455943/91.jpg
إختر كائن القائمة المنسدلة و من جدول الخصائص , غير الخاصية (Name) , إلى ac
وغير الخاصية Text إلى "إختر الألبوم"
قم بترتيب الأدوات في النافذة حتى تصبح هكذا :
http://absba7.absba.org/teamwork8/455943/92.jpg
جميع الدوال التي سنستخدمها للتعامل مع ملف XML موجوده في فضاء الأسماء XML الموجود داخل الفضاء System
لذلك يجب إضافة عبارة using لتعريف جميع دوال وكائنات التعامل مع ملفات XML
إذهب إلى شفرة نافذة الألبومات و أكتب السطر التالي , تحت جمل using في رأس الملف:
http://absba7.absba.org/teamwork8/455943/93.jpg
يتم تحميل ملف XML إلى البرنامج والتعامل معه من خلال كائن XmlDocument
حيث سنعرف كائن عام من هذا النوع ليتم التعامل معه في جميع أنحاء نافذة الألبومات
إنسخ كود التعريف تحت تعريف قائمة albume من الدرس السابق :
http://absba7.absba.org/teamwork8/455943/94.jpg
قمنا هنا بتعريف كائن إسمه doc من نوع XmlDocument , ولأنه كائن إستخدمنا الكلمة new
إجراء تحميل الألبومات للقائمة المنسدلة FillCombo
يقوم هذا الإجراء بتحميل أسماء الألبومات الموجوده في ملف XML إلى القائمة المنسدلة ac
قم بنسخ الكود التالي إلى شفرة نافذة الألبومات وتأكد أنه خارج أي إجراء آخر :
void FillCombo()
{
doc.Load(Application.StartupPath + "//albumes.xml");
XmlNode alnd = doc["albumes"].FirstChild;
while (alnd != null)
{
ac.Items.Add(alnd.Name);
alnd = alnd.NextSibling;
}
}
السطر الأول يقوم بتحميل الملف إلى الكائن doc
والتعليمة Application.StartupPath تعيد قيمة نصية تمثل مسار ملف exe للتطبيق
حيث إستفدنا من هذه التعليمة لمعرفة مسار ملف XML وأضفنا إسم الملف للمسار
في السطر الثاني قمنا بتعريف كائن من نوع عقدة XmlNode إسمه alnd
ثم حملنا هذا الكائن أول عقدة فرعية داخل العقدة الرئيسية albumes من خلال الخاصية FirstChild
السطر الثالث يمثل جملة while تنفذ كود الدوارة ما دامت العقدة alnd تحمل قيمة
الشرط alnd!=null يختبر الكائن alnd فإذا كان يحمل قيمة غير القيمة الفارغة null فسيتم تنفيذ كود الدوارة
أما إذا كان الكائن alnd لا يحمل قيمة أي أنه يحمل null فعندها لن يتم تنفيذ كود الدوارة
السطر الخامس يقوم بإضافة إسم العقدة alnd إلى القائمة المنسدلة ac
السطر السادس يقوم بإختيار العقدة التالية للعقدة alnd حيث يحمل الكائن alnd العقد التالية لما كان يحمله
يتم تكرار السطرين السابقين حتى الوصول إلى آخر عقدة عندها سيحمل الكائن alnd القيمة null لأنه لا يوجد عقدة تالية للعقدة الأخيرة
وبالتالي ينتهي تكرار جملة while
لكن ماذا لو لم يكن هناك إي عقد في ملف XML , عندها سينتج خطأ من تنفيذ هذا الإجراء ولحل ذلك نستخدم عبارة try:
قم بتعديل الكود السابق حتى يصبح هكذا :
void FillCombo()
{
try
{
doc.Load(Application.StartupPath + "//albumes.xml");
XmlNode alnd = doc["albumes"].FirstChild;
while (alnd != null)
{
ac.Items.Add(alnd.Name);
alnd = alnd.NextSibling;
}
}
catch
{
MessageBox.Show("حدث خطأ أثناء إسترجاع بيانات الألبومات");
}
}
بعد شرح إجراء FillCombo بقي أن نحدد مكانا مناسباً لإستدعاءه , وأفضل مكان لذلك هو عند تحميل النافذة
إذا إلى تصميم نافذة الألبومات وانقر مزدوجاً على مكان فارغ في النافذة لتذهب إلى كود تحميل النافذة albumes_Load
أضف إستدعاء إجراء FillCombo تحت إجراء FillView من الدرس السابق , حيث يصبح كود تحميل النافذة هكذا :
void AlbumesLoad(object sender, System.EventArgs e)
{
FillView();
FillCombo();
}
إجراء قراءة محتويات الألبوم ReadAlbume
سيقوم هذا الإجراء بقراءة محتويات ألبوم محدد من ملف XML وتخزينها في قائمة albume
ثم إستدعاء إجراء FillView لنسخ محتويات القائمة إلى كائن المستعرض lv
يحتوي هذا الإجراء على مدخل من نوع نص يمثل الألبوم المختار المراد تحميل ملفاته إلى كائن المستعرض
إنسخ الكود التالي إلى شفرة نافذة الألبومات وتأكد أنه خارج أي إجراء آخر:
void ReadAlbume(string albumename)
{
try
{
doc.Load(Application.StartupPath + "//albumes.xml");
XmlNode filend = doc["albumes"][albumename].FirstChild;
albume.Clear();
while (filend != null)
{
albume.Add(filend.InnerText);
filend = filend.NextSibling;
}
FillView();
}
catch
{
MessageBox.Show("حدث خطأ أثناء محاولة إسترجاع بيانات الألبومات");
}
}
السطر الأول من الكود يحتوي على إسم الإجراء وإسم المدخل ونوعة string
السطر الخامس لتحميل ملف XML إلى الكائن doc
السطر السادس عرفنا كائن من نوع عقدة يحمل أول عقدة من العقدة الفرعية التي إسمها هو المدخل والموجوده داخل العقدة الرئيسية albumes
لاحظ أنا وضعنا إسم المدخل في العقدة الفرعية فعند تشغيل البرنامج سيتم إستبدالة بقيمة المدخل كما سنرى لاحقاً
السطر السابق يقوم بتحديد عقدة الألبوم المدخل , مثلاً albume1 ثم أخذ أول عقدة منه file وتحميلها على الكائن filend
السطر السابع قمنا بتنظيف القائمة albume من أي عناصر موجودة فيها حتى ندخل إليها العناصر الجديدة من الملف
جملة while في السطر الثامن , تنفذ كود الدوارة ما دام filend لا يحمل القيمة null
السطر العاشر نقوم بإضافة بيانات العقدة إلى القائمة عن طريق الخاصية InnerText في العقدة
في السطر الحادي عشر نقوم بإختيار وتحميل العقدة التالية للعقدة الحالية , وهكذا حتى نصل لآخر عقدة ويتوقف تنفيذ كود الدوارة
في السطر الثالث عشر نقوم بإستدعاء إجراء نسخ القائمة albume إلى كائن المستعرض lv
بعد شرح هذا الإجراء بقي أن نختار المكان المناسب لإستدعائة
وأفضل مكان لذلك هو عندما يختار المستخدم إسم الألبوم من القائمة المنسدلة
إذهب إلى تصميم نافذة الألبومات وأنقر مزدوجاً على كائن القائمة المنسدلة
ستذهي إلى الشفرة , أكتب هناك إستدعاء الأجراء ReadAlbume
لا تنسى أن هذا الإجراء يتطلب مدخل من نوع نص يمثل الألبوم المختار
والألبوم المختار في هذه الحالة هو النص المكتوب على كائن القائمة المنسدلة Text
لذلك فإستدعاء الإجراء سيكون هكذا :
ReadAlbume(ac.Text);
ويصبح كود الإجراء كاملاً - إختيار إسم الألبوم من القائمة - هكذا :
void AcSelectedIndexChanged(object sender, System.EventArgs e)
{
ReadAlbume(ac.Text);
}
حيث أنه عند تشغيل البرنامج وإستدعاء الإجرء سيتم تغيير albumename في الإجراء إلى قيمة ac.Text
إجراء حذف الألبوم DeleteAlbume
يقوم هذا الإجراء بحذف بيانات الألبوم المختار من ملف XML
حيث يتطلب مدخل واحد من نوع نص , يمثل إسم الألبوم المراد حذفة
انسخ الكود التالي إلى شفرة نافذة الألبومات وتأكد من أنه خارج أي إجراء آخر :
void DeleteAlbume(string albumename)
{
try
{
if (MessageBox.Show("هل أنت متأكد من حذف / تعديل الألبوم ؟", "هل أنت متأكد", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
doc.Load(Application.StartupPath + "//albumes.xml");
doc["albumes"].RemoveChild(doc["albumes"][albumename]);
doc.Save(Application.StartupPath + "//albumes.xml");
ac.Items.RemoveAt(ac.SelectedIndex);
lv.Items.Clear();
}
}
catch
{
}
}
السطر الأول يحتوي على إسم الإجراء وإسم المدخل ونوعه string
السطر الخامس جملة if تقوم بإظهار رسالة تحذير للمستخدم بحيث يتم تأكيد الحذف , لاحظ عبارة إستدعاء الدالة :
MessageBox.Show("هل أنت متأكد من حذف / تعديل الألبوم ؟", "هل أنت متأكد", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
العبارة إختلفة عن ما كنا نعرفه من قبل , ورغم أنها نفس التعليمة إلا أنها هذه المرة إستقبلت مدخلات أكثر
لذلك وظيفتها هذه المرة مختلفة قليلاً , المدخل الأول هو نص الرسالة كما عرفنا سابقاً
المدخل الثاني هو عنوان الرسالة الذي سيظهر في شريك العنوان
المدخل الثالث MessageBoxButtons.YesNo هو الأزرار المطلوب إظهارها في الرسالة حيث إخترنا YesNo
وهناك أيضاً OkCancel و هناك مجموعات أخرى من الأزرار
المدخل الرابع MessageBoxIcon.Question يمثل الأيقونه المراد إظهارها في الرسالة حيث إخترنا أيقونة السؤال Question
المدخل الخامس MessageBoxDefaultButton.Button2 يمثل الزر الإفتراضي , أي الزر الذي يكون التركيز عليه عند ظهور الرسالة
وقد إخترنا Button2 والذي سيكون في هذه الحالة زر No حيث سيكون الجواب الإفتراضي للرسالة هو No
وقد إخترنا No بدلا من Yes حتى يتأكد المستخدم من إختيارة قبل أن نحذف بيانات الألبوم
وإذا كانت نتيجة هذه الرسالة هي الموافقة DialogResult.Yes سيتم تنفيذ كود الحذف وإلا فلا
في السطر السابع تعليمة تحميل الملف لكائن doc
وفي السطر الثامن تعلمية إزالة عقدة الألبوم , حيث يتم إزالة عقدة بتحديد عقدتها الرئيسية ثم إستدعاء الإجراء RemoveChild
والعقدة الرئيسية لعقد الألبومات هي albumes لذلك تم إستدعاء إجراء الحذف منها
داخل قوسي إجراء الحذف العقدة المراد حذفها , وهي العقدة الذي إسمها هو المدخل albumename
الموجودة داخل العقدة الرئيسية albumes
في السطر التاسع تعليمة حفظ التغييرات على ملف XML بإستدعاء الإجراء Save من كائن doc
في السطر العاشر تعليمة حذف إسم الألبوم المحذوف من القائمة المنسدلة
وفي السطر الحادي عشر تعليمة تنظيف كائن المستعرض lv من ملفات الألبوم المحذوف
المكان المناسب لإستدعاء هذا الإجراء هو كود الزر "حذف الألبوم"
إذهب إلى تصميم نافذة الألبومات وانقر مزدوجاً على زر "حذف الألبوم" وأكتب إستدعاء إجراء الحذف هناك :
DeleteAlbume(ac.Text);
إجراء حفظ الألبوم WriteAlbume
هذا الإجراء سيقوم بتخزين محتويات كائن المستعرض lv إلى ملف XML
حيث يقوم الإجراء أولاً بإنشاء عقدة الألبوم , وتسميتها بالنص المكتوب على القائمة المنسدلة
ثم يقوم بإنشاء العقد الفرعية file والتي تحتوي على مسارات الملفات الموجودة في كائن المستعرض
وأيضاً يقوم الإجراء بحفظ التغيرات على ألبوم موجود أساساً , بحيث يقوم بحذفة أولاً من الملف ثم تخزين ألبوم جديد بنفس الإسم وبالبيانات المعدلة
إنسخ الكود التالي إلى شفرة نافذة الألبومات وتأكد من أنه خراج إلى إجراء آخر :
void WriteAlbume(string albumename)
{
try
{
doc.Load(Application.StartupPath + "//albumes.xml");
if (doc["albumes"][albumename]!=null)
{
doc["albumes"].RemoveChild(doc["albumes"][albumename]);
}
else
{
ac.Items.Add(ac.Text);
}
XmlNode albumend = doc.CreateElement(albumename);
for (int i = 0; i < albume.Count; i++)
{
XmlNode filend = doc.CreateElement("file");
XmlNode path = doc.CreateTextNode(albume[i]);
filend.AppendChild(path);
albumend.AppendChild(filend);
}
doc["albumes"].AppendChild(albumend);
doc.Save(Application.StartupPath + "//albumes.xml");
}
catch
{
MessageBox.Show("حدث خطأ أثناء محاولة حفظ بيانات الألبومات");
}
}
السطر الأول يحتوي على إسم الإجراء وإسم المدخل و نوعة string
السطر الخامس تعليمة تحميل الملف إلى كائن doc
السطر السادس عبارة if تختبر هل هناك عقدة للألبوم المحدد في ملف XML
فإذا كانت العقدة موجودة فالسطر الثامن يقوم بحذفها , حتى توضع بدلاً منها العقدة بالبيانات المعدلة
والحذف هنا هو للبيانات القديمة وخزن البيانات الجديدة كأنها إلبوم جديد بنفس الإسم
أما اذا لم يكن الألبوم موجود في الملف فإن كود الحذف لن يفعل شيئاً
لأنه ألوم جديد وبالتالي يضاف إسم هذا الألبوم إلى القائمة المنسدلة في السطر الثاني عشر
السطر الرابع عشر عرفنا متغير من نوع عقدة إسمه albumend وأسندنا له عقدة جديدة بعد إستدعاء تعليمة إنشاء العقدة
doc.CreateElement(albumename);
حيث يقوم الكود السابق بإنشاء عقدة جديدة في الملف إسمها هو المدخل albumename وهو إسم الألبوم المراد حفظه
السطر الخامس عشر عبارة for من الصفر إلى عدد عناصر القائمة albume لإنشاء عقد جديدة لكافة عناصرها
السطر السابع عشر عرفنا متغير من نوع عقدة إسمه filend حيث سيقوم بحمل عقدة جديدة إسمها file بعد إستدعاء تعليمة إنشاء العقدة
doc.CreateElement("file");
لاحظ لحد الآن أن لدينا عقدتين , العقدة albumend التي تحمل إسم الألبوم , والعقدة filend التي تحمل إسم file
بقي أن ندخل البيانات إلى العقدة file
السطر الثامن عشر عرفنا متغير من نوع عقدة وحملناه قيمة نصية من خلال إستدعاء إجراء إنشاء عقدة نصية
doc.CreateTextNode(albume[i]);
حيث يستقبل هذه الإجراء مدخل من نوع نص وهو البيانات المراد خزنها في العقدة , وهي العنصر الذي ترتيبة i من القائمة albume
الآن أصبح لدينا ثلاث عقد عقدة albumend التي تحمل إسم الألبوم , والعقدة filend التي تحمل إسم file وعقدة path التي تحمل مسار الملف من عنصر القائمة albume
إلى الآن لم يتم ربط العقد ببعضها البعض فهي إلى حد الآن عقد مستقلة ومنفصلة
يتم ربط عقدة فرعية بعقدة رئيسية من خلال إستدعاء الإجراء AppendChild من العقدة الرئيسية
وتمرير العقدة الفرعية كمدخل لهذا الإجراء , حيث في السطر التاسع عشر ربطنا العقدة path بعقدة filend
وأصبحت العقدة file تحتوي على بيانات , ثم في السطر العشرين ربطنا العقدة filend بما فيها بالعقدة albumend
وبتكرار العملية لكافة عناصر القائمة albume ستنتج لنا عقدة رئيسية إسمها بإسم المدخل albumename
تحتوي على عدة عقدة فرعية file تحتوي على مسارات الملفات في الألبوم
لاحظ أن عقدة الألبوم حتى الآن لم ترتبط بعقدة رئيسية , بل ربطناها بعقد فرعية فقط
في السطر التانب والعشرين ربطنا العقدة albumend بالعقدة الرئيسية في الملف albumes
وبهذا أصبح لدينا جميع العقد متصلة ومترابطة مع بعض ولم يبقى سوى حفظ التغيرات إلى الملف في السطر الثالث والعشرين
بقي أن نحدد مكان إستدعاء هذا الإجراء , إذهب إلى تصميم نافذة الأبومات وأنقر مزدوجاً على زر "حفظ الألبوم"
ستنتقل إلى الشفرة , أكتب هذا :
WriteAlbume(ac.Text);
بقي لدينا زر واحد وهو زر "البوم جديد" , إذهب إلى تصميم نافذة الألبومات وانقر مزوجاً على الزر "ألبوم جديد"
وأكتب داخلة هذه التعليمات :
lv.Items.Clear();
albume.Clear();
ac.Text = "";
في السطر الأول قمنا بتنظيف كائن المستعرض من أي ملفات موجودة مسبقاً
وفي السطر الثاني قمنا بتنظيف القائمة albume من أي عناصر موجودة مسبقاً
وفي السطر الثالث قمنا بتصفير النص المكتوب على القائمة المنسدلة , بحيث اصبح كل شيئ جاهز لإنشاء ألبوم جديد
شغل البرنامج الآن وقم بتجريب حفظ ألبوم و إسترجاع بياناته
ملاحظة: عند أنشاء ألبوم جديد تأكد من أن إسم الألبوم لا يحتوي على فراغات أو رموز غريبة
لأن أسماء العقد يجب أن لا تحتوي على فراغات أو رموز غريبة وإلا ظهرت رسالة الخطأ .
الواجب
أرسل التطبيق
.نهاية الدرس الحادي عشر.
..
دوارة While
في الدرس الرابع تعرفنا على هيكل من هياكل التكرار في لغة C# وهو دوارة for
والحقيقة أن هناك هياكل أخرى من هياكل التكرار أهمها هي دوارة While
وهي تشبة إلى حد كبير دوارة for بإختلاف أنها لا تحتوي على عداد Counter كما كنا نعرف i في دوارة for
والهيكل الأساسي لدوارة While يشبة إلى حد كبير هيكل for بإختلاف أشياء بسيطة :
while (شرط التكرار)
{
كود الدوارة
}
تقوم جملة while بتكرار كود الدوارة ما دام شرط التكرار متحققاً , مثلاً :
int n=0;
while (n<5)
{
MessageBox.Show("من داخل الدوارة ");
n++;
}
الدوارة السابقة تقوم بإظهار الرسالة خمس مرات
حيث عرفنا متغير من نوع رقم n وأسندنا له قيمة إبتدائية 0
وشرط التكرار في الدوارة هو أن تكون قيمة المتغير n أصغر من 5
في المرة الأولى ستكون قيمة n هي صفر , وبالتالي فشرط التكرار متحقق , لأن الصفر أقل من 5
يتم تنفيذ كود إظهار الرسالة , والكود n++ يعني إضافة واحد إلى قيمة n أي أن n سيحمل الآن القيمة 1
يعود المعالج لبداية جملة while ويختبر شرط التكرار مرة أخرى ثم ينفذ كود إظهار الرسالة ويزيد واحد لقيمة n
وهكذا حتى تصبح قيمة n=5 عندها لن يتحقق شرط التكرار لأن 5 لسيت أقل من 5
وبالتالي يقفز المعالج إلى نهاية كود الدوارة ويواصل تنفيذ التعليمات بعدها
يستخدم هذا النوع من الدوارات حين لا نعرف كم بالضبط سنكرر كود الدوارة
وسنستخدمها في درس اليوم حيث لدينا معلومات الألبوم ولا نعرف عدد الملفات في الألبوم كما سنشرح بالتفصيل لا حقا
ملفات XML
من اهم أنظمة الحاسوب التي استفادة منها الإنسانية منذ ظهور الحاسوب هي أنظمة قواعد البيانات
وأنظمة قواعد البيانات هي برمجيات تستخدم مع لغات البرمجة بغرض خزن وإسترجاع أنواع متعددة من البيانات
ويتم خزن هذه البيانات بطرق مرتبة ومنهجية بحيث يسهل إسترجاع بيانات محددة مهما كبير كان حجم البيانات
حيث يتم ترتيب البيانات في وحدات متجانسة تسمى جداول Tables والتي تحتوي على حقول Fields لكل حقل نوع محدد من البيانات
ويمكن للجدول الواحد أن يحتوي على عدة حقول من أنواع بيانات مختلفة
قد ترتبط الجداول مع بعضها بواسطة علاقات Relationships حيث تعتمد بيانات من جدول على بيانات من جدول آخر
أنظمة قواعد البيانات تقسم إلى قسمين , نظام الخزن , ونظام المعالجة
أما نظام الخزن فهو المسئول عن خزن البيانات في ملفاتها المحددة بغض النظر عن ترتيبها أو أماكنها
ونظام المعالجة هو المسئول عن تحديد أماكن البيانات الصحيحة و إسترجاعها والقيام بالعمليات عليها
النظام الأول -نظام الخزن- يتكفل به نظام التشغيل ولا يحتاج لبرمجيات أو برامج خاصة
أما النظام الثاني فيتطلب برمجيات محددة لنظام قواعد البيانات
معظم أنظمة قواعد البيانات تستخدم النظام الثاني , مثل قواعد الأكسس و الأوراكل و غيرها
هناك أنواع أخرى لا تتطلب برمجيات مخصصة للتعامل معها ومنها نظام قواعد البيانات عبر ملفات XML
وهذا هو محور درسنا اليوم , حيث لا يحتاج هذا النظام لبرمجيات متخصصة للتعامل معه
وإنما ملفاته عبارة عن ملفات نصية يمكن فتحها وتعديلها بأي محرر نصوص
وسنستخدم ملفات XML في تطبيقنا لخزن بيانات الألبومات أو قوائم التشغيل
صيغة هذه الملفات النصية تشبة إلى حد كبير صيغة ملفات HTML
حيث يعتمد على وسوم Tags ترتب البيانات في هياكل مترابطة
وكل جزء من البيانات يحتوي على وسم بداية ووسم نهاية وله إسم محدد
فمثلاً هذا الكود :
<msg>رسالة</msg>
هذا جزء من كود ملف XML حيث يحتوي على جزء لخزن البيانات إسمه msg
يحتوي هذا الجزء على بيانات مخزنة هو كلمة "رسالة" لاحظ أن الجزء يحتوي على وسمين
وسم البداية حيث يحتوي على إسم الجزء بين علامتي أصغر وأكبر من
ووسم النهاية وهو مشابه تماما لوسم البداية بزيادة الشرطة المائلة / قبل إسم الجزء في وسم النهاية
وبين الوسمين توجد البيانات
وتسمى الأجزاء في ملفات XML بالعقد Nodes فالكود السابق يحتوي على عقدة إسمها msg
سميت بالعقد لأنه يمكن لأي جزء من البيانات أن يحتوي على أجزاء أخرى :
<albumes>
<albume1>
</albume1>
</albumes>
الكود السابق يحتوي على عقدة رئيسية إسمها albumes تحتوي بدورها على عقدة فرعية إسمها albume1
يمكن أن تحتوي العقدة على عدة عقد فرعية :
<albumes>
<albume1>
</albume1>
<albume2>
</albume2>
</albumes>
لعقدة الرئيسية albumes تحتوي على عقدتين فرعيتين albume1 و albume2
يمكن أيضاً للعقدة الفرعية أن تحتوي على عقد فرعية أخرى:
<albumes>
<albume1>
<file>sound.mp3</file>
<file>wave.rm</file>
</albume1>
<albume2>
<file>real.wav</file>
</albume2>
</albumes>
العقدة الرئيسية albumes تحتوي على عقدتين فرعيتين albume1 و albume2
العقدة الفرعية albume1 تحتوي على عقدتين فرعيتين بنفس الإسم file
كل عقدة من عقدتي file بيانات نصية sound.mp3 و wave.rm
والعقدة الفرعية albume2 تحتوي على عقدة فرعية file
الكود السابق يمثل ملف XML يحتوي على بيانات مرتبة في عقد , ولكن ينقصة شيئ مهم
نوع التكويد في المف , ورقم إصدار كود XML , والتكويد هو أسلوب خزن البيانات النصية في الملف
عادة ما نستخدم تكويد UTF-8 , وسطر نوع التكويد يجب أن يكون في بداية الملف:
<?xml version="1.0" encoding="utf-8"?>
<albumes>
<albume1>
<file>sound.mp3</file>
<file>wave.rm</file>
</albume1>
<albume2>
<file>real.wav</file>
</albume2>
</albumes>
هذا السطر لا يتغير في معظم ملفات XML
هذا هو هيكل الملف الذي سيقوم بخزن بيانات الألبومات وقوائم التشغيل
يتم التعامل مع ملف XML في البرنامج من خلال كائن XmlDocument الموجود في فضاء الأسماء System.XML:
XmlDocument doc = new XmlDocument();
الكود السابق عرفنا من خلالة كائن إسمه doc من نوع XmlDocument
الكائن doc يقوم بتحميل المف عن طريق الإجراء Load
doc.Load("c://albumes.xml");
الكود السابق يقوم بتحميل الملف albumes.xml الموجود في القرص c إلى الكائن doc
يتم الوصول إلى العقد الموجوده في المف عن طريق ذكر إسم العقدة الرئيسية متبوعة بقوسين مربعين يحتويان إسم العقدة الفرعية
أما إذا أردنا الوصول إلى العقد الرئيسية المسماه albumes فنكتب إسم الكائن doc متبوعاً بقوسين مربعين يحتويان إسم العقدة :
doc["albumes"];
ويتم الوصول إلى البيانات في العقدة بواسطة الخاصية InnerText :
MessageBox.Show(doc["albumes"].InnerText);
الكود السابق يقوم بإظهار رسالة تحتوي على البيانات المخزنة في العقدة albumes
ويتم الوصول لإسم العقدة عن طريق الخاصية :Name
MessageBox.Show(doc["albumes"].Name);
الكود السابق يظهر رسالة تحتوي على إسم العقدة albumes
ويتم الوصول إلى العقد الفرعية بإضافة قوسين مربعين يحتويان إسم العقدة
فمثلاً للوصول إلى العقدة الفرعية albume1 الموجود في العقدة albumes :
doc["albumes"]["albume1"]
وللوصول إلى العقدة الأعمق file :
doc["albumes"]["albume1"]["file"]
التطبيق
افتح تطبيق الدرس السابق , من نافذة مستعرض المشروع, أنقر بالزر الأيمن على إسم المشروع
ومن القائمة الناتجة إختر Add ثم New Item :
http://absba7.absba.org/teamwork8/455943/89.jpg
ستظهر نافذة إضافة ملف جديدة للمشروع , من القائمة في اليسار إختر misc
ثم إختر Empty XML file , وفي صندوق إسم الملف أكتب الإسم التالي albumes.xml , وإختر OK
http://absba7.absba.org/teamwork8/455943/90.jpg
إذهب إلى مجلد المشروع وأنسخ الملف albumes.xml إلى مجلد Debug الموجود داخل مجلد bin
حيث يصبح الملف موجود بجانب ملفات المشروع الأخرى
الآن قم بفتح تصميم نافذة الألبومات وسحب ثلاثة أزرار إلى النافذة وغير الأسماء فيها إلى
ألبوم جديد
حفظ الألبوم
حذف الألبوم
ومن صندوق الأدوات إسحب كائن القائمة المنسدلة إلى نافذة الالبومات :
http://absba7.absba.org/teamwork8/455943/91.jpg
إختر كائن القائمة المنسدلة و من جدول الخصائص , غير الخاصية (Name) , إلى ac
وغير الخاصية Text إلى "إختر الألبوم"
قم بترتيب الأدوات في النافذة حتى تصبح هكذا :
http://absba7.absba.org/teamwork8/455943/92.jpg
جميع الدوال التي سنستخدمها للتعامل مع ملف XML موجوده في فضاء الأسماء XML الموجود داخل الفضاء System
لذلك يجب إضافة عبارة using لتعريف جميع دوال وكائنات التعامل مع ملفات XML
إذهب إلى شفرة نافذة الألبومات و أكتب السطر التالي , تحت جمل using في رأس الملف:
http://absba7.absba.org/teamwork8/455943/93.jpg
يتم تحميل ملف XML إلى البرنامج والتعامل معه من خلال كائن XmlDocument
حيث سنعرف كائن عام من هذا النوع ليتم التعامل معه في جميع أنحاء نافذة الألبومات
إنسخ كود التعريف تحت تعريف قائمة albume من الدرس السابق :
http://absba7.absba.org/teamwork8/455943/94.jpg
قمنا هنا بتعريف كائن إسمه doc من نوع XmlDocument , ولأنه كائن إستخدمنا الكلمة new
إجراء تحميل الألبومات للقائمة المنسدلة FillCombo
يقوم هذا الإجراء بتحميل أسماء الألبومات الموجوده في ملف XML إلى القائمة المنسدلة ac
قم بنسخ الكود التالي إلى شفرة نافذة الألبومات وتأكد أنه خارج أي إجراء آخر :
void FillCombo()
{
doc.Load(Application.StartupPath + "//albumes.xml");
XmlNode alnd = doc["albumes"].FirstChild;
while (alnd != null)
{
ac.Items.Add(alnd.Name);
alnd = alnd.NextSibling;
}
}
السطر الأول يقوم بتحميل الملف إلى الكائن doc
والتعليمة Application.StartupPath تعيد قيمة نصية تمثل مسار ملف exe للتطبيق
حيث إستفدنا من هذه التعليمة لمعرفة مسار ملف XML وأضفنا إسم الملف للمسار
في السطر الثاني قمنا بتعريف كائن من نوع عقدة XmlNode إسمه alnd
ثم حملنا هذا الكائن أول عقدة فرعية داخل العقدة الرئيسية albumes من خلال الخاصية FirstChild
السطر الثالث يمثل جملة while تنفذ كود الدوارة ما دامت العقدة alnd تحمل قيمة
الشرط alnd!=null يختبر الكائن alnd فإذا كان يحمل قيمة غير القيمة الفارغة null فسيتم تنفيذ كود الدوارة
أما إذا كان الكائن alnd لا يحمل قيمة أي أنه يحمل null فعندها لن يتم تنفيذ كود الدوارة
السطر الخامس يقوم بإضافة إسم العقدة alnd إلى القائمة المنسدلة ac
السطر السادس يقوم بإختيار العقدة التالية للعقدة alnd حيث يحمل الكائن alnd العقد التالية لما كان يحمله
يتم تكرار السطرين السابقين حتى الوصول إلى آخر عقدة عندها سيحمل الكائن alnd القيمة null لأنه لا يوجد عقدة تالية للعقدة الأخيرة
وبالتالي ينتهي تكرار جملة while
لكن ماذا لو لم يكن هناك إي عقد في ملف XML , عندها سينتج خطأ من تنفيذ هذا الإجراء ولحل ذلك نستخدم عبارة try:
قم بتعديل الكود السابق حتى يصبح هكذا :
void FillCombo()
{
try
{
doc.Load(Application.StartupPath + "//albumes.xml");
XmlNode alnd = doc["albumes"].FirstChild;
while (alnd != null)
{
ac.Items.Add(alnd.Name);
alnd = alnd.NextSibling;
}
}
catch
{
MessageBox.Show("حدث خطأ أثناء إسترجاع بيانات الألبومات");
}
}
بعد شرح إجراء FillCombo بقي أن نحدد مكانا مناسباً لإستدعاءه , وأفضل مكان لذلك هو عند تحميل النافذة
إذا إلى تصميم نافذة الألبومات وانقر مزدوجاً على مكان فارغ في النافذة لتذهب إلى كود تحميل النافذة albumes_Load
أضف إستدعاء إجراء FillCombo تحت إجراء FillView من الدرس السابق , حيث يصبح كود تحميل النافذة هكذا :
void AlbumesLoad(object sender, System.EventArgs e)
{
FillView();
FillCombo();
}
إجراء قراءة محتويات الألبوم ReadAlbume
سيقوم هذا الإجراء بقراءة محتويات ألبوم محدد من ملف XML وتخزينها في قائمة albume
ثم إستدعاء إجراء FillView لنسخ محتويات القائمة إلى كائن المستعرض lv
يحتوي هذا الإجراء على مدخل من نوع نص يمثل الألبوم المختار المراد تحميل ملفاته إلى كائن المستعرض
إنسخ الكود التالي إلى شفرة نافذة الألبومات وتأكد أنه خارج أي إجراء آخر:
void ReadAlbume(string albumename)
{
try
{
doc.Load(Application.StartupPath + "//albumes.xml");
XmlNode filend = doc["albumes"][albumename].FirstChild;
albume.Clear();
while (filend != null)
{
albume.Add(filend.InnerText);
filend = filend.NextSibling;
}
FillView();
}
catch
{
MessageBox.Show("حدث خطأ أثناء محاولة إسترجاع بيانات الألبومات");
}
}
السطر الأول من الكود يحتوي على إسم الإجراء وإسم المدخل ونوعة string
السطر الخامس لتحميل ملف XML إلى الكائن doc
السطر السادس عرفنا كائن من نوع عقدة يحمل أول عقدة من العقدة الفرعية التي إسمها هو المدخل والموجوده داخل العقدة الرئيسية albumes
لاحظ أنا وضعنا إسم المدخل في العقدة الفرعية فعند تشغيل البرنامج سيتم إستبدالة بقيمة المدخل كما سنرى لاحقاً
السطر السابق يقوم بتحديد عقدة الألبوم المدخل , مثلاً albume1 ثم أخذ أول عقدة منه file وتحميلها على الكائن filend
السطر السابع قمنا بتنظيف القائمة albume من أي عناصر موجودة فيها حتى ندخل إليها العناصر الجديدة من الملف
جملة while في السطر الثامن , تنفذ كود الدوارة ما دام filend لا يحمل القيمة null
السطر العاشر نقوم بإضافة بيانات العقدة إلى القائمة عن طريق الخاصية InnerText في العقدة
في السطر الحادي عشر نقوم بإختيار وتحميل العقدة التالية للعقدة الحالية , وهكذا حتى نصل لآخر عقدة ويتوقف تنفيذ كود الدوارة
في السطر الثالث عشر نقوم بإستدعاء إجراء نسخ القائمة albume إلى كائن المستعرض lv
بعد شرح هذا الإجراء بقي أن نختار المكان المناسب لإستدعائة
وأفضل مكان لذلك هو عندما يختار المستخدم إسم الألبوم من القائمة المنسدلة
إذهب إلى تصميم نافذة الألبومات وأنقر مزدوجاً على كائن القائمة المنسدلة
ستذهي إلى الشفرة , أكتب هناك إستدعاء الأجراء ReadAlbume
لا تنسى أن هذا الإجراء يتطلب مدخل من نوع نص يمثل الألبوم المختار
والألبوم المختار في هذه الحالة هو النص المكتوب على كائن القائمة المنسدلة Text
لذلك فإستدعاء الإجراء سيكون هكذا :
ReadAlbume(ac.Text);
ويصبح كود الإجراء كاملاً - إختيار إسم الألبوم من القائمة - هكذا :
void AcSelectedIndexChanged(object sender, System.EventArgs e)
{
ReadAlbume(ac.Text);
}
حيث أنه عند تشغيل البرنامج وإستدعاء الإجرء سيتم تغيير albumename في الإجراء إلى قيمة ac.Text
إجراء حذف الألبوم DeleteAlbume
يقوم هذا الإجراء بحذف بيانات الألبوم المختار من ملف XML
حيث يتطلب مدخل واحد من نوع نص , يمثل إسم الألبوم المراد حذفة
انسخ الكود التالي إلى شفرة نافذة الألبومات وتأكد من أنه خارج أي إجراء آخر :
void DeleteAlbume(string albumename)
{
try
{
if (MessageBox.Show("هل أنت متأكد من حذف / تعديل الألبوم ؟", "هل أنت متأكد", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
doc.Load(Application.StartupPath + "//albumes.xml");
doc["albumes"].RemoveChild(doc["albumes"][albumename]);
doc.Save(Application.StartupPath + "//albumes.xml");
ac.Items.RemoveAt(ac.SelectedIndex);
lv.Items.Clear();
}
}
catch
{
}
}
السطر الأول يحتوي على إسم الإجراء وإسم المدخل ونوعه string
السطر الخامس جملة if تقوم بإظهار رسالة تحذير للمستخدم بحيث يتم تأكيد الحذف , لاحظ عبارة إستدعاء الدالة :
MessageBox.Show("هل أنت متأكد من حذف / تعديل الألبوم ؟", "هل أنت متأكد", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
العبارة إختلفة عن ما كنا نعرفه من قبل , ورغم أنها نفس التعليمة إلا أنها هذه المرة إستقبلت مدخلات أكثر
لذلك وظيفتها هذه المرة مختلفة قليلاً , المدخل الأول هو نص الرسالة كما عرفنا سابقاً
المدخل الثاني هو عنوان الرسالة الذي سيظهر في شريك العنوان
المدخل الثالث MessageBoxButtons.YesNo هو الأزرار المطلوب إظهارها في الرسالة حيث إخترنا YesNo
وهناك أيضاً OkCancel و هناك مجموعات أخرى من الأزرار
المدخل الرابع MessageBoxIcon.Question يمثل الأيقونه المراد إظهارها في الرسالة حيث إخترنا أيقونة السؤال Question
المدخل الخامس MessageBoxDefaultButton.Button2 يمثل الزر الإفتراضي , أي الزر الذي يكون التركيز عليه عند ظهور الرسالة
وقد إخترنا Button2 والذي سيكون في هذه الحالة زر No حيث سيكون الجواب الإفتراضي للرسالة هو No
وقد إخترنا No بدلا من Yes حتى يتأكد المستخدم من إختيارة قبل أن نحذف بيانات الألبوم
وإذا كانت نتيجة هذه الرسالة هي الموافقة DialogResult.Yes سيتم تنفيذ كود الحذف وإلا فلا
في السطر السابع تعليمة تحميل الملف لكائن doc
وفي السطر الثامن تعلمية إزالة عقدة الألبوم , حيث يتم إزالة عقدة بتحديد عقدتها الرئيسية ثم إستدعاء الإجراء RemoveChild
والعقدة الرئيسية لعقد الألبومات هي albumes لذلك تم إستدعاء إجراء الحذف منها
داخل قوسي إجراء الحذف العقدة المراد حذفها , وهي العقدة الذي إسمها هو المدخل albumename
الموجودة داخل العقدة الرئيسية albumes
في السطر التاسع تعليمة حفظ التغييرات على ملف XML بإستدعاء الإجراء Save من كائن doc
في السطر العاشر تعليمة حذف إسم الألبوم المحذوف من القائمة المنسدلة
وفي السطر الحادي عشر تعليمة تنظيف كائن المستعرض lv من ملفات الألبوم المحذوف
المكان المناسب لإستدعاء هذا الإجراء هو كود الزر "حذف الألبوم"
إذهب إلى تصميم نافذة الألبومات وانقر مزدوجاً على زر "حذف الألبوم" وأكتب إستدعاء إجراء الحذف هناك :
DeleteAlbume(ac.Text);
إجراء حفظ الألبوم WriteAlbume
هذا الإجراء سيقوم بتخزين محتويات كائن المستعرض lv إلى ملف XML
حيث يقوم الإجراء أولاً بإنشاء عقدة الألبوم , وتسميتها بالنص المكتوب على القائمة المنسدلة
ثم يقوم بإنشاء العقد الفرعية file والتي تحتوي على مسارات الملفات الموجودة في كائن المستعرض
وأيضاً يقوم الإجراء بحفظ التغيرات على ألبوم موجود أساساً , بحيث يقوم بحذفة أولاً من الملف ثم تخزين ألبوم جديد بنفس الإسم وبالبيانات المعدلة
إنسخ الكود التالي إلى شفرة نافذة الألبومات وتأكد من أنه خراج إلى إجراء آخر :
void WriteAlbume(string albumename)
{
try
{
doc.Load(Application.StartupPath + "//albumes.xml");
if (doc["albumes"][albumename]!=null)
{
doc["albumes"].RemoveChild(doc["albumes"][albumename]);
}
else
{
ac.Items.Add(ac.Text);
}
XmlNode albumend = doc.CreateElement(albumename);
for (int i = 0; i < albume.Count; i++)
{
XmlNode filend = doc.CreateElement("file");
XmlNode path = doc.CreateTextNode(albume[i]);
filend.AppendChild(path);
albumend.AppendChild(filend);
}
doc["albumes"].AppendChild(albumend);
doc.Save(Application.StartupPath + "//albumes.xml");
}
catch
{
MessageBox.Show("حدث خطأ أثناء محاولة حفظ بيانات الألبومات");
}
}
السطر الأول يحتوي على إسم الإجراء وإسم المدخل و نوعة string
السطر الخامس تعليمة تحميل الملف إلى كائن doc
السطر السادس عبارة if تختبر هل هناك عقدة للألبوم المحدد في ملف XML
فإذا كانت العقدة موجودة فالسطر الثامن يقوم بحذفها , حتى توضع بدلاً منها العقدة بالبيانات المعدلة
والحذف هنا هو للبيانات القديمة وخزن البيانات الجديدة كأنها إلبوم جديد بنفس الإسم
أما اذا لم يكن الألبوم موجود في الملف فإن كود الحذف لن يفعل شيئاً
لأنه ألوم جديد وبالتالي يضاف إسم هذا الألبوم إلى القائمة المنسدلة في السطر الثاني عشر
السطر الرابع عشر عرفنا متغير من نوع عقدة إسمه albumend وأسندنا له عقدة جديدة بعد إستدعاء تعليمة إنشاء العقدة
doc.CreateElement(albumename);
حيث يقوم الكود السابق بإنشاء عقدة جديدة في الملف إسمها هو المدخل albumename وهو إسم الألبوم المراد حفظه
السطر الخامس عشر عبارة for من الصفر إلى عدد عناصر القائمة albume لإنشاء عقد جديدة لكافة عناصرها
السطر السابع عشر عرفنا متغير من نوع عقدة إسمه filend حيث سيقوم بحمل عقدة جديدة إسمها file بعد إستدعاء تعليمة إنشاء العقدة
doc.CreateElement("file");
لاحظ لحد الآن أن لدينا عقدتين , العقدة albumend التي تحمل إسم الألبوم , والعقدة filend التي تحمل إسم file
بقي أن ندخل البيانات إلى العقدة file
السطر الثامن عشر عرفنا متغير من نوع عقدة وحملناه قيمة نصية من خلال إستدعاء إجراء إنشاء عقدة نصية
doc.CreateTextNode(albume[i]);
حيث يستقبل هذه الإجراء مدخل من نوع نص وهو البيانات المراد خزنها في العقدة , وهي العنصر الذي ترتيبة i من القائمة albume
الآن أصبح لدينا ثلاث عقد عقدة albumend التي تحمل إسم الألبوم , والعقدة filend التي تحمل إسم file وعقدة path التي تحمل مسار الملف من عنصر القائمة albume
إلى الآن لم يتم ربط العقد ببعضها البعض فهي إلى حد الآن عقد مستقلة ومنفصلة
يتم ربط عقدة فرعية بعقدة رئيسية من خلال إستدعاء الإجراء AppendChild من العقدة الرئيسية
وتمرير العقدة الفرعية كمدخل لهذا الإجراء , حيث في السطر التاسع عشر ربطنا العقدة path بعقدة filend
وأصبحت العقدة file تحتوي على بيانات , ثم في السطر العشرين ربطنا العقدة filend بما فيها بالعقدة albumend
وبتكرار العملية لكافة عناصر القائمة albume ستنتج لنا عقدة رئيسية إسمها بإسم المدخل albumename
تحتوي على عدة عقدة فرعية file تحتوي على مسارات الملفات في الألبوم
لاحظ أن عقدة الألبوم حتى الآن لم ترتبط بعقدة رئيسية , بل ربطناها بعقد فرعية فقط
في السطر التانب والعشرين ربطنا العقدة albumend بالعقدة الرئيسية في الملف albumes
وبهذا أصبح لدينا جميع العقد متصلة ومترابطة مع بعض ولم يبقى سوى حفظ التغيرات إلى الملف في السطر الثالث والعشرين
بقي أن نحدد مكان إستدعاء هذا الإجراء , إذهب إلى تصميم نافذة الأبومات وأنقر مزدوجاً على زر "حفظ الألبوم"
ستنتقل إلى الشفرة , أكتب هذا :
WriteAlbume(ac.Text);
بقي لدينا زر واحد وهو زر "البوم جديد" , إذهب إلى تصميم نافذة الألبومات وانقر مزوجاً على الزر "ألبوم جديد"
وأكتب داخلة هذه التعليمات :
lv.Items.Clear();
albume.Clear();
ac.Text = "";
في السطر الأول قمنا بتنظيف كائن المستعرض من أي ملفات موجودة مسبقاً
وفي السطر الثاني قمنا بتنظيف القائمة albume من أي عناصر موجودة مسبقاً
وفي السطر الثالث قمنا بتصفير النص المكتوب على القائمة المنسدلة , بحيث اصبح كل شيئ جاهز لإنشاء ألبوم جديد
شغل البرنامج الآن وقم بتجريب حفظ ألبوم و إسترجاع بياناته
ملاحظة: عند أنشاء ألبوم جديد تأكد من أن إسم الألبوم لا يحتوي على فراغات أو رموز غريبة
لأن أسماء العقد يجب أن لا تحتوي على فراغات أو رموز غريبة وإلا ظهرت رسالة الخطأ .
الواجب
أرسل التطبيق
.نهاية الدرس الحادي عشر.
..