السلام عليكم ورحمة الله وبركاته
أثناء بحثي في ملفاتي القديمة وجدت هذا المقال للأخ أحمد أبو دقة مشرف منتدى ASP.NET في فيجوال بيسك للعرب
وهو عن طريقة عرض البيانات على DataGrid بشرح كاف وواف
فجزاه الله خيرا
وهاأنذا أنقله للفائدة
المقال
السلام عليكم ورحمة الله وبركاته
عندما تسأل كيف يمكنك أن تعرض بياناتك على صفحة الويب ستجد الجواب استخدم DataGrid أو Repeater أو DataList و لكن كيف ستختار الأداة
أختيارك للأداة المناسبة ستكون مبنية على اساس طريقة العرض التي تريدها
قبل البدأ لن يتم شرح كيفية التعامل مع قاعدة البيانات وانما كيفية العرض وانشاء قوالب العرض وفي كل الأدوات يتم عرض البيانات في كل من الأدوات الثلاث أعلا بتحديد DataSource وهو كائن الDataSet او DataTable أو DataView أو DataRow واذا كان الDataSource هو DataSet فيجب تحديد إسم الجدول في الخاصية DataMember للأداة ثم بعد ذلك للعرض نكتب الأمر DataBind للأداة
DataGrid بإختصار شديد عندما تعرض البيانات تعرضها على شكل جدول والعنصر (Item) هو عبارة عن خلية (Cell) في الجدول وكل سجل في البيانات والمعبر عنه DataRow في ال.NET هو عبارة عن صف (TableRow)
معنى هذا ان كل سجل في قاعدة البيانات او الDataTable عبارة عن سطر في الجدول هذا السطر يتكون من الخلايا الموجود في هذا السجل
مثلا لو كان السجل يتكون من الإسم والايميل سيعرض الاسم والايميل في خليتين في نفس الصف من الجدول المعروض
ستتضح طريقة العرض اكثر عندما تجربها
عند إنشائك الDataGrid يجب عليك تحديد الأعمدة الذي تريد عرضها من الجدول ويمكنك تحديد طريقة العرض لكل عمود مثلا لو اردت عرض العمود الأول كرابط والثاني كنص عادي وهكذا
وكما ذكرت سابقا انت مقيد بالجدول وان كل سجل هو صف في هذا الجدول لذا تقوم بتعيين طريقة عرض لكل عمود لذلك ستجد فقط كائن Columns لإضافة طريقة العرض للأعمدة
ومثالا على ذلك لو كان لديك جدول DataTable أسمه Forums موجود في DataSet ولكن Ds وبها الأعمدة التالية
ForumID , Title , ThreadsCount , PostsCount
وكنت تريد عرض الTitle والThreadsCount و PostsCount لكل سجل
اولا أكتب مايلى في كود Html لصفحة الaspx وليس في CodeBehind
<asp:DataGrid ID="DG" Runat=server></asp:DataGrid>
بهذا قمنا بإنشاء DataGrid أسمها DG داخل اقواس التتويج للأداة ننشئ الكائن Columns ليصبح هكذا
<asp:DataGrid id="DataGrid1" runat="server"><Columns></Columns></asp:DataGrid>
دخل الأداة Colunms نضع طرق العرض للأعمدة التي تريد عرضها وتككون من عدة كائنات
أولاها BoundColumn يمكنك من هذا الكائن عرض الخلية كنص فقط وذلك بتحديد إسم الحقل في الخاصية DataField
مثلا
<asp:BoundColum DataField="Title"></asp:BoundColumn>
هذا السطر يقوم بعرض الحقل Title في كل السجلات في الجدول ولكن لو اردت ان يضهر اسم لهذا العمود في أعلى الجدول أو أسفله تقوم بكتابة النص في الخاصية HeaderText هذه لكتابة النص في الأعلى و FooterText لكتابة نص في الأسفل أو يمكنك وضع صور في الخاصيتين HeaderImageUrl و FooterImageUrl
وهناك خاصية أخرى تبدو لي مهمه وهي DataFormatString يمكنك من هذه الخاصية ان تضع نمط معين لعرض النص وهي قريبة من الدالة Format للفيجوال بيسك
مثال على Format
مثلا إضافة كلمة "منتدى" بجوار الTitle تكتب في ال DataFormatString "منتدى {0:#}"
مثلا إضهار أول رقمين عشرين لو كان لديك كسر او ناتج نسبة او ما شابه تكتب "{0:0.00}"
وهكذا ،،،
لنرى كيف يمكن عرض الثلاث أعمدة Title و TheardsCount و PostsCount مع ظهور في رأس كل عمود أسم لكل منهم
<asp:DataGrid ID="DG" Runat="server" AutoGenerateColumns="False"> <Columns> <asp:BoundColumn DataField="Title" HeaderText="إسم المنتدي"></asp:BoundColumn> <asp:BoundColumn DataField="ThreadsCount" HeaderText="عدد المواضيع"> </asp:BoundColumn> <asp:BoundColumn DataField="PostsCount" HeaderText="عدد المشاركات"> </asp:BoundColumn> </Columns> </asp:DataGrid>
ملاحظة عند انشاءك الDataGrid تكون القيمة الإفتراضية للخاصية AutoGenerateColumns تكون True وبهذا ستقوم بعرض جميع خلايا الجدول كنصوص وايضا الخاصية ShowHeader تكون True لذلك يجب تعطيل الخاصية AutoGenerateColumns إذا كنت ستخصص عرض الخلايا و لا تريد عرض جميع خلايا السجلات كما هو المثال
بعد ان عرفت كيف تقوم بعرض السجل يجب عليك معرفة كيفية تغير المظهر لشكل السجلات بما يناسبك الخواص ItemStyle-XX في الكائن BoundColumn تمكنك من تغير الStyle للخلية وايضا يوجد الخواص HeaderStyle-XX لوضع Style معين عنوان في رأس العمود وايضا الخواص FooterStyle-XX
XX تعبر عن جميع خواص التنسيق الخاصة بالTableCell مثل BackColor FontColor ... إلخ
اذا كنت تريد كل خلايا السجل تكون بنفس التنسيق يكون في خواص الDataGrid تجد خواص ItemStyle-XX و HeaderStyle-XX و FooterStyle-XX وأيضا ستجد شيئا جديدا وهو AlternatingItemStyle-XX
مالفرق بين الخواص AlternatingItemStyle-XX و الخواص ItemStyle-XX الفرق ستراه بعينك عندما تضع تنسيقين مختلفين في كل منهما الItemStyle-XX ستطبق على كل السجلات اذا لم يكون هناك اذا لم تستخدم اي خاصية من الAlternatingItemStyle-XX
ماذا سيحدث اذا استخدمت خواص AlternatingItemStyle-XX ستجد انه سجل ينطبق عليه خواص ItemStyle-XX والسجل الذي يلية ينطبق عليه الخواص AlternatingItemStyle-XX هكذا الي نهاية الجدول
ولكن اذا كنت قد وضعت على سبيل المثال ItemStyle-Color=LightBlue ووضعت الخاصية AlternatingItemStyle-Font-Bold=True ماذا سيحدث ستجد أن كل السجلات أصبحت خلفيته باللون الأزق الفاتح وستجد السجلات الزوجية فقط خطها عريض أقصد من ذلك ان اقول ان الخواص ItemStyle-XX تطبق على السجلات ثم بعد ذلك AlternatingItemStyle-XX تنطبق على السجلات الزوجية فقط تاركة وراءها ما يمكن تركه من خواص ItemStyle-XX
وذا كنت قد عينت أي Style من الكائن BoundColumn فإنه سائد على خواص الItemStyle الموجوده في DataGrid اما AlternatingItemStyle فلا
الكائن التالي من كائنات الDataGrid هو HyperLinkColumn وهو باين من اسمه ويستخدم لعرض نص الخلية كرابط إلى عنوان اما ثابت وتضعه في الخاصية NavigateUrl لهذا الكائن أو موجود في أحد خلايا السجل وتضع اسم الخلية في الخاصية DataNavigateUrlField وغالبا ماتكون البيانات لا تحتوي على روابط وانما على ID مثلا تقوم بإضافته الى الرابط كـQueryString وذلك بإستخدام خاصية DataNavigateUrlFormatString لهذا الكائن
على سبيل المثال نضه الخلية Title كـرابط لصفحة Forum.aspx ونضيف اليها قيمة الID
سيكون كالتالي
<asp:HyperLinkColumn DataTextField="Title" DataNavigateUrlField="ID"
DataNavigateUrlFormatString="Forum.aspx?Id={0:#}"></asp:HyperLinkColumn>الكائن التالي من كائنات الDataGrid وهو TemplateColumn ويعتبر أهم الكائنات لعرض العمود في الDataGrid حيث يمكنك عمل اي قالب داخل هذه الخلية من الجدول مثلا ان تضعه في اداة مثلا زر input او radiobutton او حتى DropDownList مثلا لو كنت عامل منتدى ومستخدم DropDownList لعرض المشرفين أو أنك عمال زر يضيف السجل في سلة مشتريات أو نضام رسائل فتحتاج إلى CheckBox لتحديد الرسالة للحذف او النقل او ماشابه
ما الذي يمكنك عمله في هذا القالب
أولا ItemTemplate قالب عناصر السجلات
لعرض العنصر Title كما هو عن طريق القالب نكتب
<asp:TemplateColumn> <ItemTemplate><%# DataBinder.Eval(Container.DataItem, "Title") %></ItemTemplate> </asp:TemplateColumn>
كما ترى قمت بالتعبير عن العنصر Title ب<%# DataBinder.Eval(Container.DataItem, "Title") %> ويمكنك ان تضع مقدار اكثر من عنصر داخل الخلية مثلا لو أردت عمل رابط مثل الذي عملناه تماما في HyperButton
<a href='Forum.aspx?Id=<%# DataBinder.Eval(Container.DataItem, "ID") %>'> <%# DataBinder.Eval(Container.DataItem, "Title") %></a>
لاحظ اني استخدمت عنصرين من السجل في خلية واحدة من الجدول وينمكنك استخدم العدد الذي تريد .
هنا قمت بوضع قيمة الID بعد "Forum.aspx?Id=" لي ملاحظة مهمة مع هذه في حالة الأدوات الخاصة بالWebControl أقصد الادوات التي تحتوي في التتويج asp: عند استخدام خاصائصها في يجب ان تكتب كل الخاصية اما خارج القوسين <%%> أو داخلهما ولا يمكنك كتابة نصفه في الداخل ونصفه في الخارج مثل هذا المثال
بالنسبة لأدوات Html مثل HtmlAnchor عندما استخدمت الخاصية Href وضعت قيمتها 'Forum.aspx?Id=<%# DataBinder.Eval(Container.DataItem, "ID") %>' لنري كيف يمكن كتابة هذا الرابط مع الأداة asp:Hyperlink
<asp:TemplateColumn> <ItemTemplate><asp:HyperLink ID="Lnk" Runat=server NavigateUrl='<%# "Forum.aspx?Id=" & DataBinder.Eval(Container.DataItem, "ID") %>'> <%# DataBinder.Eval(Container.DataItem, "Title") %></asp:HyperLink></ItemTemplate> </asp:TemplateColumn>
كما رأيت هنا قد وضعت النص "Forum.aspx?Id=" ثم ضفته مع العنصر وهنا كان الكود VB اذا كنت بتستخدم C# انتبه للكود فبدل & ضع +
أيضا يمكنك استخدام اي دول نصوص خاصة بالنصوص او حتى الإستعانة بمتغيرات وثوابت ولكن اذا كنت تستخدم CodeBehind يجب أن يكون المتغير او الكائن اما protected أو family أو puplic أما اذا كان private فسيحدث خطأ في الصفحة أما اذا لم تكن تستخدم CodeBehind فلا يهم
هناك ايضا HeaderTemplate و الFooterTemplate يمكنك استخدامهما عمل احداث عامه على كل السجلات مثلا لو كنت تعرض رسائل وتستخدم CheckBox في تحديد الرسائل هناك CheckBox تقوم بتحديد جميع الرسائل مثلا
يوجد ايضا داخل كائن TemplateColumn نفس خائص الStyle لـ BuondColumn
الكائن ButtonColumn هذا الكائن يختص لعمل أزرار أوامر اما على شكل رابط او على شكل زر Input Botton وذلك بأن تضع نوع الزر الذي تريد ButtonType ولها قيمتين PushButton وهو زر عادي Button أو LinkButton وهو زر HeyberLinkButton ثم تضع له إسم CommandName لكي تستطيع التعامل معه في الخاصية CommandName
وهذه الأزرار تستخدم ليس كروابط وانما لأحداث تريد القيام بها مثل حذف السجل أو اي شيئ من هذا القبيل
يمكن استخدام خاصية DataTextField لتضع نص للزر من خلية معينه للسجل
من مييزات DataGrid أنك تستطيع تحديد سجل معين من السجلات وإعطاء هذه السجل لون معين أو بالأصح Style خاص به
على سبيل المثال كان عندك مستخدمين في موقعك وتريض عرض قائمة بأسمائهم وعند الضغط على أحدهم يقوم بتحديد هذا المستخدم ويمكن القيام بأي امر تريد مثلا على بيناته على الصفحة (Profile) أو لأي سبب آخر
يوجد في خصائص الDataGrid خصائص SelectedItemStyle هذه الخصائص تقوم بوضعها لتحديد الشكل الذي سيكون به السجل المحدد
كيفية تحديد سجل تحديد سجل ببساطة تقوم بوضع السجل الذي تريد تحديده في الخاصية SelectedIndex لأداة الDataGrid
لا تقلق سيكون هناك امثله موضحه
يمكنك في هذه الأداة أن تقوم بتعديل البيانات مباشرة دون الحاجة لنموذج آخر للتعديل ولكن يجب أن يكون العمود الذي تريده متاحا للتعديل هو BoundColomn ويتم تحويله إلى مربع نص في حالة التعديل أما إذا كان TemplateColumn يجب أن يكون به قالب للتعديل EditTemplate و يجب أن يكون به مربع نص وهذا القالب لايقبل أي اداه أخرى غير مربع النص فلا يمكنك استخدام DropDownList مثلا فإذا قمت بإضافة اي اداة أخرى سيعطيك خطأ أما بالنسبة HyberLinkColumn فلا يمكنك التتعديل واذا اردت تعديله فأستخدم TemlateColumn لعمل هذا الرابط وقم بعمل EditTepmlate وبهذا أصبحت قادرا على تعديله
قبل أن تعدل طبعا يجب تحديد السجل الذي تريد تعديل لكي يظهر قالب التعديل لهذا السجل وذلك ببساطة تحديد رقم السجل ItemIndex الذي تريد تعديله في الخاصية EditItemIndex للأداة DataGrid
تحتاج لذلك 3 أزرار أوامر CommandButton زر للتحديد السجل بعد ذلك عن ظهور قالب التعديل يظهر زران أحدهم لتعديل التغيرات والآخر للهروب في حالة التراجع عن التعديل
ولكن بدل من أن تنشأ كل هذه الازرار وتتعب نفسك هناك كائن من كائنات الColumns لأداة الDataGrid وهو EditCommandColumn
ماالذي يفعله هذا الكائن يقوم بعرض زر واحد بإسم Edit في حالة العرض وزران بإسم Update و Cancel في حالة التعديل وبهذا قد أرحنا رؤسنا من عمل كل هذه الأزرار بكائن واحد
هذا الكائن له بعض الخصائص وهي خصائص الStyle منها Item و Footer و Header
له 3 خصائص تحدد في النص الذي يضهر على الأزرار على سبيل المثال الزر Edit يضهر عليه كلمة "تعديل" وذلك في الخاصية EditText
وأيضا لبقية الأزرار UpdateText و CancelText
<asp:EditCommandColumn ButtonType="PushButton" UpdateText="حفظ" CancelText="إلغاء" EditText="تعديل"></asp:EditCommandColumn>
سأقوم بشرح بعض الاحداث لأداة الDataGrid ثم متابعة شرح بقية الخصائص والاحداث
الحدث ItemDataBound
هذا الحدث يحدث بعد انشاء كل Item في الDataGrid وله اهمية كبيره يمكنك مثلا من خلاله عمل أي تعديل على كل سجل او عمل استعلام فرعي وكتابة النتائج داخل هذا السجل مثلا كما ذكرت في البداية عندما قلت بأنك يمكن عمل DropDownlist بأسماء المشرفين ولكن كيف ستضع البيانات داخلها مع العلم ان المشرفين غير محددين لكل منتدى لذلك تقوم بعمل استعلام عن مشرفين لكل سجل اي لكل منتدى وتعبئت الأسماء داخل أداة الDropDownList
هذا الحدث يحدث أيضا بعد إنشاء الHeader وال Footer ،،،
في هذا الحدث يتم إرسال بارمترين مهمين الأول Object وهو كائن الDataGrid اي يمكنك استخدامه في تغيير خصائص الDataGrid اي كأنك بتستخدم الID للDataGrid لا فرق الباراميتر التاني DataGridItemEventArgs وهذا يتم فيه ارسال الكائن Item وهو عبارة عن خاصية في هذا الكائن تتفرع منه بعض الوضائف والخصائص لجلب بيانات عن السجل الحالى والتحكم فيه لتغيير ما تريد تغييره
أليك هذا المثال البسيط قمت فيه بعمل جدول بسيط يتكون من عمود واحد Name به بعض الأسماء واقوم بعرض 3 أعمدة 2 فارغات الأول لترقيم الجدول بإستخدام الحدث ItemDataBound والأخر لكتابة عدد الأحرف للأسم لكل سجل أيضا بإستخدم هذا الحدث
<asp:datagrid id="DataGrid1" runat="server" AutoGenerateColumns="False"> <Columns> <asp:BoundColumn></asp:BoundColumn> <asp:BoundColumn DataField="Name" HeaderText="الأسم"></asp:BoundColumn> <asp:TemplateColumn> <HeaderTemplate>عدد الأحرف</HeaderTemplate> <ItemTemplate><asp:Label ID="CharCount" Runat=server></asp:Label></ItemTemplate> </asp:TemplateColumn> </Columns> </asp:datagrid>
كما ترى هذه DataGrid تتكون من ثلاث أعمل العمود الأول عبارة عن Cell في الجدول فارغ وذلك بإنشاء كائن BoundColumn لنسند فيه قيمة رقم السجل ItemIndex الثاني به عمود Name من الجدول والثالث إستخدمت TepmlateColumn ووضعت فيه Label بإسم CharCount وقد تعمد بوضع لكي تتعرف على طريقة التعامل مع الكائنات في هذا الحدث
في الحدث Load للصفحة قمت بتحديد الDataSoruce والذي هو دالة تقوم بإنشاء DataTable ثم الأمر DataBind لعرض الجدول
VB.NET Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load If Not IsPostBack Then DataGrid1.DataSource = MakeTable() DataGrid1.DataBind() End If End Sub
C#
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
DataGrid1.DataSource = MakeTable();
DataGrid1.DataBind();
}
} VB.NET
Private Function MakeTable() As DataTable
Dim Dt As New DataTable()
Dt.Columns.Add(New DataColumn("Name", GetType(String)))
Dim Dr As DataRow = Dt.NewRow()
Dr("Name") = "أحمد"
Dt.Rows.Add(Dr)
Dr = Dt.NewRow()
Dr("Name") = "ابراهيم"
Dt.Rows.Add(Dr)
Dr = Dt.NewRow()
Dr("Name") = "محمد"
Dt.Rows.Add(Dr)
Dr = Dt.NewRow()
Dr("Name") = "أسامة"
Dt.Rows.Add(Dr)
Dr = Dt.NewRow()
Dr("Name") = "عبد الله"
Dt.Rows.Add(Dr)
Dr = Dt.NewRow()
Dr("Name") = "مصطفى"
Dt.Rows.Add(Dr)
Return Dt
End Function C#
private DataTable MakeTable()
{
DataTable Dt = new DataTable();
Dt.Columns.Add(new DataColumn("Name", typeof(string)));
DataRow Dr = Dt.NewRow();
Dr["Name"] = "أحمد";
Dt.Rows.Add(Dr);
Dr = Dt.NewRow();
Dr["Name"] = "ابراهيم";
Dt.Rows.Add(Dr);
Dr = Dt.NewRow();
Dr["Name"] = "محمد";
Dt.Rows.Add(Dr);
Dr = Dt.NewRow();
Dr["Name"] = "أسامة";
Dt.Rows.Add(Dr);
Dr = Dt.NewRow();
Dr["Name"] = "عبد الله";
Dt.Rows.Add(Dr);
Dr = Dt.NewRow();
Dr["Name"] = "مصطفى";
Dt.Rows.Add(Dr);
return Dt;
}في الحدث ItemDataBound
VB.NET
Private Sub DataGrid1_ItemDataBound(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles DataGrid1.ItemDataBound
'AlternatingItem أو Item التأكد إذا كان السجل الذي أنشاءه هو
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
'كتابة رقم السجل في الخلية الأولى من الصف في الجدول وهو العمود الأول الفارغ الذي أنشاءناه
e.Item.Cells(0).Text = e.Item.ItemIndex
'في الفيجوال بيسك Ctype وتحديد نوعه عن طريق الدالة CharCount البحث عن الاداة
CType(e.Item.FindControl("CharCount"), Label).Text = _
DataBinder.Eval(e.Item.DataItem, "Name").ToString().Length
End If
End Sub C#
private void DataGrid1_ItemDataBound(object sender,
System.Web.UI.WebControls.DataGridItemEventArgs e)
{
//AlternatingItem أو Item التأكد إذا كان السجل الذي أنشاءه هو
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType ==
ListItemType.AlternatingItem))
{
//كتابة رقم السجل في الخلية الأولى من الصف في الجدول وهو العمود الأول الفارغ الذي أنشاءناه
e.Item.Cells[0].Text = e.Item.ItemIndex.ToString();
//وتحديد نوعها وتغيير النص لها CharCount البحث عن الاداة
((Label)e.Item.FindControl("CharCount")).Text =
DataBinder.Eval(e.Item.DataItem, "Name").ToString().Length.ToString();
}
}ملاحظة في استخدام Ctype لمبرمجي الفيجوال بيسك يستحسن إسناد الكائن إلى متغير يتم تعريفه بنوع الكائن في حالة استخدام الأداة أكثر من مره مثلا
VB.NET
Dim CharCount As Label = Ctype(e.Item.FindControl("CharCount"), Label)
CharCount.Text = "Very"
CharCount.Text &= "Good"اذا قمت باستخدام Ctype في كل مره ستكتب فيها ستظطر في البحث عن الأداة مرتين
وكذلك في C#
C#
Label CharCount = (Label)e.Item.FindControl("CharCount")
CharCount.Text = "Very";
CharCount.Text += "Good";الحدث ItemCommand
هذا الحدث المهم يحدث عند الظغط على زر موجود في الDataGrid طبعا يجب أن يكون Run At Server ويجب أن يكون أحد أنواع الأزرار الثلاثة
- Button
- LinkButton
- ImageButton
او الزر الذي ينشئ عن العمود ButtonTemplate
عند الضغط على اي زر في الDataGrid داخل السجلات أو في الHeader أو الFooter يحدث هذا الحدث ويرسل بارمترين هما نفس البارمترين للحدث ItemDataBound الا أن البارميتر التاني وهو DataGridItemEventArgs يضاف له بعض الخصائص الخاصة بالزر المضغوط
- CommandName
- CommandArgument
- CommandSource
CommandName وهو عبارة عن نص تضعه في الزر ليبين اسم الزر المضغوط وهو ليس الID لذلك فهو يسهل عليك معرفة الزر المظغوط دون الحاجة لمعرفة الID فمعرفة الID تحتاج مشقة في هذا الحدث سأوضحها القيمة الإفتراضية لهذه الخاصية فارغة ""
CommandArgument وهو عبارة عن نص أيضا ويمكن استخدامه بدل الCommandName لكن السبب الأساسي لوضعه هو انك ربما تحتاج الى وضع قيمة نصية لاعادة ترتيب
السجلات مثلا تكون قيمته ASC أو DESC أو أي استخدام مثلا تحتاج لزر حذف السجل ورقم السجل ليس له عمود في الDataGrid فتخبأه هنا لوقت الحاجة
الDataGrid فتخبأه هنا لوقت الحاجة
القيمة الأفتراضية لهذه الخاصية فارغة
CommandSource وهو المعبر على الأداة التي ضغطت عليها أي يمكنك إستخدام هذه الخاصية لإستخدام الأداة التى ضغطت دون الحاجة بأن تبحث عن الID لها لكي تغير النص مثلا ولا تحتاج ايضا لأن تضع ID للزر أصلا ...
لذا عند وضعك الأزرار في الDataGrid تضع لها CommandName وليس ID ولكن إذا كنت ستستخدم الزر في حدث آخر مثل ItemDataBound فضع له ID أو يمكنك استخدام رقم الأداة واستدعاءها من مصفوفة الControls في الخلية
سأكتب مثال يبين إستخدام الحدث ItemCommand ولكن قبل البدأ يج أن تعرف بعض الأحداث المشابهه وهم:-
- EditCommand
- UpdateCommand
- CancelCommand
- Delete Command
- SortCommand
هم نفس الحدث ItemCommand ولكن متى تحدث الحدث EditCommand يحدث فقط عن الضغط على زر الCommandName له Edit
ولكن هل يحدث ItemCommand والجواب هو نعم ولكن وضغت هذه الأحداث للأزرار الشائعة مثل Edit و Delete وال Cancelلأنها شائعه وبدل من شرط التحقق للCommandName تقوم بوضع الحدث بشكل منفصل ويمكنك أستخدام الطريقتين
اما بالنسبة للSortCommand فإن الكائن DataGridItemEventArgs يرسل معه CommandSource والSortExprestion ,وهي عبارة عن قيمة نص موجود خاصية أي عمود وتستخدم لوضع ترتيب معين للجدول تستخدمه لترتيب السجلات في الحدث SortCommand
طبعا يجب وضع الSortExpretion في عمود الزر الذي يحمل إسم Sort ولا يرسل معه CommandArgument وCommandName
في هذا المثال سيتم إستخدام قاعدة بيانات Access
تتكون قاعدة البيانات من جدول واحد اسمه users وبه عمودين Id رقم يزيد تلفائيا وهو Primarykey والعمود الثاني Name نص
في المثال سنقوم بعرض الأسماء الموجوده على الDataGrid أمر بسيط ولكن مع امكانية تحديد وتعديل وحذف
في صفحة الaspx ننشئ هذه الDataGrid
<asp:datagrid id="DataGrid1" runat="server" AutoGenerateColumns="False" ShowFooter="True" Width="100%"> <HeaderStyle BackColor="#99ccff" HorizontalAlign="Center" /> <ItemStyle HorizontalAlign="Center" /> <AlternatingItemStyle BackColor="Gainsboro" /> <SelectedItemStyle BackColor="#000000" ForeColor="#ffffff" /> <EditItemStyle BackColor="DarkGray" /> <Columns> <asp:BoundColumn DataField="Name" /> <asp:ButtonColumn CommandName="Select" Text="تحديد" HeaderText="تحديد" /> <asp:EditCommandColumn EditText="تعديل" UpdateText="حفظ" CancelText="إلغاء الأمر" HeaderText="التعديل" ButtonType="PushButton" /> <asp:ButtonColumn CommandName="Delete" Text="حذف" HeaderText="الحذف" ButtonType="PushButton" /> </Columns> </asp:datagrid>
أعتقد أنها واضحه
دالة وضع البيانات في جدول DataTable
VB.NET
Private Function GetTable() As DataTable
Dim Cn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("db\db1.mdb"))
Dim Adptr As New OleDbDataAdapter("Select * From Users", Cn)
Dim CB As New OleDbCommandBuilder(Adptr)
Dim Dt As New DataTable()
Adptr.Fill(Dt)
Return Dt
End Function C#
private DataTable GetTable()
{
OleDbConnection Cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + this.Server.MapPath("db\\db1.mdb"));
OleDbDataAdapter Adptr = new OleDbDataAdapter("Select * From Users", Cn);
OleDbCommandBuilder CB = new OleDbCommandBuilder(Adptr);
DataTable Dt = new DataTable();
Adptr.Fill(Dt);
return Dt;
}في الحدث Page_Load تقوم بعرض البيانات على الDataGrid
VB.NET Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load If Not IsPostBack Then DataGrid1.DataSource = GetTable() DataGrid1.DataBind() End If End Sub
C#
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
DataGrid1.DataSource = GetTable();
DataGrid1.DataBind();
}
}ملاحظة هامة يجب إستخدام Page.IsPostBack عند عرض البيانات على الDataGrid أو أخواتها من الأدوات وذلك لكي تسطيع التقاط التغيرات التى تحصل فلو كنت تعرض البيانات دائما لن تستطيع إلتقاط التغيرات التى تكتب في النص داخل الDataGrid لأن الحدث Page_Load يسبق كل الأحداث وبذلك ستكون قيم مربع النص الخاص بالتعديل قد أصبح يساوي قيمته الأصلية في قاعدة والقيمة التي أدخلها المستخدم بتكون طارت
أول شيء سنعمل زر التحديد وقد وضعته العمود الثاني في الDataGrid والCommandName له Select
لذا سنذهب الى الحدث Item_Command لنقول للDataGrid إختر السجل الذي انضغط على رز الSelect له وضعه في الخاصية SelectedIndex للDataGrid
VB.NET Private Sub DataGrid1_ItemCommand(ByVal source As Object, ByVal e As DataGridCommandEventArgs) Handles DataGrid1.ItemCommand Select Case e.CommandName Case "Select" 'DataGridإختيار السجل الحالى ووضعه بأنه محدد في ال DataGrid1.SelectedIndex = e.Item.ItemIndex 'تغير إسم الزر وتغيير النص له لكي يقوم بإلغاء التحديد Dim LBtn As LinkButton = CType(e.CommandSource, LinkButton) LBtn.CommandName = "UnSelect" LBtn.Text = "إلغاء التحديد" Case "UnSelect" 'SelectedIndex = -1 إلغاء التحديد وذلك بوضع قيمة الخاصية DataGrid1.SelectedIndex = -1 'تغيير إسم الزر وتغيير النص لكي يقوم بالتحديد في الضغط عليه المره القادمة Dim LBtn As LinkButton = CType(e.CommandSource, LinkButton) LBtn.CommandName = "Select" LBtn.Text = "تحديد" End Select End Sub
C#
private void DataGrid1_ItemCommand(object source, DataGridCommandEventArgs e)
{
switch(e.CommandName)
{
case "Select":
{
//DataGridإختيار السجل الحالى ووضعه بأنه محدد في ال
DataGrid1.SelectedIndex = e.Item.ItemIndex;
//تغير إسم الزر وتغيير النص له لكي يقوم بإلغاء التحديد
LinkButton LBtn = ((LinkButton)e.CommandSource);
LBtn.CommandName = "UnSelect";
LBtn.Text = "إلغاء التحديد";
break;
}
case "UnSelect":
{
//SelectedIndex = -1 إلغاء التحديد وذلك بوضع قيمة الخاصية
DataGrid1.SelectedIndex = -1;
//تغيير إسم الزر وتغيير النص لكي يقوم بالتحديد في الضغط عليه المره القادمة
LinkButton LBtn = ((LinkButton)e.CommandSource);
LBtn.CommandName = "Select";
LBtn.Text = "تحديد";
break;
}
}
}في هذا الحدث قمت بمقارنة الCommandName للزر المضغوط إذا كان = "Select" فإنه يقوم بتحديد السجل في الDataGrid ويقوم بتغيير الCommandName لهذا الزر إلى UnSelect لإستخدامه في الغاء تحديد السجل دون استخدام زر آخر ثم غييرت النص لهذا الزر واصبح إلغاء التحديد أما إذا كان الـ CommandName للزر المظغوط هو "UnSelect" فإنه يقوم بإلغاء تحديد السجل ثم يقوم بتغيير الزر لوضع التحديد
في حدث الزر Edit نقوم بنفس الطريقة لتحديد السجل في الخاصية EditIndex للـ DataGrid ولكن بعد ذلك يجب عمل Bind للـبيانات مجددا في الDataGrid وذلك حتى يظهر قالب التعديل مباشرة وايضا حتى تظهر قيمة الحقل في النص الخاص به بدون Bind ستظهر بعض المشاكل الأخرى مثل تحديد السجل !!!
VB.NET Private Sub DataGrid1_EditCommand(ByVal source As Object, ByVal e As DataGridCommandEventArgs) Handles DataGrid1.EditCommand DataGrid1.EditItemIndex = e.Item.ItemIndex DataGrid1.DataSource = GetTable() DataGrid1.DataBind() End Sub
C#
private void DataGrid1_EditCommand(object source, DataGridCommandEventArgs e)
{
DataGrid1.EditItemIndex = e.Item.ItemIndex;
DataGrid1.DataSource = GetTable();
DataGrid1.DataBind();
}بالنسبة لأزرار الحذف والتعديل عند الحذف أو التعديل فإنانا نحتاج إلى الId للسجل لكي نقوم بالبجث عنه في قاعدة البيانات لنحذف أو نعدله لذلك هنا نقوم بإستخدام الخاصية CommandArgument لأزرار الحذف والتعديل ولكن كيف نقوم بذلك وهذه الخاصية غير موجوده في العمودين ButtonColumn و EditButtonColumn لذا نقوم بإضافة الID لـCommandArgument لكلا الزرّين في الحدث ItemDataBound
ولكن زر Edit كما قلت في المشاركة السابقة أنه فقط لعرض قالب التعديل للسجل إذا هو ليس الزر المناسب لوضع الID به زر حفظ التعديلات الذي يأتي مع قالب التعديل وهو الزر Update لذا سنشترط في هذا الحدث حدث ItemDataBound بأنه إذا كان السجل نوعه = EditItem لنرى الكود الذي يضيف الID لكل أزرار الحذف ويضيفه في زر الحفظ للسجل الذي يحتوي على قالب التعديل ،،،
VB.NET Private Sub DataGrid1_ItemDataBound(ByVal sender As Object, ByVal e As DataGridItemEventArgs) Handles DataGrid1.ItemDataBound 'لزر الحذف في كل سجل CommandArgument في الخاصية Idوضع قيمة ال If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then CType(e.Item.Cells(3).Controls(0), Button).CommandArgument = DataBinder.Eval(e.Item.DataItem, "Id") End If 'لزر حفظ التعديل في السجل الذي يكون قالب للتعديل CommandArgument في الخاصية Idوضع قيمة ال If e.Item.ItemType = ListItemType.EditItem Then CType(e.Item.Cells(2).Controls(0), Button).CommandArgument = DataBinder.Eval(e.Item.DataItem, "Id") End If End Sub
C#
private void DataGrid1_ItemDataBound(object sender, DataGridItemEventArgs e)
{
//لزر الحذف في كل سجل CommandArgument في الخاصية Idوضع قيمة ال
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
((Button)e.Item.Cells[3].Controls[0]).CommandArgument = DataBinder.Eval(e.Item.DataItem, "Id").ToString();
}
//لزر حفظ التعديل في السجل الذي يكون قالب للتعديل CommandArgument في الخاصية Idوضع قيمة ال
if (e.Item.ItemType == ListItemType.EditItem)
{
((Button)e.Item.Cells[2].Controls[0]).CommandArgument = DataBinder.Eval(e.Item.DataItem, "Id").ToString();
}
}ملاحظة الـ ListItemType.Item غير الـ ListItemType.AlternatingItem أي أن إذا عملت شرط يطبق على ListItemType.Item فقط فإنه يطبق على السجلات الفردية والثاني على الزوجية وليست كخصائص الStyle تطبق الItemSytle إن لم يوجد بديل لها AlternatingItemStyle
بعد ذلك نقوم بعمل تعديل على السجل المحدد في الحدث UpdateCommand الخاص بالزر Update
VB.NET
Private Sub DataGrid1_UpdateCommand(ByVal source As Object, ByVal e As DataGridCommandEventArgs) Handles DataGrid1.UpdateCommand
Dim Cn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("db\db1.mdb"))
'من مربع النص الموجود في الخلية الأولى في السجل الخاصة بالاسم Nameتعديل نص الـ
'ItemDataBound في الحدث Idللزر الذي قد قمنا بتخزين رقم ال CommandArgument واستدعاء الخاصية
Dim Cmd As New OleDbCommand("Update Users Set Name='" & CType(e.Item.Cells(0).Controls(0), TextBox).Text & _
"' Where Id=" & e.CommandArgument, Cn)
Cn.Open()
Cmd.ExecuteNonQuery()
Cn.Close()
'إلغاء قالب التعديل بعد تعديل السجل
DataGrid1.EditItemIndex = -1
'DataGridعرض البيانات الجديده واسترجاع الوضع العادي للسجلات في ال
DataGrid1.DataSource = GetTable()
DataGrid1.DataBind()
End Sub C#
private void DataGrid1_UpdateCommand(object source, DataGridCommandEventArgs e)
{
//من مربع النص الموجود في الخلية الأولى في السجل الخاصة بالاسم Nameتعديل نص الـ
//ItemDataBound في الحدث Idللزر الذي قد قمنا بتخزين رقم ال CommandArgument واستدعاء الخاصية
OleDbConnection Cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + this.Server.MapPath("db\\db1.mdb"));
OleDbCommand Cmd = new OleDbCommand("Update Users Set Name='" + ((TextBox)e.Item.Cells[0].Controls[0]).Text +
"' Where Id=" + e.CommandArgument, Cn);
Cn.Open();
Cmd.ExecuteNonQuery();
Cn.Close();
//إلغاء قالب التعديل بعد تعديل السجل
DataGrid1.EditItemIndex = -1;
//DataGridعرض البيانات الجديده واسترجاع الوضع العادي للسجلات في ال
DataGrid1.DataSource = GetTable();
DataGrid1.DataBind();
}بعد ذلك زر إلغاء التعديل او الرجوع عن التعديل اللي هو زر Cancel ونستخدم الحدث الخاص به CancelCommand ونكتب فيه بأن يقوم بإلغاء قالب التعديل وإعادة عرض السجلات وهو نفس آخر 3 أسطر من الحدث السابق
VB.NET Private Sub DataGrid1_CancelCommand(ByVal source As Object, ByVal e As DataGridCommandEventArgs) Handles DataGrid1.CancelCommand DataGrid1.EditItemIndex = -1 DataGrid1.DataSource = GetTable() DataGrid1.DataBind() End Sub
C#
private void DataGrid1_CancelCommand(object source, DataGridCommandEventArgs e)
{
DataGrid1.EditItemIndex = -1;
DataGrid1.DataSource = GetTable();
DataGrid1.DataBind();
}زر الحذف
لقد قمنا بتسجل الID في الخاصية CommandArgument لزر الحدف في كل السجلات لذلك نقوم بالحذف حسب الID الموجود في هذه الخاصية للزر
Vb.NET
Private Sub DataGrid1_DeleteCommand(ByVal source As Object, ByVal e As DataGridCommandEventArgs) Handles DataGrid1.DeleteCommand
Dim Cn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("db\db1.mdb"))
Dim Cmd As New OleDbCommand("Delete From Users Where Id=" & e.CommandArgument, Cn)
Cn.Open()
Cmd.ExecuteNonQuery()
Cn.Close()
DataGrid1.DataSource = GetTable()
DataGrid1.DataBind()
End Sub C#
private void DataGrid1_DeleteCommand(object source, DataGridCommandEventArgs e)
{
OleDbConnection Cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath("db\\db1.mdb"));
OleDbCommand Cmd = new OleDbCommand("Delete From Users Where Id=" + e.CommandArgument, Cn);
Cn.Open();
Cmd.ExecuteNonQuery();
Cn.Close();
DataGrid1.DataSource = GetTable();
DataGrid1.DataBind();
}