فكرة الـ MultiBinding
سأوضح هنا مشكلة يعاني منها الكثير ولا أعلم لم!
المشكلة تتحدث عن ربط الأدواة في مرحلة ما بعد ربط الأداة الأساسية ..و توضيحا لذلك أرفقت لكم صورة لأداة DataGrid تقوم بعرض مستخدمين في نظام ما و في العمود الثاني وبجانب كل مستخدم تظهر قائمة منسدلة بأسماء الرسائل التي أرسلها.
منطقيا يجب أن نقوم بربط ال DataGird أولا و من ثم نقوم بربط ال DropDownList.
في البداية نحتاج لجدولين في قاعدة البيانات كالتالي :
tblUsers و به الحقلين التاليين فرضا id و login
tblMessages و به الحقول التالية id و title من أجل عنوان الرسالة و Sender و هو المرسل للرسالة
قم بتعبئة الجداول يدويا فقط من أجل عمل تجربة سريعة واختصارا للوقت.
الان نأتي للمهم..
عندما نفتح صفحة ويب WebForm نجد الحدث Page_Load ... سنستخدمه لربط الداتا جريد كالتالي :
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
this.GetData();
}
}نرى أننا نحتاج لدالة اسمها GetData تقوم بربط الأداة .. دعونا نفكر ماذا نحتاج بها ..
سوف نستدعيها لتقوم بالتالي :
تنشيء DataSet
تقوم بعمل جدول أول في ال DataSet و ندرج به محتويات جدول المستخدمين
نقوم أيضا بإدراج جدول اخر في ال DataSet به محتويات الرسائل كلها
نقوم بعمل DataView التي من وظيفتها فلترة البيانات على الجدول الثاني الخاص بالرسائل.
نربط الداتا جريد فقط بمحتويات الجدول الأول كي تعرض لنا المستخدمين.
من يتضح لنا أننا نحتاج لبعض التعريفات ك Class Scope و هي كالتالي
SqlConnection cn = new SqlConnection(System.Configuration.ConfigurationSettings.AppSettings["CnStr"]); SqlDataAdapter da; DataSet ds=new DataSet(); DataView dv;
الان سأكتب الدالة GetData التي ستقوم بما شرحت من قليل
private void GetData()
{
da=new SqlDataAdapter("Select * From tblUsers",cn);
da.Fill(ds,"users");
da.SelectCommand=new SqlCommand("Select * From tblMessages",cn);
da.Fill(ds,"msgs");
dv=ds.Tables[1].DefaultView;
this.DataGrid1.DataSource = ds.Tables[0].DefaultView;
this.DataGrid1.DataBind();
}حتى الان ستظهر لنا الداتا جريد و بها بيانات المستخدمين و هنا تفاصيل الداتا جريد
<asp:datagrid id="DataGrid1" runat="server" AutoGenerateColumns="False" BorderColor="#DEBA84" BorderStyle="None" BorderWidth="1px" BackColor="#DEBA84" CellPadding="3" CellSpacing="2" Width="176px"> <SelectedItemStyle Font-Bold="True" ForeColor="White" BackColor="#738A9C"></SelectedItemStyle> <ItemStyle ForeColor="#8C4510" BackColor="#FFF7E7"></ItemStyle> <HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#A55129"></HeaderStyle> <FooterStyle ForeColor="#8C4510" BackColor="#F7DFB5"></FooterStyle> <Columns> <asp:BoundColumn DataField="login"></asp:BoundColumn> <asp:TemplateColumn> <ItemTemplate> <asp:DropDownList ID="drop" Runat="server"></asp:DropDownList> </ItemTemplate> </asp:TemplateColumn> <asp:ButtonColumn Text="Display" CommandName="Display"></asp:ButtonColumn> </Columns> <PagerStyle HorizontalAlign="Center" ForeColor="#8C4510" Mode="NumericPages"></PagerStyle> </asp:datagrid>
نجد أننا أدرجنا في العمود الثاني أداة DropDownList و أسميناها drop .. و لكن دعونا نفكر بشكل صحيح كيف سنربطها؟ سنجد أنه أمر معقد أن نقوم بربطها عند ربط الداتا جريد أول مرة داخل الطريقة GetData و لكن نحن نعلم أننا أنشأنا DataView تحمل إسم dv و تستطيع التأثير على جدول الرسائل سواء فلترة ترتيب أو بحث و طبعا من لا يملك فكرة عن موضوع ال DataView سيجد لها شرحا وافقا هنا Http://www.as4web.com .
دعونا نبسط الأمور .. كيف ستتم عملية الربط هذه و أنا أعلم أنه يوجد أكثر من مستخدم للتطبيق؟
الجواب سيكون أنه يجب ان نربط كل قائمة منسدلة تخص مستخدم فقط عند إضافة عمود المستخدم للداتا جريد و هذا يجعلنا نتجه بالتفكير للحدث ItemDataBound و هذا الحدث يتم تفعيله عند إضافة كل صف للداتا جريد.
إذا من هنا نستطيع ان نقوم بجلب مسجات المستخدم لوحده عند إضافة صفه للداتا جريد و نقوم بربطها في القائمة المنسدلة الخاصة برسائله.
دعوني أكتب هذا الحدث ثم أشرح ما به
private void DataGrid1_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
{
if(e.Item.ItemType==ListItemType.Item || e.Item.ItemType==ListItemType.AlternatingItem)
{
System.Web.UI.WebControls.DropDownList dl=new DropDownList();
dl=(DropDownList)e.Item.FindControl("drop");
dl.DataSource=this.GetMessages((string)DataBinder.Eval(e.Item.DataItem,"login"));
dl.DataTextField="title";
dl.DataBind();
}
}أولا قمنا بعمل شرط يبحث في الصفوف حتى يتجب ال Header وال Footer والتي لا تحوي على عنصر للقائمة المنسدلة و في حال تحقق الشرط سيتم تعريف قائمة منسدلة بإسم dl و كي نجعلها هي نفسها الخاصة بنفس الصف الذي سيظهر بيانات المستخدم استخدمنا e.Item.FindControl و مررنا لها اسم القائمة المنسدلة في منطقة ال HTML و كانت drop .
الان نستطيع التعامل مع القائمة المنسدلة dl على انها أداة عادية لها خصائص مثل DataSource و DataBind و سنجعل مصدر البيانات هو
this.GetMessages((string)DataBinder.Eval(e.Item.DataItem,"login"));
ربما سيشعر البعض بنوع من التعقيد ولكن دعونا نبسط الأمور ..
قمت بعمل دالة من نوع dataview تعيد لنا ال dv ولكن بعد فلترتها.. طبعا كيف سنقوم بفلترة جدول الرسائل؟ لو عدنا لقاعدة البيانات لوجدنا انه من خلال الحقل Sender يمكننا فعل ذلك.
توضيح :
عند استدعاء الحدث ItemDataBound يمكننا الوصول لإسم المستخدم من خلال
DataBinder.Eval(e.Item.DataItem,"login")
وبالتالي سنمرره لل DataView والتي ستفلتره حسب اسم المرسل من خلال الدالة Getmessages و التي تحوي هذا الكود
private DataView GetMessages(string filter)
{
dv.RowFilter = "Sender='" + filter + "'";
return dv;
}سنكون ربطنا ال DropDownList عند إضافة كل مستخدم برسائل هذا المستخدم.
بقي شيء وحيد ..
لنفرض أنه أضفنا زر عند الضغط عليه سيقوم بعرض الرسالة التي اخترتها من قائمة المستخدم المنسدلة فماذا نفعل؟
نقوم بإضافة زر و نجعل ال CommandName هو display و نفعل الحدث ItemCommand الخاص بالداتا جريد و نكتب به التالي :
private void DataGrid1_ItemCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e)
{
string msg;
msg=((DropDownList)e.Item.FindControl("drop")).SelectedItem.Value;
Response.Write(msg);
}أتمنى أن لا أكون قد جلبت لكم الصداع و تحياتي لكم دوما
محمد خليل أبو صلاح
هنا كود الصفحة كاملا :
public class test : System.Web.UI.Page
{
protected System.Web.UI.WebControls.DataGrid DataGrid1;
SqlConnection cn = new SqlConnection(System.Configuration.ConfigurationSettings.AppSettings["CnStr"]);
SqlDataAdapter da;
DataSet ds=new DataSet();
DataView dv;
private DataView GetMessages(string filter)
{
dv.RowFilter = "Sender='" + filter + "'";
return dv;
}
private void GetData()
{
da=new SqlDataAdapter("Select * From tblUsers",cn);
da.Fill(ds,"users");
da.SelectCommand=new SqlCommand("Select * From tblMessages",cn);
da.Fill(ds,"msgs");
dv=ds.Tables[1].DefaultView;
this.DataGrid1.DataSource = ds.Tables[0].DefaultView;
this.DataGrid1.DataBind();
}
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
this.GetData();
}
}
private void DataGrid1_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
{
if(e.Item.ItemType==ListItemType.Item || e.Item.ItemType==ListItemType.AlternatingItem)
{
System.Web.UI.WebControls.DropDownList dl=new DropDownList();
dl=(DropDownList)e.Item.FindControl("drop");
dl.DataSource=this.GetMessages((string)DataBinder.Eval(e.Item.DataItem,"login"));
dl.DataTextField="title";
dl.DataBind();
}
}
private void DataGrid1_ItemCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e)
{
string msg;
msg=((DropDownList)e.Item.FindControl("drop")).SelectedItem.Value;
Response.Write(msg);
}
}