Link to home
Start Free TrialLog in
Avatar of marko020397
marko020397

asked on

Access dinamically created controls in DataGrid after Button Click

Hello!

I have a DataGrid where users type in values or check checboxes. Every row of DataGrid has editing controls. Editing controls are added with dinamicaly created columns like this:

// Percentage column
tc = new TemplateColumn ();
tc.HeaderText = "Percent";
tc.ItemTemplate = new PercentageItemTemplate ();
tc.ItemStyle.HorizontalAlign = HorizontalAlign.Right;
tc.ItemStyle.CssClass = "text";
detailGrid.Columns.Add (tc);

// CheckBox column
tc = new TemplateColumn ();
tc.HeaderText = "Choose";
tc.ItemTemplate = new CheckboxItemTemplate ();
tc.ItemStyle.HorizontalAlign = HorizontalAlign.Left;
tc.ItemStyle.CssClass = "text";
detailGrid.Columns.Add (tc);

I put a Save button on the page. Event handler for this button should iterate through all rows in DataGrid.

foreach (DataGridItem item in detailGrid.Items)
{
  // do whatever you have to do with data written in DataGrid
}

The problem is that after I click Save button all values are gone. Bound columns which are defined in <asp:datagrid> tag stay in DataGrid also after the page is reloaded (Save button is clicked). All values and columns that are added programatically are gone. I also tried to declare TemplateColumn in <asp:datragrid> tag. Then I set ItemTemplate and other properties in program. The result was empty TemplateColumn. Again were all programatically altered values gone.

Should I add those values to StateBag? How?

Marko
Avatar of mmarinov
mmarinov

Hi,

when you create dynamically controls they are not included in the view state and when you submit the page the asp.net can not get them from viewstate to show them to to the user

the best practise is to recreate every time the dynamically created controls

other way is to add the dyncamically controls in the init event of the page - then they will be included in the view state and everything will work as you expected

Regards,
B..M
make sure to bind your datagrid in the following way:

if (!Page.IsPostBack)
{
  BindDataGrid();
}

After that you can access the selected dynamic control state easily.

HTH, Nauman.
Avatar of marko020397

ASKER

I am binding DataGrid the first time the page is loaded just like you wrote. When the page is reloaded (when I click "Save"), DataGrid is empty and I can't fill values with BindDataGrid because all values user has written will be lost.

Maybe I was not exact enough. The page is fine when it is loaded for the first time and all the data are ok. The problem is handling events. All dinamically added collumns are gone after reload/event handling.

Marko
mmarinov,

I can easily recreate dinamically created controls but all the values the user has written in are lost. How can I get the values the user has written in.

The second option you proposed is to add them in to Init event. How can I do this? Will I be able to get the values written by user?
You will need to rebind after you update your datasource for your recreated dynamically created controls to reflect this update.

Regards,

Aeros
if you choose the first scenario ( to recreate them ) then you will have to remove if (!IsPostBack) and create them on every visit
then the values will no be lost

for the second scenario take a look at this : http://support.microsoft.com/default.aspx?scid=kb;EN-US;317515

Regards,
B..M
ASKER CERTIFIED SOLUTION
Avatar of nauman_ahmed
nauman_ahmed
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
AerosSaga,

I will rebind the DataGrid after I update my data source. But how can I update my data source? I have no information what did user type in the DataGrid.
nauman ahmed,

I have also found the example you are offering me. Take a look at the source code in the question. Template column I need can not be made with Templatecolumn in asp:datagrid because it has special class defined in ItemTemplate property.
Heres my routine to accomplish this bear in mind mine are bound columns so you may need to make a few adjustments but you 'll get the underlying logic:

 Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        If Not IsPostBack Then
            Me.lblProductID.Text = CStr(Session("ProductID")).ToString
            Me.lblQuantity.Text = CInt(Session("Quantity")).ToString
            Me.lblSessionID.Text = CInt(Session("SessionID")).ToString
            Me.lblWeight.Text = CStr(Session("Weight"))
            Session("SessionID") = Me.lblSessionID.Text.ToString
            GetSelectedProductInfo()
            LoadProductData()
            CalculateTotal()
        End If
    End Sub
    Private Sub LoadProductData()
        Dim cnn As New OleDb.OleDbConnection(ConfigurationSettings.AppSettings("SiteDB"))
        Dim cmd As New OleDb.OleDbCommand
        cmd.CommandType = CommandType.Text
        cmd.CommandText = "SELECT TempSession.SessionID, TempSession.SessionString, TempSession.ProductID, TempSession.ProductName,TempSession.ProductPrice, TempSession.Quantity FROM TempSession " & _
                "WHERE SessionString = '" & Me.Session.SessionID & "'"
        cmd.Connection = cnn
        cnn.Open()
        dg.DataSource = cmd.ExecuteReader
        dg.DataBind()
        Me.HyperLink1.NavigateUrl = "ProductDetails.aspx?pid=" & lblProductID.Text.ToString
        Me.HyperLink1.Text = "Continue Shopping"
        Me.HyperLink2.NavigateUrl = "Checkout.aspx?SID=" & Me.Session.SessionID
        Me.HyperLink2.Text = "Proceed To Checkout"
        cnn.Close()
        cmd.Dispose()
        cnn.Dispose()
    End Sub
    Private Sub CalculateTotal()
        Dim cnn As New OleDb.OleDbConnection(ConfigurationSettings.AppSettings("SiteDB"))
        Dim cmd As New OleDb.OleDbCommand
        Dim dr As OleDb.OleDbDataReader
        Dim intQuantity As Integer
        Dim decPrice, decTotal, decTotalTemp As Decimal
        decTotal = 0
        cmd.CommandType = CommandType.Text
        cmd.CommandText = "SELECT * FROM TempSession WHERE SessionString = '" & Me.Session.SessionID.ToString & "';"
        cmd.Connection = cnn
        cnn.Open()
        dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
        While dr.Read()
            decPrice = CDec(dr.Item("ProductPrice"))
            intQuantity = CInt(dr.Item("Quantity"))
            decTotalTemp = decPrice * intQuantity
            decTotal = decTotalTemp + decTotal
        End While
        Me.lblOrderTotal.Text = CStr(decTotal).ToString
    End Sub
    Private Sub dg_DeleteCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles dg.DeleteCommand
        Dim cnn As New OleDb.OleDbConnection(ConfigurationSettings.AppSettings("SiteDB"))
        Dim cmd As New OleDb.OleDbCommand
        cmd.CommandType = CommandType.Text
        cmd.CommandText = "DELETE * FROM TempSession WHERE ProductID = " & e.Item.Cells(5).Text & " AND SessionString = '" & Me.Session.SessionID & "'"
        cmd.Connection = cnn
        cnn.Open()
        cmd.ExecuteNonQuery()
        cnn.Close()
        cmd.Dispose()
        cnn.Dispose()
        LoadProductData()
        CalculateTotal()
    End Sub
    Private Sub dg_EditCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles dg.EditCommand
        dg.EditItemIndex = e.Item.ItemIndex
        LoadProductData()
        CalculateTotal()
    End Sub
    Private Sub dg_UpdateCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles dg.UpdateCommand
        Dim cnn As New OleDb.OleDbConnection(ConfigurationSettings.AppSettings("SiteDB"))
        Dim cmd As New OleDb.OleDbCommand
        Dim intQuantity As String = CType(e.Item.Cells(3).Controls(0), TextBox).Text
        cmd.CommandType = CommandType.Text
        cmd.CommandText = "UPDATE TempSession SET Quantity = " & intQuantity.ToString & " WHERE SessionString LIKE '" & Me.Session.SessionID.ToString & "' AND ProductName LIKE '" & e.Item.Cells(2).Text & "'"
        cmd.Connection = cnn
        cnn.Open()
        cmd.ExecuteNonQuery()
        cnn.Close()
        cmd.Dispose()
        cnn.Dispose()
        dg.EditItemIndex = -1
        LoadProductData()
        CalculateTotal()
    End Sub
    Private Sub dg_CancelCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles dg.CancelCommand
        dg.EditItemIndex = -1
        LoadProductData()
        CalculateTotal()
    End Sub
    Private Sub GetSelectedProductInfo()
        Dim ProductID As String = Request.QueryString("ProductID")
        Dim cnn As New OleDb.OleDbConnection(ConfigurationSettings.AppSettings("SiteDB"))
        Dim cmd As New OleDb.OleDbCommand
        Dim dr As OleDb.OleDbDataReader
        cmd.CommandType = CommandType.Text
        cmd.CommandText = "SELECT * FROM Products WHERE ProductID = " & Me.lblProductID.Text
        cmd.Connection = cnn
        cnn.Open()
        dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
        While dr.Read
            Session("ProductID") = ProductID
            Session("Name") = dr.Item("Name")
            Session("Price") = dr.Item("Price")
            Session("Weight") = dr.Item("Weight")
        End While
        dr.Close()
        cmd.Dispose()
        cnn.Close()
        cnn.Dispose()
    End Sub

I have also found the nauman ahmeds example from www.c-sharpcorner.com before I was looking the solution on EE. Although the solution he proposed was not realy the right one, he gave me a clue and made me think. Finaly I realized I can do the same job with controls put on ASPX page and not created programaticaly.

As soon as the control is made programaticaly it doesn't transfer the values on submit. Here was nauman wrong when he suggested to make TemplateColumn and create contorols programaticaly.
Thanks marko that I was able to help you somehow :) Is it possible that you can write the approach you have selected so that members can refer to it in future?

Best, Nauman.