س:
في DataGridView، هل
يمكن تغيير مصدر بيانات خانة في أحد الأعمدة، تبعا لقيمة خانة أخرى في عمود آخر في
نفس الصف؟.. مثال: إذا كان هناك عمود تعرض خاناته أسماء المحافظات، وبجوار عمود
تعرض خاناته أسماء المدن.. هل يمكن جعل خانة أسماء المدن تعرض فقط المدن الخاصة
بالمحافظة التي اختارها المستخدم في الخانة المجاورة لها؟
ج:
نعم، ممكن..
نحن
نتكلم هنا عن أعمدة من النوع DataGridViewComboBoxColumn، وهي تمتاز بأن خاناتها تعرض قائمة مركبة ComboBox في وضع التحرير Edit Mode، لكي يختار المستخدم منها قيمة معينة.. وفي الوضع العادي يتم ربط
العمود بمصدر بيانات باستخدام الخصائص:
-
DataGridViewComboBoxColumn.DataSource:
يوضع
فيها المجموعة Collection التي
تحتوي على البيانات التي ستعرضها القائمة المركبة، مثل جدول المحافظات، وجدول
المدن.
-
DataGridViewComboBoxColumn.DisplayMember:
يوضع
فيها اسم الخاصية التي ستعرض عناصر القائمة المركبة قيمتها للمستخدم.. مثلا: اسم
الخاصية "Name"
لعرض اسم المحافظة أو المدينة.
-
DataGridViewComboBoxColumn.ValueMember:
يوضع
فيها اسم الخاصية التي سيتم حفظ قيمتها في الخانة عندما يختار المستخدم عنصرا من
القائمة المركبة.. مثلا: اسم الخاصية "ID" لحفظ رقم المحافظة أو المدينة المحددة.
لكن
ماذا يفعل العمود بقيم هذه الخصائص؟
ما
يحدث فعليا هو أن العمود يضع قيم هذه الخصائص في كل خانة من خاناته.. هذه الخانات
من النوع DataGridViewComboBoxCell، وهي
أيضا تمتلك الخصائص DataSource و DisplayMember و ValueMember.. هذا معناه أنك
تستطيع تغيير مصدر بيانات كل خانة على حدة.. لكن ما يفعله العمود هو أنه يضع قيم
هذه الخصائص في الخانة التي تعيدها الخاصية DataGridViewComboBoxColumn.CellTemplate.. هذه الخانة تعمل كقالب افتراضي لكل الخانات الجديدة التي تضاف
في هذا العمود.. كما يقوم العمود بتغيير قيم هذه الخصائص في الخانات القديمة.
إذن،
كيف يمكن تغيير قائمة أسماء المدن، عند تغيير اسم المحافظة؟
يمكن
فعل هذا باستخدام الحدث GataGridView.CellValueChanged، الذي
ينطلق عند تغير قيمة أي خانة من خانات جدول العرض (لا يقع التغيير إلا بعد مغادرة
الخانة بالفعل).. في هذا الحدث سنفحص قيمة المعامل e.ColumnIndex
للتأكد أن الخانة التي تغيرت قيمتها تقع في العمود الخاص
بالمحافظات.. (وليكن رقم X):
If
e.ColumnIndex = X Then
…………………
End
If
فإن
كان هذا الشرط صحيحا، فسنتبع التالي:
- سنحصل على الصف الحالي
باستخدام رقم الصف e.RowIndex
كالتالي:
Dim
Row = DataGridView1.Rows(e.RowIndex)
- سنحصل على خانة اسم المحافظة باستخدام رقم العمود X كالتالي:
Dim
Cell = Row(e.RowIndex).Cells(X)
- سنعرف رقم المحافظة التي اختارها المستخدم باستخدام الخاصية Value للخانة (هذا بافتراض أنك جعلت الخاصية
ValueMember تشير إلى الخاصية ID في مصدر البيانات الذي يعرض المحافظات):
Dim
GovID = CType(Cell.Value, Integer)
- اكتب الكود المناسب للحصول أسماء مدن هذه المحافظة، تبعا للطريقة
التي تستخدمها في برنامجك لتمثيل قاعدة البيانات (ADO.NET أو LinQ To SQL أو Entity Framework).. افترض أن النتيجة العائدة هي مجموعة اسمها Cities.. نريد أن نستخدم هذه المجموعة كمصدر
بيانات الخانة المجاورة للخانة الحالية (رقم X + 1).
-
عرّف متغيرا لخانة أسماء المدن.. يجب تحويل نوع هذا المتغير
من نوع الخانة العامة DataGridViewCell إلى النوع المحدد DataGridViewComboBoxCell حتى يمكننا استخدام خصائص ربط البيانات الخاصة بهذا النوع من
الخانات:
Dim
CityCell As DataGridViewComboBoxCell = Row.Cells(X + 1)
CityCell.DataSource
= Cities
CityCell.DisplayMember
= "Name"
CityCell.ValueMember
= "ID"
بهذه
الطريقة كلما غير المستخدم اسم المحافظة في أي صف، ستعرض خانة اسم المدن قائمة
فيها أسماء مدن هذه المحافظة فقط.
ملحوظة:
يؤدي
ترتيب صفوف جدول العرض إلى ضياع قيم هذه خصائص ربط البيانات من كل خانة، لأن جدول
العرض يستخدم القالب CellTemplate لإعادة
رسم الخانات بعد عملية الترتيب (وكما ذكرت في مقال سابق، يؤدي هذا أيضا إلى ضياع
تنسيق الخانات وضياع أي بيانات غير مرتبطة بمصدر بيانات!).. وهذا سيجعل أسماء
المدن التي اختارها المستخدم تختفي من كل خانات العمود (رغم أن أرقام المدن ما
زالت محفوظة في الخانات، لكن لا يمكن عرض أسمائها بدون مصدر بيانات)!
لهذا
إما تمنع المستخدم من ترتيب الصفوف عند ضغط الأعمدة، وذلك بتغير قيمة الخاصية SortMode في كل عمود.. وإما أن تستخدم الحدث Sorted الذي ينطلق بعد تمام عملية الترتيب، لتمر
عبر كل صفوف الجدول، وتعيد وضع مصدر بيانات خانات المدن تبعا للمحافظات المحددة في
كل صف!
وهناك
حل ثالث، هو أن تجعل العمود يشير إلى مصدر بيانات يحتوي على كل أسماء المدن بغض
النظر عن المحافظات.. في هذه الحالة سيوضع هذا المصدر في قالب الخانة CellTemplate، وعند الترتيب
سيتم وضعه في كل خانات المدن، وبهذا ستظل أسماء المدن التي اختارها المستخدم
ظاهرة.. لكن لو ضغط المستخدم الخانة وعرض القائمة المركبة، فسيري فيها كل أسماء
المدن. لهذا عليك أن تستخدم الحدث DataGridView.CellEnter
الذي ينطلق عند دخول الخانة، لتعيد للخانة مصدر البيانات الصحيح
تبعا للمحافظة المحددة.
ليست هناك تعليقات:
إرسال تعليق
ملحوظة: يمكن لأعضاء المدونة فقط إرسال تعليق.