Insert a new Item to a GridView using an ObjectDataSource and the EditItemTemplate

12 ביוני 2008

8 תגובות

Click here for the English Version

GridView לא מגיע עם תמיכה מובנית להוספת שורה חדשה של נתונים בתוך הפקד בצורה הבאה: 


הפתרונות שבדרך כלל מוצעים ברשת מדברים על הוספת הנתונים בדף נוסף/DIV צף… ז"א מחוץ לgrid או הוספת TextBoxes וכפתור עם אירוע שמירה מתאיםב Header או Footer (דוגמא מפורטת להוספת השדות בצורה זו)


הבעיות עם הפתרון לעיל: 




  1.  ה grid תמיד נטען במצב של אפשרות הכנסה של איבר חדש = רעש מיותר כאשר המשתמש רק צופה בנתונים.


  2. שכפול של פקדים שכבר נמצאים ב EditItemTemplate.


  3. ייתכן שצריך לבצע פעולות אחרות ב Header/Footer.

ניתן להשיג את התוצאה המבוקשת גם ע"י שימוש פשוט ב EditItemTemplate בצורה הבאה:


<asp:Button ID="btnInsert" runat="server" OnClick="btnInsert_Click" Text="Add new item" />
<asp:GridView ID="GridView1" runat="server" AllowSorting="true" DataKeyNames="pkDataId"
AutoGenerateColumns="False" DataSourceID="ods1" OnRowCancelingEdit="GridView1_RowCancelingEdit">
<Columns>
<asp:CommandField ShowEditButton="True" UpdateText="Save" />
<asp:TemplateField SortExpression="someData" HeaderText="someData">
<ItemTemplate>
<asp:Label ID="lblDescription" runat="server" Text='<%# Eval("someData") %>' />
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txbDescription" runat="server" Text='<%# Bind("someData") %>' />
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ods1" runat="server" SelectMethod="GetMyData" TypeName="BL.TestMock"
InsertMethod="AddMyData" UpdateMethod="SaveMyData" OnUpdating="ods1_Updating">
<SelectParameters>
<asp:Parameter Name="bNew" Type="Boolean" DefaultValue="false" />
</SelectParameters>
<InsertParameters>
<asp:Parameter Name="someData" Type="String" />
</InsertParameters>
<UpdateParameters>
<asp:Parameter Name="someData" Type="String" />
</UpdateParameters>
</asp:ObjectDataSource>


 


מה שמעניין בקוד לעיל זה ה SelectParameter שהוספתי bNew שבעצם יקבע מתי נוסיף שורה ריקה בראש ה dataSource שלנו.


ב CodeBehind: 


/// change to InsertMode so the Select Method will add a new row   
/// to the beginning of the DataSource
protected void btnInsert_Click(object sender, EventArgs e)
{
ods1.SelectParameters["bNew"].DefaultValue = "true";
GridView1.EditIndex = 0;
}

protected void ods1_Updating(object sender, ObjectDataSourceMethodEventArgs e)
{
//check if we are updating in New mode
if (Convert.ToBoolean(ods1.SelectParameters["bNew"].DefaultValue))
{
//set all the Insert Parameters from the e.InputParameters
ods1.InsertParameters["someData"].DefaultValue = e.InputParameters["someData"].ToString();
ods1.Insert();
e.Cancel = true;
ods1.SelectParameters["bNew"].DefaultValue = "false"; //return to regular mode
}
}

protected void GridView1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
ods1.SelectParameters["bNew"].DefaultValue = "false";
}


 


 


באירוע של הוספת שורה נשנה את הערך של bNew ונעביר את ה grid למצב של Edit על השורה הראשונה.


בתוך BL.TestMock (ה ObjectDataSource מחובר אליו) הפונקציה המעניינת היא פונקצית ה Select: 


public static DataTable GetMyData(bool bNew)
{
DataTable theData = DataMgr.GetMyData();
if (bNew)
{
theData = theData.Copy();//assume we take the data from the cache
theData.Rows.InsertAt(theData.NewRow(), 0);
}
return theData;
}

פתרון זה טוב בעיקר לדפי Admin/דפים שבהם היעילות היא לא העיקר, כיוון שתמיש מרנדרים פה את כל ה Grid, ויעבוד טוב בתוך UpdatePanel כדי לתת חווית משתמש נחמדה.


כמובן שאפשר לעבוד עם Collection משלכם במקום DataTable.


וכדאי להשתמש ביכולת ה cache של ה ObjectDataSource כדי לשפר ביצועים.


משהו קטן לגבי WLW :




  • לכתוב בעברית ולשלב קוד לא בא לו כ"כ טוב, התוסף שמצאתי שותל ים זבל,


  • בשלב מסויים עורך ה HTML פשוט לא נתן לי להוסיף תווים כשרציתי ליישר לשמאל – יש הגבלה על מספר התווים?


  • אני מניח שהבעיה אצלי ולא אצלו, אבל מבחינת חווית כתיבה היה דיי סיוט.

אשמח לשמוע הערות/הארות.


English Version



GridView don't support inserting a new item at the first Line like the following way:


 



The common solutions, found on the web, suggest adding the new data at a new window or a container outside of the GridView – not a very user friendly way to add the data.


Another solution is to add the propper TextBoxes at the Header/Footer of the Grid + a propper Command Button for saving the data.


The problems with the Header/Footer solutions are:




  1. The TextBoxes for adding a new row are always loaded and ready to use when the Grid loads, which might be nice for some scenarios, but for most scenarios it is just plain noise.


  2. There is a duplication of these input controls at the Header/Footer (already located at the EditItemTemplate) + it's binding at every load

    We might need the Header/Footer space for other uses (like filtering)

We can obtain the desired result by a simple use of the EditItemTemplate in the following way:


<asp:Button ID="btnInsert" runat="server" OnClick="btnInsert_Click" Text="Add new item" />
<asp:GridView ID="GridView1" runat="server" AllowSorting="true" DataKeyNames="pkDataId"
AutoGenerateColumns="False" DataSourceID="ods1" OnRowCancelingEdit="GridView1_RowCancelingEdit">
<Columns>
<asp:CommandField ShowEditButton="True" UpdateText="Save" />
<asp:TemplateField SortExpression="someData" HeaderText="someData">
<ItemTemplate>
<asp:Label ID="lblDescription" runat="server" Text='<%# Eval("someData") %>' />
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txbDescription" runat="server" Text='<%# Bind("someData") %>' />
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ods1" runat="server" SelectMethod="GetMyData" TypeName="BL.TestMock"
InsertMethod="AddMyData" UpdateMethod="SaveMyData" OnUpdating="ods1_Updating">
<SelectParameters>
<asp:Parameter Name="bNew" Type="Boolean" DefaultValue="false" />
</SelectParameters>
<InsertParameters>
<asp:Parameter Name="someData" Type="String" />
</InsertParameters>
<UpdateParameters>
<asp:Parameter Name="someData" Type="String" />
</UpdateParameters>
</asp:ObjectDataSource>


The only interesting part at the code above is the "bNew" SelectParameter, which will determine when we will add a new empty item at the beginning of the DataSource


at the CodeBehind:


/// change to InsertMode so the Select Method will add a new row   
/// to the beginning of the DataSource
protected void btnInsert_Click(object sender, EventArgs e)
{
ods1.SelectParameters["bNew"].DefaultValue = "true";
GridView1.EditIndex = 0;
}

protected void ods1_Updating(object sender, ObjectDataSourceMethodEventArgs e)
{
//check if we are updating in New mode
if (Convert.ToBoolean(ods1.SelectParameters["bNew"].DefaultValue))
{
//set all the Insert Parameters from the e.InputParameters
ods1.InsertParameters["someData"].DefaultValue = e.InputParameters["someData"].ToString();
ods1.Insert();
e.Cancel = true;
ods1.SelectParameters["bNew"].DefaultValue = "false"; //return to regular mode
}
}

protected void GridView1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
ods1.SelectParameters["bNew"].DefaultValue = "false";
}


On the Event of Adding a new Row we will change the value of bNew, and set the EditIndex of the Grid to 0 for Editing the first row.


At BL.TestMock (which is the TypeName of the ObjectDataSource) the Select method holds the interesting part:


public static DataTable GetMyData(bool bNew)
{
DataTable theData = DataMgr.GetMyData();
if (bNew)
{
theData = theData.Copy();//assume we take the data from the cache
theData.Rows.InsertAt(theData.NewRow(), 0);
}
return theData;
}

This solution is good where the performance of the page is not critical(mostly admin pages) since we are performing a full postback and rendering the whole grid for every action (using paging might increase performance). Use it inside an UpdatePanel to get a better experience.


Hope this helps.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

8 תגובות

  1. Offir Shvartz12 ביוני 2008 ב 11:35

    הבלוג נראה מצויין עלה והצלח ןכן ירבו

    הגב
  2. אוהד אסטון13 ביוני 2008 ב 18:15

    מזל"ט על הבלוג החדש!

    הגב
  3. Avi Pinto13 ביוני 2008 ב 19:22

    תודה רבה :),
    לקח לי כמעט שמונה חודשים להתחיל לכתוב.
    מקווה שיהיה מעניין ומועיל.

    הגב
  4. שלום1 ביולי 2008 ב 15:43

    תתחדש על הבלוג.

    הגב
  5. John5 בנובמבר 2009 ב 14:50

    Thank you very much for explanation. It's good start point to begin build viewgrids with update and insert options. Your solution one of the best on Web

    הגב
  6. Avi Pinto5 בנובמבר 2009 ב 15:10

    Thanks John, happy you found it usefull

    הגב
  7. שלום26 בדצמבר 2010 ב 15:21

    מה זה ה DataMgr שבפונקציה ?.

    public static DataTable GetMyData(bool bNew)
    {
    DataTable theData = DataMgr.GetMyData();
    if (bNew)
    {
    theData = theData.Copy();//assume we take the data from the cache
    theData.Rows.InsertAt(theData.NewRow(), 0);
    }
    return theData;
    }

    תודה רבה

    הגב
  8. Avi Pinto26 בדצמבר 2010 ב 19:22

    היי שלום,
    DataMgr זה השירות שממנו אני מביא את המידע,
    לצורך העניין פה בדוגמא, אם אני לא טועה זו הייתה מחלקה סטטית שמחזירה dataTable סטטי – כך שבהדגמה המידע החדש מתווסף אליו.

    אבל זה בהחלט לא המימוש עבור מערכת production.

    ובכלל, מחמיא שפוסט כ"כ ישן זוכה להתייחסות.
    אם אתה לא חייב, ממליץ לך להתרחק כמו מאש מ gridView בכלל ומ objectDataSource בפרט.

    שיהיה בהצלחה

    הגב