分享
 
 
 

Multi-row Editing in the ASP.NET DataGrid...

王朝asp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

Multi-row Editing in the ASP.NET DataGrid...

This articles demonstrates how you can have multiple datagrid rows available for editing at one time, not just the one row you are normally limited to.

By: John KilgoShajahan Kakkattil ("Shaji")

Date: August 28, 2003
Download the code.
Printer Friendly Version

Introduction

The ASP.NET DataGrid is a vital part of .Net web programming and is the highly discussed control among news groups and discussion forums. No wonder Microsoft has a newsgroup (dotnet.framework.aspnet.datgridcontrol) solely devoted for the datagrid!

You can use the datagrid to display as well as to edit data. The default in-place editing is a cool feature of the datagrid but it is restricted to edit and update one row at a time by enabling the "EditItemIndex" property and by handling EditCommand, UpdateCommand and CancelCommand to intiate edit, update and cancel editing respectively. Obviously there are limitations to enable windows form or excel style editing as far as the web application development is concerned.

However, in real life scenarios we may face situations where we really need to enable multi row editing, but without losing the easiness of coding with asp.net server controls.

This tutorial discusses a technique to enable the datagrid for multi row editing.

Scenario

Suppose that we have a web form which allows candidates to update their resume details, something like a wizard which collects the relevant information in each step. One of the intermediate steps is say, entering the work experience details of the candidate. This is a set of line entries in which the candidate can enter any number of rows which he needs, and can come back and edit it on the fly.

We are using a data grid to do this with multi row editing facility.

The technique

Before jumping to the implementation details of this scenario, let me put up how we are achieving this for those who are so curious. As mentioned earlier, we cannot use the default "EditItemIndex" property here because it can be set only to a single row. If it set to multiple rows the last row will override the others and only the last row will be in edit mode.

Here, we use "template columns" for all the editable columns as in the normal inplace editing. But the difference is we don't use the "EditItemTemplate", instead the "ItemTemplate" itself is used for item editing. Appropriate edit controls (textbox, combo box, check box, etc.) will be placed in the "ItemTemplate" of the template column. Then bind the datagrid with the datasource and display the data in the template columns. So, upon displaying the grid in the browser all rows will be rendered with editing controls and the data can be entered/edited and posted back to the server.

Things are straight forward up to this point, but how do we get back the edited data and merge with the data set? That is DataGrid.DataBind set the data to the datagrid, but we need to get back the data from the grid to the dataset after the user edited the data. Yes we need the reverse process of the DataGrid.DataBind…...maybe DataGrid.ReverseBind! But unfortunately datagrid does not support anything as such.

If there is nothing built-in, then we build up! But it is easy, loop thru each rows and collect the data back. Here is the code snippet that implements "ReverseBind" for the application which we are going to build.

Public Sub ReverseBind()

'This function is the heart of this application.

'It reads each grid rows,get the edited data

'and serialize back to the dataset.

'Yes the reverse process of "datagrid.databind", hence the name.

'The grid row

Dim gridrow As DataGridItem

'Typed data set row

Dim datarow As Dataset1.WorkExperianceDataRow

'Loop thru each grid row and synchronize the edited data

'with the corresponding data set.

'In this demo the typed data set has a one to one mapping

'with the templated columns for the sake of simplicity.

For Each gridrow In DataGrid1.Items

'"DatsetIndex" property of the gridrow gives the

'refernce to the datrow used for binding

datarow = _dataSet.WorkExperianceData(gridrow.DataSetIndex)

'get the data from grid row element and update the column in the 'data row

datarow.ExperiancePeriod = CType(gridrow.FindControl("ExperiancePeriod"), TextBox).Text

'(Note:the hardcoded control names is not a good programming 'practice, better to use

'a constant instead.)

'reverse bind the other fields

datarow.TotalYears = CShort(CType(gridrow.FindControl("TotalYears"), TextBox).Text)

datarow.CompanyName = CType(gridrow.FindControl("CompanyName"), TextBox).Text

datarow.JobDescription = CType(gridrow.FindControl("JobDescription"), TextBox).Text

'Update the data tabe with new values.

_dataSet.WorkExperianceData(gridrow.DataSetIndex).ItemArray = datarow.ItemArray

Next

End Sub

Please note that the datagrid in question is DataGrid1 and the DataSource is "Dataset1.WorkExperianceData" which is a typed dataset table with 4 columns (ExperiancePeriod, TotalYears, CompanyName, JobDescription). Also, the datagrid has template columns to edit these fields respectively.

The key point here is getting the reference of the dataset row used for binding each row, then updating the datarow with the edited data. In the above mentioned code snippet it is done by the following code

datarow = _dataSet.WorkExperianceData(gridrow.DataSetIndex)

Where, "_dataSet" is a form level variable which holds the typed dataset with work experience data.

Demo application

Let us have a look at how this is implemented in this demo application. It demonstrates the multi row data entry for the "work experience" data entry scenario. When the form first loads the grid shows a set of rows in edit mode with some initialization data. The existing data can be edited and deleted; also new rows can be added. You can add multiple rows at a time by specifying the number of rows to add. Also the paging is enabled, so during editing you can navigate thru the pages before making the final update by clicking the "Update" button.

Controls

Following are the main server controls used in the application. "DataGrid1" is used for entering and editing the data. The definition of DataGrid1 is as follows:

<asp:datagrid id="DataGrid1" runat="server" AutoGenerateColumns="False" PageSize="5" AllowPaging="True">

<Columns>

<asp:TemplateColumn HeaderText="Period">

<ItemTemplate>

<asp:TextBox id="ExperiancePeriod" runat="server"></asp:TextBox>

</ItemTemplate>

</asp:TemplateColumn>

<asp:TemplateColumn HeaderText="No of Years">

<ItemTemplate>

<asp:TextBox id="TotalYears" runat="server" Width="70px"></asp:TextBox>

<asp:CompareValidator id="CompareValidator1" runat="server" Type="Integer"

Operator="DataTypeCheck" ControlToValidate="TotalYears"

ErrorMessage="No of Years - Numeric value expected">!

</asp:CompareValidator>

</ItemTemplate>

</asp:TemplateColumn>

<asp:TemplateColumn HeaderText="Name of the Company">

<ItemTemplate>

<asp:TextBox id="CompanyName" runat="server" Width="256px"></asp:TextBox>

</ItemTemplate>

</asp:TemplateColumn>

<asp:TemplateColumn HeaderText="Job Description">

<ItemTemplate>

<asp:TextBox id="JobDescription" runat="server" Width="224px"></asp:TextBox>

</ItemTemplate>

</asp:TemplateColumn>

<asp:TemplateColumn HeaderText="Delete">

<ItemTemplate>

<asp:LinkButton id="DeleteRow" runat="server">X</asp:LinkButton>

</ItemTemplate>

</asp:TemplateColumn>

</Columns>

<PagerStyle NextPageText="Next" PrevPageText="Previous"

HorizontalAlign="Center" Mode="NumericPages">

</PagerStyle>

</asp:datagrid>

"DataSet1" is a typed dataset having a table with 4 fields.

[Note:Headers omitted for simplicity]

<xs:element name="Dataset1" msdata:IsDataSet="true">

<xs:complexType>

<xs:choice maxOccurs="unbounded">

<xs:element name="WorkExperianceData">

<xs:complexType>

<xs:sequence>

<xs:element name="ExperiancePeriod" type="xs:string" minOccurs="0" />

<xs:element name="TotalYears" type="xs:short" minOccurs="0" />

<xs:element name="CompanyName" type="xs:string" minOccurs="0" />

<xs:element name="JobDescription" type="xs:string" minOccurs="0" />

</xs:sequence>

</xs:complexType>

</xs:element>

</xs:choice>

</xs:complexType>

</xs:element>

Other Controls

AddRows; Link button to add additional rows

Save; Command button. The data is not saved to anywhere instead it is displayed in "DataGrid2" in read-only mode

DataGrid2; datagrid to show the edited data.

The important methods and event handlers are explained below. For the full listing please refer to the source code of the application provided with this tutorial.

Page_Load Event

Initialize the data and bind the grid if the page is loading for the first time. We are using a stub method "InitializeData" for loading the data with some values for the first time. On each post back the data is binding back to the data set from the grid by calling "ReverseBind()".

Private Sub Page_Load(ByVal ………..) Handles MyBase.Load

'Put user code to initialize the page here

If Not IsPostBack Then

'Load the data for the first time

InitializeData()

BindGrid()

Else

'Get the edited data, and populate back to the data holder

' (dataset)

ReverseBind()

End If

End Sub

InitializeData

Loading some start up data.

Private Sub InitializeData()

'Initializing the data for the first time.

'This is just a "stub" to load some startup data for demo purpose only.

'Normally the data will be loaded from data provider (database) or it can be empty initially.

With _dataSet.WorkExperianceData

.AddWorkExperianceDataRow("1/Jan/1988 to 31/Dec/2000", 3, "IBM", "Bulding IBM Mainframe systems")

etc……

etc……

End With

End Sub

LoadViewState / SaveViewState

The edited data collected from the grid is stored in the dataset, and the dataset is persisted in a viewstate variable called "data". Again, you can implement your own logic to persist the data, but using the viewstate is ideal in most situations, provided that the dataset is not so huge. For the database programmers, if the underlying dataset is huge then it is better to use a custom dataset to collect required data from the user, then load it back to the dataset representing your database tables before making a database update.

To enable the viewstate variable as our temporary data store the "LoadViewstate" and "SaveViewState" are overridden as follows.

Protected Overrides Sub LoadViewState(ByVal savedState As Object)

MyBase.LoadViewState(savedState)

'Get the dataset from the viewstate. This is the data before last editing

If (Not Me.ViewState("Data") Is Nothing) Then

_dataSet = CType(Me.ViewState("Data"), Dataset1)

End If

If (Not Me.ViewState("LastEditedPage") Is Nothing) Then

'Just a variable to keep the last edited page index for the purpose of this application

_lastEditedPage = CType(Me.ViewState("LastEditedPage"), Integer)

End If

End Sub

Protected Overrides Function SaveViewState() As Object

'The datset used for editing needs to be persisted across postbacks.

'The performance will be affected if the dataset is huge in size.Please

'refer the tutorial for more details

Me.ViewState("Data") = _dataSet

Me.ViewState("LastEditedPage") = _lastEditedPage

Return (MyBase.SaveViewState())

End Function

Addrow_click

Adding new rows to the application. This is the event handler of command button "AddRow".

Private Sub AddRow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddRow.Click

'Add the number of rows specified by "RowCount" to grid

If (IsNumeric(RowCount.Text)) Then

Dim i As Integer

For i = 1 To CInt(RowCount.Text)

'Adding a blank record to the dataset.

_dataSet.WorkExperianceData.AddWorkExperianceDataRow("", 0, "", "")

'In our case the typed datset has only a few fileds, so that it is

'easy to pass the default data as arguments. If there are many

'fields (that is the case usually in real life scenarios)

'instatiate a data row and load initialization data one by one. Then

'plug it into the data table.

'You can even pass blank row with out initialization data, but in

'that case you need to handle "DBNull" situation during grid row

'binding either by checking "IsDBNull" or by

'setting default value property for the field in the the dataset.

Next

End If

'Rebind the grid to show the newly added row(s).

BindGrid()

End Sub

DataGrid1_ItemDataBound

Nothing special, simply populating the templated controls with data during grid bind.

Private Sub DataGrid1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles DataGrid1.ItemDataBound

'This event handler is executed once per each row of the datagrid

'while binding the dataset records.

'The templated controls get populated with data here from

'the "workexperiance" data table

If (e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem) Then

Dim datarow As Dataset1.WorkExperianceDataRow

datarow = CType(CType(e.Item.DataItem, DataRowView).Row, Dataset1.WorkExperianceDataRow)

CType(e.Item.FindControl("ExperiancePeriod"), TextBox).Text = datarow.ExperiancePeriod

CType(e.Item.FindControl("TotalYears"), TextBox).Text = datarow.TotalYears.ToString

CType(e.Item.FindControl("CompanyName"), TextBox).Text = datarow.CompanyName

CType(e.Item.FindControl("JobDescription"), TextBox).Text = datarow.JobDescription

End If

End Sub

There are couple of other methods also to complete the functionality of the application but are not worth mentioning here. See the "WebForm1.aspx" for a complete code listing.

Conclusion

This is not a ready made solution suitable for all multi-row data editing requirements, but the technique can be adopted for many situations. I think there are only minor changes required for Microsoft to enable multi-row editing in the grid control. For instance, by providing a property called "EnableEditing" at the row level, and if it is true that row should be rendered using "ItemEditTemplate". Also the Update and cancel Edit commands should be provided in the grid level, not in the row level. Upon postback itemUpdate event should be raised for each row which had the "EnableEditing" set to true. The data can be read back from the grid at this point, the exact reverse process of ItemDataBound event handler. Let me see if I can mange to customize the grid to enable this, I will surely get back here if can.

You may run the program here.

You may download the code here.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有