المتابعون للمدونة

الخميس، 31 أكتوبر 2013

تغيير لون خانة رئيسية في DataGridView؟


س: كيف يمكن تغيير لون خلفية الخانة الرئيسية Header Cell لأحد الأعمدة في الأداة DataGridView؟

 

ج: مبدئيا يجب أن تغير قيمة الخاصية DataGridView.EnableHeadersVisualStyles إلى False، لأن قيمتها لو كانت True فلن يكون هناك أي تأثير لو غيرت لون الخلفية في الخاصية ColumnHeadersDefaultCellStyle والخاصية RowHeadersDefaultCellStyle والخاصية Style الخاصة بالخانة الرئيسية للعمود أو الصف:

DataGridView1.EnableHeadersVisualStyles = False

بعد هذا، يمكنك أن تغير لون خلفية الخانة الرئيسية للعمود رقم X كالتالي:

DataGridView1.Columns(X).HeaderCell.Style.BackColor = Color.Red

ويمكنك تطبيق نفس الكلام على لون النص ForeColor.

 

 

الأداة DateTimePiker تعطي تاريخا مختلفا عن الذي تعرضه!


س: الأداة DateTimePiker تعرض تاريخا، لكن عند قراءة قيمة الخاصية Value تعيد تاريخا مختلفا!

 

ج: تحدث هذه المشكلة إذا لم تضع تاريخا محددا في الخاصية DateTimePiker.Value، ففي هذه الحالة تعرض الأداة التاريخ الحالي Now كما هو محدد في ساعة الجهاز، لكن الخاصية Value قد تعيد تاريخا مختلفا عن ذلك المعروض.. لهذا يجب عليك أن تضع تاريخا في الخاصية Value في وقت التصميم أو في حدث تحميل النموذج.. مثل:

DateTimePiker1.Value = Now

هذا يحل هذه المشكلة نهائيا.

 

الأربعاء، 30 أكتوبر 2013

تغيير مصدر بيانات خانة في DataGridView

س: في DataGridView، هل يمكن تغيير مصدر بيانات خانة في أحد الأعمدة، تبعا لقيمة خانة أخرى في عمود آخر في نفس الصف؟.. مثال: إذا كان هناك عمود تعرض خاناته أسماء المحافظات، وبجوار عمود تعرض خاناته أسماء المدن.. هل يمكن جعل خانة أسماء المدن تعرض فقط المدن الخاصة بالمحافظة التي اختارها المستخدم في الخانة المجاورة لها؟

 

ج: نعم، ممكن..

نحن نتكلم هنا عن أعمدة من النوع DataGridViewComboBoxColumn، وهي تمتاز بأن خاناتها تعرض قائمة مركبة ComboBox في وضع التحرير Edit Mode، لكي يختار المستخدم منها قيمة معينة.. وفي الوضع العادي يتم ربط العمود بمصدر بيانات باستخدام الخصائص:

- DataGridViewComboBoxColumn.DataSource:

يوضع فيها المجموعة Collection التي تحتوي على البيانات التي ستعرضها القائمة المركبة، مثل جدول المحافظات، وجدول المدن.

- DataGridViewComboBoxColumn.DisplayMember:

يوضع فيها اسم الخاصية التي ستعرض عناصر القائمة المركبة قيمتها للمستخدم.. مثلا: اسم الخاصية "Name" لعرض اسم المحافظة أو المدينة.

- DataGridViewComboBoxColumn.ValueMember:

يوضع فيها اسم الخاصية التي سيتم حفظ قيمتها في الخانة عندما يختار المستخدم عنصرا من القائمة المركبة.. مثلا: اسم الخاصية "ID" لحفظ رقم المحافظة أو المدينة المحددة.

 

لكن ماذا يفعل العمود بقيم هذه الخصائص؟

الثلاثاء، 29 أكتوبر 2013

الترتيب يمحو بعض خانات DataGridView


س: عند ضغط رأس العمود في DataGridView لترتيب صفوف جدول العرض، يتم محو قيم خانات بعض الأعمدة.. فما السبب وما الحل؟

 

ج: يؤدي ترتيب جدول العرض إلى إعادة إنعاش الصفوف. هذا يؤدي إلى ضياع قيم الخانات غير المرتبطة بمصدر بيانات Data Source بينما تقوم الخانات المرتبطة بمصدر البيانات بإعادة طلب القيم منه وعرضها مرة أخرى.. السبب في هذا هو أن جدول العرض مصمم لتوفير مساحة الذاكرة وتحسين الأداء، لهذا حينما يكون مرتبطا بمصدر بيانات أو يعمل في الوضع الافتراضي VirtualMode، فهو لا يملأ كل الخانات بالبيانات، ولكنه يرسم مجموعة من الخانات مناسبة لمساحة العرض، ويحضر القيم من مصدر البيانات كلما احتاج إلى إنعاش الخانات المعروضة (عند تحريك المنزلق لعرض خانات جديدة، أو عند ترتيب الصفوف، أو عند اختفاء النافذة وإعادة عرضها.. إلخ).. لكن المشكلة تحدث حينما تضيف بعض الأعمدة غير المرتبطة بمصدر بيانات، فعند ترتيب الصفوف تفقد خانات هذه الأعمدة قيمها.

ويمكنك حل هذه المشكلة بالتأكد من ربط جميع الأعمدة بمصدر البيانات.. طبعا من غير العملي إضافة أعمدة في قاعدة البيانات Database مقابلة لهذه الأعمدة، فالبيانات التي تعرضها في الغالب تكون بيانات مستنتجة أو محسوبة أو مجرد CheckBox يؤدي وظيفة معينة، أو ترقيم أو ما شابه، ومن العبث حفظ هذه البيانات في قاعدة البيانات على حساب زيادة حجمها بلا مقابل.. فما الحل إذن؟

الحل هو إضافة خاصية جديدة في الفئة التي تمثل مصدر البيانات (مثل فئات LinQ To SQL أو الفئات الخاصة بمجوعة البيانات محددة النوع Typed DataSet).. لا تفعل هذا في الملف المولّد تلقائيا Auto Generated (الذي ينتهي اسمه بالكلمة Designer.vb أو Designer.cs) لأن أي شيء تكتبه في هذا الملف سيكون عرضة للضياع.. ولكن اضغط بزر الفأرة الأيمن على اسم الفئة في مخطط محتوى البيانات DataContext أو مجموعة البيانات DataSet، واضغط الأمر View Code لعرض الملف الخاص بامتداد هذه الفئة Partial Class، وأضف إليه خاصية عامة Public Property لتربط بها العمود الخاص بك.

لاحظ أن هذه الخاصية لن تظهر ضمن خصائص الكائن في نافذة مصادر البيانات Data Sources ولن تستطيع اختيار اسمها في نافذة الخصائص من ضمن خصائص مصدر الربط BindingSource، لكن رغم هذا ما زلت تستطيع ربط العمود بها بوضع اسمها يدويا في الخاصية DataPropertyName الخاصة به (سواء في مصمم الأعمدة أو في الكود).

الآن يمكنك ترتيب صفوف جدول العرض دون خسارة بيانات هذا العمود.

 

ملحوظة:

يؤدي ترتيب جدول العرض أيضا إلى ضياع تنسيق جميع الخانات CellStyle وعودتها إلى القيم الأساسية المحفوظة في الخاصية DataGridView.DefultCellStyle.. حل هذه المشكلة يحتاج جهدا كبيرا، لأن الخانة تأخذ تنسيقها من عدة خصائص مختلفة مثل DataGridView.RowsDefultCellStyle و DataGridViewRow.DefultCellStyle و DataGridViewCell.CellStyle

وغيرها من الخصائص التي يمكنك الحصول على تأثيرها النهائي من خلال الخاصية DataGridViewCell.InheritedCellStyle

لهذا فإن محاولة حفظ قيم كل هذه الخصائص واستعادة تنسيق كل خانة بعد ترتيب الجدول عملية معقدة، خاصة إذا كان تنسيق الخانات يتغير أثناء تنفيذ البرنامج (كتغير لون خلفية أحد الصفوف عند اختيار قيمة معينة في إحدى خاناته)!

 

السبت، 26 أكتوبر 2013

رسم مستطيل حول الصف الحالي في DataGridView


س: كيف يمكن رسم مستطيل حول الصف الحالي في جدول العرض DataGridView؟ 



ج: أسهل طريقة لفعل هذا، هي استخدام الحدث RowPostPaint.. هذا الحدث ينطلق بعد أن يقوم جدول العرض برسم الصف.. يحدث هذا كلما كانت هناك ضرورة لإنعاش رسم الصف (كأن يختفي جزء من النافذة، أو يتم تكبيرها أو تصغيرها... إلخ).. ونظرا لأن هذا الحدث ينطلق بعدد الصفوف الظاهرة على الشاشة كلما دعت الحاجة لرسمها، فعليك أن تفحص معاملات الحدث لتتأكد من أن رقم الصف المرسوم هو رقم الصف الحالي:

Dim Row = DataGridView1.CurrentRow ' الصف الحالي

If Row Is Nothing Then Return ' لا يوجد صف محدد حاليا

If Row.Index < > e.RowIndex Then Return

بعد هذا يمكنك أن ترسم مستطيلا حول الصف.. لفعل هذا استخدم الخاصية e.RowBounds لمعرفة إحداثيات المستطيل المحيط بالجزء الظاهر على الشاشة من الصف.. واستخدم الخاصية e.Graphics للحصول على كائن الرسوم الخاص بالصف، لتقوم بواسطته بعملية الرسم.

إلى هنا وكل شيء بسيط.. لكن هناك بعض اللمسات التي يجب وضعها حتى يظهر المستطيل بشكل صحيح:

الأربعاء، 23 أكتوبر 2013

تغيير ارتفاع اللافتة لتستوعب النص


سس: في نماذج الويندوز، كيف يمكن تغيير ارتفاع اللافتة Label لتستوعب النص المكتوب داخلها بالضبط، مع تثبيت عرضها؟.. وهل يمكن عرض منزلق رأسي في اللافتة؟

 

ج: تمتلك اللافتة الخاصية AutoSize، وعند جعل قيمتها True فإن اللافتة تغير حجمها لتستوعب النص المكتوب داخلها.. لكن هذه الخاصية تسبب مشكلة مع السطور الطويلة جدا، فهي تجعل عرض اللافتة كبيرا جدا ليستوعب أطول سطر مكتوب فيها.. لهذا إذا أردت تثبيت عرض اللافتة وجعلها تقسم السطر الطويل على أكثر من سطر، فيجب أن تضع في الخاصية AutoSize القيمة False.. لبكن في هذه الحالة سيظل ارتفاع اللافتة ثابتا، وقد يكون أكبر من ارتفاع السطور المكتوبة داخلها، وقد يكون أصغر مما يجعل بعض السطور لا تظهر في الجزء المعروض من اللافتة.

لحل هذه المشكلة يجب علينا قياس ارتفاع النص.. يمكن فعل هذا باستخدام كائن الرسوم Graphics Object الخاص باللافتة، فهو يمتلك وسيلة اسمها MeasureString، تقوم بقياس حجم النص المرسل إليها عند عرضه في اللافتة عندما يكون لها عرض معين.. وتعيد هذه الوسيلة كائنا من النوع SizeF يحتوي على عرض وارتفاع النص عند وضعه في اللافتة.. كل ما علينا إذن هو تغيير ارتفاع اللافتة إلى هذا الارتفاع:

Label1.AutoSize = False

Dim G = Label1.CreateGraphics( )

Dim textSize = G.MeasureString(Label1.Text, Label1.Font, Label1.Width)

Label1.Height = Math.Ceiling(textSize.Height)

لاحظ أن ارتفاع اللافتة قد يكون كبيرا جدا إذا وضعت فيها نصا طويلا جدا.. يمكن التغلب على هذه المشكلة باستخدام منزلق رأسي Vertical ScrollBar.. طبعا اللافتة لا تمتلك مثل هذا المنزلق، لهذا عليك وضعها داخل لوحة Panel، وجعل اللافتة تنطبق على حافتها العلوية (Dock = Top) والتأكد من جع اللوحة ذاتية الانزلاق:

Panel1.AutoScroll = True

بهذه الطريقة صار لديك لافتة تغير ارتفاعها لتحتوي النص المكتوب فيها، مع عرض منزلق رأسي إذا زاد ارتفاع النص عن حد معين (تتحكم أنت فيه بالتحكم في ارتفاع اللوحة).

 

ملحوظة: يمكنك استخدام هذه اللافتة المرنة في تصميم مربع رسالة Message Box أكثر أناقة من مربع الرسالة الخاص بالويندوز، فعرض منزلق رأسي يريحك من تغيير عرض مربع الرسالة، ويجعلك لا تقلق من عرض الرسائل الطويلة جدا.

 

الثلاثاء، 22 أكتوبر 2013

3 أخطاء محتملة عند التعامل مع DateTimePicker


3 أخطاء محتملة عند التعامل مع DateTimePicker

 

عند استخدام أداة اختيار الوقت والتاريخ DateTimePicker، هذه ثلاثة أخطاء الصغيرة قد تقع فيها:

1- عند تغيير القيمة الصغرى MinDate والقيمة القصوى MaxDate للتاريخ أثناء تشغيل البرنامج (نتيجة لاختيار المستخدم لعدة تواريخ تتعلق ببعضها)، قد تعطيك الأداة DateTimePicker رسالة بأن القيمة الصغرى أكبر من القيمة العظمى، أو أن القيمة العظمى أصغر من القيمة الصغرى، رغم أنك اخترت قيمتين صحيحتين لهما.. السبب في هذا هو أن القيمتين الجديتين قد تتعارضان مع القيمتين القديمتين.. على سبيل المثال:

إذا كانت القيمة الصغرى الحالية هي 1/10/2013 والقيمة العظمى هي 31/10/2013، وأردت تغييرهما إلى 1/11/2013 و 30/11/2013 على الترتيب.. في هذه الحالة لو حاولت أن تضع القيمة الصغرى الجديدة 1/11/2013 فسيحدث خطأ في البرنامج لأنها أكبر من القيمة العظمى القديمة!.. في هذه الحالة يجب وضع القيمة العظمى أولا.. لكنك لا تستطيع اعتماد هذا الترتيب في كل الحالات، لأن القيمة العظمى الجديدة في موقف آخر قد تكون أصغر من القيمة الصغرى القديمة!

لتجنب هذه المشكلة بطريقة بسيطة وبدون الدخول في حسابات وجمل شرط، استخدم الترتيب التالي:

- لا تضع القيمة الصغرى التي تريدها مباشرة، بل ضع في الخاصية MinDate تاريخا قديما جدا، مثل 1/1/1900.

- ضع القيمة القصوى في الخاصية MaxDate.. طبيعي أنها ستكون أكبر من ذلك التاريخ القديم.

- ضع القيمة الصغرى في الخاصية MinDate.

- لاحظ أن تغيير قيمة أي من الخاصيتين MinDate و MaxDate يغير قيمة التاريخ الحالي المحدد في الأداة (الموجود في الخاصية Value)، لهذا قد تحتاج لإعادة وضع قيمة التاريخ الذي تريد عرضه في الأداة في الخاصية Value.

هذا مثال على هذه الطريقة:

DateTimePicker1.MinDate = #1/1/1900#

DateTimePicker1.MaxDate = Now.AddDays(3)

DateTimePicker1.MinDate = Now.AddDays(-3)

DateTimePicker1.Value = Now

 

2- عند استخدام Now لوضع قيم الخصائص MinDate أو MaxDate أو Value في الأداة DateTimePicker هناك احتمال أن يحدث خطأ في البرنامج.. السبب في هذا أن الأداة DateTimePicker لا تتعامل مع التاريخ فقط (السنة والشهر واليوم) بل تأخذ الوقت في اعتبارها أيضا.. ونظرا لأن استدعاء الدالة Now يعيد وقتا مختلفا في كل مرة، فإن الكود التالي سيسبب خطأ في البرنامج:

DateTimePicker1.MinDate = Now

DateTimePicker1.Value = Now

لأن الوقت العائد من Now في المرة الثانية، سيكون أكبر من القيمة العظمى!

لحل هذه المشكلة، استدع الدالة Now مرة واحدة فقط وضع ناتجها في متغير، ثم ضع قيمته في خصائص الأداة DateTimePicker:

Dim D = Now

DateTimePicker1.MinDate = D

DateTimePicker1.Value = D

 

3- نظرا لأن الأداة DateTimePicker لا تتعامل مع التاريخ فقط (السنة والشهر واليوم) بل تأخذ الوقت في اعتبارها أيضا، أنصحك عند استخدام الدالة Now في وضع قيمة أي من الخصائص (MinDate أو MaxDate أو Value) أن تتخلص من جزء الوقت لأنه قد يسبب مشاكل، ويجعل بعض التواريخ خارج النطاق المسموح به بسبب بضع ساعات أو دقائق أو حتى ثواني!

لفعل هذا، يمكنك تكوين تاريخ جديد باستخدام معلومات السنة والشهر واليوم فقط، كالتالي:

Dim FullDate = Now

ShortDate = New Date (FullDate.Year, FullDate.Month, FullDate.Day)

 

 

السبت، 19 أكتوبر 2013

تغيير ارتفاع مربع النص مفرد السطر


س: كيف يمكن تغيير ارتفاع مربع النص الذي يعرض سطرا واحدا فقط؟

 

ج: في الوضع الافتراضي يعرض مربع النص TextBox سطرا واحدا فقط، وذلك لأن للخاصية MultiLine القيمة False.

وفي هذه الحالة لو حاولت تغيير ارتفاع مربع النص من مصمم النموذج أو من الكود، فلن يحدث له أي تغيير، لكنه سيأخذ تلقائيا الارتفاع المناسب لحجم الخط.. لهذا ستجد أن الطريقة الوحيدة لتغيير الارتفاع هي تغيير حجم الخط!

هناك حل آخر هو أن تجعل مربع النص متعدد الأسطر MultiLine = True لتستطيع تغيير ارتفاعه.. لكن إدخال عدة سطور قد لا يناسب وظيفة مربع النص في برنامجك!

عامة هناك حل آخر بسيط.. فالسبب في عدم تغيير ارتفاع مربع النص مفرد السطر، هو أن للخاصية AutoSize القيمة True، لكن هذه الخاصية لا تظهر في نافذة الخصائص ولا في قائمة الإكمال التلقائي في محرر الكود، مما يجعلك تظن أنها غير موجودة في فئة مربع النص!.. لهذا إذا أردت تغيير ارتفاع مربع النص دون أن تجعله متعدد الأسطر، فعليك تغيير قيمة هذه الخاصية أولا.. مثال:

TextBox1.AutoSize = False

TextBox1.Height = 50

مع ملاحظة أن هناك سببا وجيها لمنعك من تغيير ارتفاع مربع النص منفرد السطر، وهو أن النص لن يغير موضعه ليتوسط الارتفاع الجديد، وبالتالي سيبدو مربع النص بشكل غير متناسق!

ولحل هذه المشكلة، يمكنك استخدام حيلة بسيطة، كالتالي:

-      ضع مربع النص على لوحة Panel.

-      اجعل مربع النص بلا إطار BorderStyle = None.

-      اجعل اللوحة مجسمة الإطار BorderStyle = Fixed3D.

-      اجعل خلفية اللوحة بيضاء مثل مربع النص BackColor = Color.White.

-      غير موضع مربع النص على اللوحة ليكون في منتصفها رأسيا.

-      غير عرض مربع النص ليكون مساويا لعرض اللوحة.

-  استخدم الخاصية Anchor الخاصة بمربع النص لتثبيت حافتيه اليمنى واليسرى بالنسبة للوحة.

-  ستحتاج لكتابة كود بسيط في الحدث Resize الخاص بمربع النص، لتوسيطه رأسيا كلما تغير الارتفاع.

بهذه الخدعة البصرية البسيطة، سيبدو كأنك حصلت على مربع نص منفرد السطر له ارتفاع أكبر J.. مع قدرتك على تغيير ارتفاع اللوحة ليبدو كأنك تغير ارتفاع مربع النص J.

الثلاثاء، 15 أكتوبر 2013

أداة اختيار التاريخ DateTimePicker


س: ما الحدث الذي ينطلق عندما يغير المستخدم حالة مربع الاختيار CheckBox الخاص بأداة اختيار التاريخ DateTimePicker؟

 


ج: يمكن أن تعرض أداة اختيار التاريخ DateTimePicker مربع اختيار CheckBox، وذلك إذا وضعت في الخاصية DateTimePicker.ShowCheckBox القيمة True.

وعندما يغير المستخدم التاريخ في الأداة DateTimePicker، أو عندما يغير حالة مربع الاختيار، ينطلق الحدث ValueChanged!.. قد يكون هذا غريبا بعض الشيء، ولكن هكذا تعمل هذه الأداة!

لهذا يمكنك أن تفحص قيمة الخاصية DateTimePicker.Checked في هذا الحدث، وبناء عليها تتخذ الفعل المناسب لبرنامجك.

 

الخميس، 10 أكتوبر 2013

تعطيل أحد أشرطة الأداة TabControl


س: كيف يمكن تعطيل أحد أشرطة الأداة TabControl؟
 

ج: كل صفحة من صفحات الأداة TabControl هي من النوع TabPage.. ورغم أنك لن تجد الخاصية Enables في نافذة الخصائص أو قائمة الإكمال الذكي عند كتابة الكود، فإن هذه الأداة تمتلك هذه الخاصية، لأنها موروثة من الفئة الأم Control.. لهذا يمكنك أن تكتب مثلا:

TabPage2.Enabled = False

لكن على عكس ما تتوقع، هذا سيعطل الصفحة وما عليها من أدوات، ولكنه لن يعطل الشريط Tab الخاص بالصفحة أعلى الأداة TabControl.. لهذا إن كنت تهدف إلى منع المستخدم من عرض الصفحة نفسها، فيمكنك أن تستخدم الحدث TabControl. Selecting الذي ينطلق عند ضغط شريط إحدى الصفحات، وفي هذا الحدث يمكنك أن تلغي عرض صفحة معينة، كالتالي:

If e.TabPage Is TabPage2 Then e.Cancel = True

طبعا تحتاج لإضافة شرط آخر يوضح متى يمكن السماح بعرض هذه الصفحة، وذلك تبعا لوظيفة برنامجك.. وأبسط طريقة لفعل هذا هي الجمع بين الطريقتين السابقتين، بمنع عرض الصفحة إذا كانت غير فعالة، كالتالي:

If e.TabPage Is TabPage2 Then e.Cancel = Not TabPage2.Enabled

وإذا أردت تغيير لون شريط الصفحة، بحيث تشعر المستخدم أنها معطلة، فيمكنك أن تتدخل أنت لرسمه، بتغيير قيمة الخاصية DrawMode كالتالي:

tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed

وكتابة معالج للحدث DrawItem تقوم فيه برسم شريط الصفحة.

أما إن كنت تريد حلا يمنع المستخدم من ضغط شريط الصفحة، فيمكنك أن تزيل الصفحة من أداة الأشرطة باستخدام الكود التالي:

TabControl1.TabPages.Remove(TabPage2)

وعندما تريد استخدامها، يمكنك إضافتها مرة أخرى:

TabControl1.TabPages.Add(TabPage2)

ولا تحاول استخدام الوسيلة TabPage2.Hide الخاصة بالصفحة، فهي لن تعمل!

 

 

الأربعاء، 9 أكتوبر 2013

DataGridViewCheckBoxColumn


س: في جدول عرض البيانات DataGridView، إذا استخدمت عمودا من النوع DataGridViewCheckBoxColumn.. كيف يمكنني أن أعرف أن المستخدم غير حالة الاختيار Checked في أي خانة في هذا العمود؟

 


ج: عندما يضغط المستخدم مربع الاختيار في أي خانة في هذا العمود، ينطلق الحدث DataGridView.CellContentClick الخاص بجدول العرض.. في هذا الحدث افعل ما يلي:

- تأكد أن الخاصية e.ColumnIndex تشير إلى رقم العمود DataGridViewCheckBoxColumn، لأن هذا الحدث ينطلق عند ضغط خانات أعمدة من أنواع أخرى.

- احصل على الخانة الحالية التي تسببت في إطلاق هذا الحدث باستخدام الخاصية DataGridView.CurrentCell.. أو يمكنك استخدام التعبير التالي للحصول على هذه الخانة (افترض أن اسم جدول العرض Dgv):

Dim Cell = Dgv.Rows(e.RowIndex).Cells(e.ColumnIndex)

أنا أفضل الطريقة الأخيرة، ففي بعض الأحيان يمكن أن تشير الخاصية CurrentCell إلى خانة محددة أخرى، بينما ضغط الخانة التي أطلقت الحدث ما زال لم يجعلها الخانة الحالية.. لهذا إذا وجدت رقم الصف والعمود في البيانات المرافقة لأي حدث من أحداث جدول العرض، فالآمن أن تستخدمها!

- لا تستخدم الخاصية Cell.Value لمعرفة قيمة الخانة، فهي لا تتغير إلا بعد مغادرة الصف الذي توجد فيه في جدول العرض!!.. الخدعة هنا هي استخدام الخاصية Cell.EditedFormattedValue بدلا منها:

If CBool(Cell.EditedFormattedValue) then

    MsgBox("تم اختيار هذه الخانة")

End If

عامة، من خلال تجاربي البائسة من العمود من النوع DataGridViewCheckBoxColumn، اكتشفت أن الحدث CellContentClick قد لا ينطلق دائما عند ضغط مرب الاختيار في خانات هذا العمود، وكذلك الحال مع الحدث CellValueChanged (فكما قلنا فإن الخانة لا تحدث قيمتها إلا بعد مغادرة الصف)!!.. كما أني حاولت أن أستخدم معالجا للحدث CheckedChanged الخاص بمربع الاختيار CheckBox الموجود في هذه الخانة، ولكن لم أستطع، لأن هذه الخانات لا تتسبب في إطلاق الحدث DataGridView.EditingControlShowing!

لهذا نصيحتي في هذا الأمر هي:

إذا كان العمود DataGridViewCheckBoxColumn مرتبطا بمصدر بيانات، فليس عليك أن تقلق بشأنه، فهو سيحدث سجلات مصدر البيانات DataSource بطريقة صحيحة طبقا للخانات التي اختارها المستخدم أو أزال منها الاختيار.. أما إذا لم يكن هذا العمود مرتبطا بمصدر بيانات، وكان عليك أداء وظيفة معينة تبعا لقيم خاناته، فالحل الأسهل والأضمن هو أن تنفذ هذه الوظيفة مرة واحدة في إجراء اسمه SaveChanges مثلا، يتم استدعاؤه عندما يضغط المستخدم زر الحفظ، أو عندما يحاول إغلاق النافذة وتسأله إن كان يريد حفظ التغييرات.. في هذا الإجراء كل ما ستفعله هو المرور عبر كل صفوف جدول العرض، وفحص قيمة كل خانة في هذا العمود (افترض أنه العمود رقم I)، واتخاذ الفعل المناسب تبعا لحالتها، على الصيغة:

Dgv.EndEdit()

For Each Row As DataGridViewRow In Dgv.Rows

       If CBool(Row.Cells(I).Value) Then

           ' الوظيفة الخاصة بكون الخانة مختارة

       Else

           ' الوظيفة الخاصة بكون الخانة غير مختارة

       End If

Next

 

لاحظ استدعاءنا للوسيلة EndEdit في بداية الكود لإنهاء تحرير أي خانة ما زالت في وضع التحرير.

 

 

 

صفحة الشاعر