Stop Textbox in GridView Losing Data on Postback - asp.net

I have a GridView which I dynamically add rows to through the button_OnClick event, this adds a new row with the Product name & Product ID from a DropDownList and also contains a column with an empty text box for user input.
My problem is that when I test it and enter data in the text box, then add another Product, the post back causes my data to be lost (the correct number of rows are still there with product names / ids).
<asp:GridView runat="server" ID="grdSelectedProducts" BorderWidth="1px" CellPadding="3" CellSpacing="2" AutoGenerateColumns="False" OnRowDataBound="grdSelectedProducts_OnRowDataBound" ShowHeaderWhenEmpty="True" DataKeyNames="ProductId"
OnRowCommand="grdSelectedProducts_RowCommand" OnRowDeleted="grdSelectedProducts_RowDeleted" OnRowDeleting="grdSelectedProducts_RowDeleting" EmptyDataText="Please select a Product and click 'Add'" EnableViewState="True">
<Columns>
<asp:BoundField DataField="Product" HeaderText="Product" ReadOnly="False"/>
<asp:TemplateField HeaderText="Description">
<ItemTemplate>
<asp:TextBox runat="server" ID="txtDescriptionEntry" Text="" style="width:98% !important" EnableViewState="True"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton runat="server" ID="linkDelete" runat="server" CommandName="Delete" CommandArgument="<%# Container.DataItemIndex %>">Remove</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="ProductId" HeaderText="ProductId" ReadOnly="False" Visible="False" />
</Columns>
</asp:GridView>
How can I avoid postback scrapping the data on each txtDescriptionEntry that is created? There could be between 0 and an infinite number of these text boxes, so I won't have exact names at any one time.
Edit, as per a comment below I'm including the code for how I add rows to the grid:
private DataTable ProductDataTable
{
get {return ViewState["ProductDataTable"] as DataTable ?? new DataTable(); }
set { ViewState["ProductDataTable"] = value; }
}
private DataTable CreateDataTable(bool isAddingValue, string selectedProduct, string selectedId)
{
// if isAddingValue is FALSE then it isn't from a button click to add a Product, it is just
// a call to create the datatable
DataTable dataTable = ProductDataTable;
if (!dataTable.Columns.Contains("Product"))
{
dataTable.Columns.Add("Product");
dataTable.Columns.Add("Description"); // This column is free format text that the user enters.
dataTable.Columns.Add("ProductId");
}
if (isAddingValue)
{
// Get the data from ViewState
//dataTable = ProductDataTable;
DataRow dataRow;
dataRow = dataTable.NewRow();
dataRow["Product"] = selectedProduct;
dataRow["ProductId"] = selectedId;
dataTable.Rows.Add(dataRow);
}
else
{
grdSelectedProducts.DataSource = null;
grdSelectedProducts.DataSource = ProductDataTable;
grdSelectedProducts.DataBind();
}
// Save the data back to ViewState
ProductDataTable = dataTable;
return dataTable;
}
protected void btnAddProduct_OnClick(object sender, EventArgs e)
{
string selectedProduct = ddlProduct.SelectedItem.Text;
string selectedId = ddlProduct.SelectedValue;
DataTable dataTable = CreateDataTable(true, selectedProduct, selectedId);
grdSelectedProducts.DataSource = dataTable;
grdSelectedProducts.DataBind();
}
protected void grdSelectedProducts_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
if (!string.IsNullOrEmpty(e.CommandArgument.ToString()))
{
int rowIndex = Convert.ToInt32(e.CommandArgument);
DataTable table = CreateDataTable(false, string.Empty, string.Empty);
table.Rows.RemoveAt(rowIndex);
grdSelectedProducts.DataSource = table;
grdSelectedProducts.DataBind();
}
}
}
And in the Page_Load event, if it isn't a PostBack there is also binding of an empty list
grdSelectedProducts.DataSource = new List<Products>();
grdSelectedProducts.DataBind();

I figured this out, not the nicest solution (so I probably wouldn't recommend it) but it got me out of a jam.
I used the OnRowDataBound event so for each row that was being bound to the table I would use the RowIndex to get the appropriate row in the DataTable, I would then assign the text box (also obtained via the index) the value from the DT. Example below.
protected void grdSelectedproducts_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowIndex > -1)
{
TextBox txtDescription = e.Row.FindControl("txtDescriptionEntry") as TextBox;
if (txtDescription != null)
{
DataTable dt = ProductDataTable;
DataRow row = dt.Rows[e.Row.RowIndex] as DataRow;
txtDescription.Text = row[1].ToString();
}
}
}

Related

how to change the gridview row value after button click event

I have a table in four columns see screenshot here:
But I need two columns in that table name and gender see screenshot here:
Display in this type but I have required after click the button row value will change in GridView button out side in GridView e.g. row value 1,2 can instead male and female that is my requirement.
You need to fetch that data from database in dataset or datatable and assign that as DataSource to the GridView and call DataBind on that GridView. Now in RowDataBound event compare the value and assign value to UI label / literal based on that.
Below is GridView in aspx page.
<asp:GridView runat="server" AutoGenerateColumns="false" ID="GridView1" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Employee Name">
<ItemTemplate>
<asp:Literal ID="ltrlEmpName" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Employee Gender">
<ItemTemplate>
<asp:Literal ID="ltrlEmpGender" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
In code behind, lets say you want to assign the datasource to this GridView in page load or any other method. Below will be its code. Note that in sample here I have taken dummy DataTable and filled values for simplicity, you need to fill that DataTable from db values.
protected void Page_Load(object sender, EventArgs e)
{
// Dummy data table below, that needs to be replaced by datatable / dataset fetched from database.
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("EmpName", typeof(string)));
dt.Columns.Add(new DataColumn("EmpGender", typeof(int)));
DataRow dr1 = dt.NewRow();
dr1["EmpName"] = "Romesh";
dr1["EmpGender"] = 1;
dt.Rows.Add(dr1);
DataRow dr2 = dt.NewRow();
dr2["EmpName"] = "Sandya";
dr2["EmpGender"] = 2;
dt.Rows.Add(dr2);
// Bind the datasource to gridview.
GridView1.DataSource = dt;
GridView1.DataBind();
}
protected void GridView1_RowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e)
{
if (e.Row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow)
{
System.Web.UI.WebControls.Literal ltrlEmpName = (System.Web.UI.WebControls.Literal)e.Row.FindControl("ltrlEmpName");
System.Web.UI.WebControls.Literal ltrlEmpGender = (System.Web.UI.WebControls.Literal)e.Row.FindControl("ltrlEmpGender");
// Bind employee name to its label.
ltrlEmpName.Text = Convert.ToString(DataBinder.Eval(e.Row.DataItem, "EmpName"));
// Bind employee gender to its label based on its value.
if (Convert.ToString(DataBinder.Eval(e.Row.DataItem, "EmpGender")) == "1")
{
ltrlEmpGender.Text = "Male";
}
else if (Convert.ToString(DataBinder.Eval(e.Row.DataItem, "EmpGender")) == "2")
{
ltrlEmpGender.Text = "Female";
}
else
{
ltrlEmpGender.Text = "Other";
}
}
}
You will get out as Table as below.

AspxGridView checkbox checked column value

I am using one aspxGridview where I used checkbox. Now I need when I check any of the row particular column value I should get in server side to complete my business logic.
Below is the gridview used:
<dx:ASPxGridView KeyFieldName="PracticeID" ID="ASPxGrd" runat="server" ClientInstanceName="grid"
ClientIDMode="AutoID" AutoGenerateColumns="false" Width="100%" OnSelectionChanged="ASPxGrd_SelectionChanged">
<Columns>
<dx:GridViewDataColumn VisibleIndex="0" Name="CheckBoxColumn">
<DataItemTemplate>
<dx:ASPxCheckBox ID="ASPxCheckBox1" runat="server" OnCheckedChanged="ASPxCheckBox1_CheckedChanged" AutoPostBack="true">
</dx:ASPxCheckBox>
</DataItemTemplate>
</dx:GridViewDataColumn>
<dx:GridViewDataColumn FieldName="PracticeName" Caption="Description" VisibleIndex="1">
<FooterTemplate>
Total:
</FooterTemplate>
</dx:GridViewDataColumn>
</dx:ASPxGridView>
I have tried to use oncheckedevent in checkbox with auto postback true and used code to get selected row like below:
protected void ASPxCheckBox1_CheckedChanged(object sender, EventArgs e)
{
ASPxGridView grid = sender as ASPxGridView;
string currentMasterKey = Convert.ToString(grid.GetMasterRowKeyValue());
}
but getting null value of grid object.
Need help.
In your example you have used DataItemTemplate, so in that case the sender will be the control which is added in that data template i.e ASPxCheckBox and you are casting it to grid bcoz of that it is getting null.
try out below snippet.
protected void ASPxCheckBox1_CheckedChanged(object sender, EventArgs e)
{
ASPxCheckBox checkBox = sender as ASPxCheckBox;
var grid = (checkBox.NamingContainer as DevExpress.Web.ASPxGridView.GridViewDataItemTemplateContainer).Grid;
string currentMasterKey = Convert.ToString(grid.GetMasterRowKeyValue());
}
I found this answer before and it's working fine like below:
for (int i = 0; i < ASPxGrd.VisibleRowCount; i++)
{
ASPxCheckBox chk = ASPxGrd.FindRowCellTemplateControl(i, null, "ASPxCheckBox1") as ASPxCheckBox;
if (chk.Checked)
{
if (i == 0)
{
practiceName = ASPxGrd.GetRowValues(i, "PracticeName").ToString();
}
}
}
using this code i am able to get selected checkbox column value.

how to delete a row in gridview if using template field

I have tried so many times but i am not able to delete a row in GRID VIEW. I didn't create any database.I am just storing all the values of the text field in the GRID VIEW.If i want to delete a row in the GRID VIEW using template field button means,what will be the solution.
This is the way i am storing and populating values in GridView.
DataSet ds = new DataSet();
DataRow dr = ds.Tables[0].NewRow();
dr[0] = lbltxtcustomer.Text;
dr[1] = FNtxt.Text;
dr[2] = LNtxt.Text;
dr[3] = DrpdownMonth.Text + "/" + DrpdownDay.Text + "/" + DrpdownYear.Text;
dr[4] = lbltxtage.Text;
dr[5] = txtEmail.Text;
dr[6] = TxtPhone.Text;
dr[7] = Txtlocation.Text;
ds.Tables[0].Rows.Add(dr);
BindGrid()
;
Try This
HTML Markup
Below is the HTML Markup of the APS.Net GridView. Here I am making use the CommandFieldand OnRowDeleting event to delete the GridView Row. Hence I will apply the JavaScript Confirmation Box to the CommandFieldDelete Button itself.
<asp:GridView ID="GridView1" CssClass = "Grid" runat="server" OnRowDeleting="OnRowDeleting" AutoGenerateColumns = "false" OnRowDataBound = "OnRowDataBound">
<Columns>
<asp:BoundField DataField="Item" HeaderText="Item" />
<asp:BoundField DataField="Price" HeaderText="Price" />
<asp:CommandField ShowDeleteButton="True" ButtonType="Button" />
</Columns>
</asp:GridView>
Applying the JavaScript Confirmation Box to the GridView CommandField
Delete Button
To apply the JavaScript Confirmation Box, I am looking for the Button in the Controls of the GridView Cell Index 2 since it has the CommandField. Once
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string item = e.Row.Cells[0].Text;
foreach (Button button in e.Row.Cells[2].Controls.OfType<Button>())
{
if (button.CommandName == "Delete")
{
button.Attributes["onclick"] = "if(!confirm('Do you want to delete " + item + "?')){ return false; };";
}
}
}
}
Delete the ASP.Net GridView Row using CommandField and OnRowDeleting
event
Below is the code to delete the ASP.Net GridView Row using OnRowDeleting event
protected void OnRowDeleting(object sender, GridViewDeleteEventArgs e)
{
int index = Convert.ToInt32(e.RowIndex);
DataTable dt = ViewState["dt"] as DataTable;
dt.Rows[index].Delete();
ViewState["dt"] = dt;
BindGrid();
}

Need help in radiobutton within gridview

Thru radio button i am selecting the data from gridview. Here all radio buttons are selectable at a time. Actually it should not happen at a time user can select only one button which i could not do. My second problem is when i am selecting particular radiobutton that details should be displayed in text box. I have Itemid, ItemName, Quantity, Rate and Total field in gridview. These values i have inserted thru textbox so i have all the corresponding text box for all. So once i select particular radiobutton those details should be displayed in corresponding textbox. I have done the insertion coding for this but couldn't do selecting thru radiobutton and dispalying in textbox. Pls somebody help me in coding for this problem.
Thanks,
sumit
Sumit,
Don't use the html control, use the asp control:
<asp:RadioButton ID="RadioSelector" runat="server" GroupName="RadioSelectors" />
I had a similar problem in an ASP.NET class, and I followed this tutorial which worked perfectly.
Sounds like the classic master/detail pattern see here:
Tutorial 10: Master/Detail Using a Selectable Master GridView with a Details DetailView
You are fighting the intended workings of ASP.NET databound controls by using radio buttons. I don't like having select links either they're not exactly Web 2.0! but they can be quite easily replaced with a row click by doing this (or variation of same):
Select a row in an asp:GridView without using a Select Command
I read several articles on the net but none were suitable. I finally figured out my own solution without using either HTMLControls radiobutton nor using Javascript. This works for my requirement.
My Gridview html settings were as follows
<asp:GridView ID="grdVersion" runat="server"
AutoGenerateColumns="false" AllowPaging="true"
AutoGenerateEditButton="false" PageSize="10" Width="400px"
EmptyDataText="No records available."
OnRowDataBound="grdVersion_RowDataBound"
AutoGenerateSelectButton="false">
<Columns>
<asp:BoundField DataField="versionid" HeaderText="Version No." ItemStyle-Width="50px"
ItemStyle-Wrap="false" HtmlEncode="true" ReadOnly="true" />
<asp:BoundField DataField="version_date" HeaderText="Version Date" ItemStyle-Width="100px"
ItemStyle-Wrap="false" HtmlEncode="true" ReadOnly="true" />
<asp:BoundField DataField="remarks" HeaderText="Remarks" ItemStyle-Width="150px"
ItemStyle-Wrap="true" HtmlEncode="true" ReadOnly="true" />
**<asp:TemplateField HeaderText="Admin" HeaderStyle-Width="100px">
<ItemTemplate>
<asp:RadioButton ID="rdCurrent" runat="server"
Checked="false" Enabled="true" GroupName="rgVersion"
AutoPostBack="true"
OnCheckedChanged="rdCurrent_CheckChanged" />
</ItemTemplate>**
</asp:TemplateField>
</Columns>
</asp:GridView>
The server code (C#) was as follows,
DataTable dtDataSpaceVersions; //place this inside the codebehind page class
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dtDataSpaceVersions = ListDataSpaceVersions();
ViewState["dtDataSpaceVersions"] = dtDataSpaceVersions;
PopulateGridVersion();
}
}
protected void PopulateGridVersion()
{
grdVersion.DataSource = dtDataSpaceVersions;
grdVersion.DataBind();
}
protected void rdCurrent_CheckChanged(object sender, EventArgs e)
{
Control selectedVersion = ((Control)sender).Parent;
if (ViewState["dtDataSpaceVersions"] != null)
dtDataSpaceVersions = (DataTable)ViewState["dtDataSpaceVersions"];
foreach (DataRow dtr in dtDataSpaceVersions.Rows)
{
if (dtr["versionid"].ToString() == ((System.Web.UI.WebControls.GridViewRow)selectedVersion.Parent).Cells[0].Text)
dtr[3] = "Y";
else
dtr[3] = "N";
}
PopulateGridVersion();
}
protected void grdVersion_RowDataBound(object sender, GridViewRowEventArgs e)
{
DataRowView drv;
if (e.Row.RowType == DataControlRowType.DataRow && e.Row.DataItem != null)
{
drv = (DataRowView)e.Row.DataItem;
if ((RadioButton)(e.Row.FindControl("rdCurrent")) != null)
if (drv.Row.ItemArray[3].ToString() == YesNo.N.ToString())
((RadioButton)(e.Row.FindControl("rdCurrent"))).Checked = false;
else
((RadioButton)(e.Row.FindControl("rdCurrent"))).Checked = true;
//setGridUserPermissionCheckBoxState(e.Row, drv);
}
}
public DataTable ListDataSpaceVersions()
{
string sql = string.Empty;
DataTable dt = new DataTable();
dt.Columns.Add("versionid", typeof(String));
dt.Columns.Add("version_date", typeof(String));
dt.Columns.Add("remarks", typeof(String));
dt.Columns.Add("is_current", typeof(String));
DataRow dtr;
dtr = dt.NewRow();
dtr[0] = "1.1";
dtr[1] = "12-Dec-2005";
dtr[2] = "Campaign Information";
dtr[3] = "N";
dt.Rows.Add(dtr);
dtr = dt.NewRow();
dtr[0] = "1.2";
dtr[1] = "06-Mar-2006";
dtr[2] = "Sales corrections";
dtr[3] = "N";
dt.Rows.Add(dtr);
dtr = dt.NewRow();
dtr[0] = "1.3";
dtr[1] = "24-Aug-2009";
dtr[2] = "Invoice reconciliation";
dtr[3] = "Y";
dt.Rows.Add(dtr);
dtr = dt.NewRow();
dtr[0] = "1.4";
dtr[1] = "30-May-2010";
dtr[2] = "Invoices verification";
dtr[3] = "N";
//dtr[0][0] = "";
dt.Rows.Add(dtr);
return dt;
}

GridView FindControl returns null when HeaderText is set

I have a GridView...
<asp:GridView EnableViewState="true"
ID="grdResults"
runat="server"
CssClass="resultsGrid"
OnRowDataBound="grdResults_OnRowDataBound"
AutoGenerateColumns="false"
HeaderStyle-CssClass="header"
OnRowCommand="grdResults_OnRowCommand">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Label ID="lblView"
runat="server"
Visible="false"
Text="View">
</asp:Label>
<asp:HyperLink ID="hypEdit"
runat="server"
Visible="false"
Text="(Edit)"
CssClass="edit">
</asp:HyperLink>
<asp:LinkButton ID="btnDelete"
runat="server"
Visible="false"
Text="(Delete)"
CssClass="delete"
CommandName="DeleteItem"
OnClientClick="return confirm('Are you sure you want to delete?')">
</asp:LinkButton>
<asp:HyperLink ID="hypSelect"
runat="server"
Visible="false"
Text="(Select)"
CssClass="select">
</asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
This has one static column containing a label two hyperlinks and a link button and also has a number of dynamically generated columns...
private void SetupColumnStructure(IEnumerable<string> columnNames)
{
var columnNumber = 0;
foreach (var columnName in columnNames)
{
var templateColumn = new TemplateField
{
ItemTemplate = new CellTemplate(columnName)
};
grdResults.Columns.Insert(columnNumber, templateColumn);
columnNumber++;
}
}
As part of the OnRowDataBound handler I retrieve one of the controls in the statically column and set some attributes on it...
protected void grdResults_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
.
.
.
var row = e.Row;
var rowData = row.DataItem as Dictionary<string, object>;
if (rowData != null)
{
if ((bool)rowData[displayEditLink])
{
var hypEdit = (HyperLink)row.FindControl("hypEdit");
hypEdit.NavigateUrl = "~/Pages/Edit.aspx?action=Edit&objectType=" + rowData[objectTypeLiteral] + "&id=" + rowData[objectIdLiteral];
hypEdit.Visible = true;
}
}
.
.
.
}
This all works fine but no column names are displayed. So I then modify the SetupColumnStructure method so that the HeaderText is set on the template field like this...
private void SetupColumnStructure(IEnumerable<string> columnNames)
{
var columnNumber = 0;
foreach (var columnName in columnNames)
{
var templateColumn = new TemplateField
{
ItemTemplate = new CellTemplate(columnName),
HeaderText = columnName
};
grdResults.Columns.Insert(columnNumber, templateColumn);
columnNumber++;
}
}
For some reason this one extra line change causes the row.FindControl("hypEdit"); call in the OnRowDataBound handler to return null.Can anyone see something im missing here or has anyone experienced a similar issue?
UPDATE
I've made sure that I'm not referring to a header or footer row here. Also, if I step over the object reference exception this occurs for every item that is in the DataSource.
Not sure if this helps, but as I expected, when I stepped through the code the table has generated all the columns expected but all cells (DataControlFieldCells) contain no controls when the HeaderText is set, yet all expected controls when it isnt set.
All very strange. Let me know if you can spot anything else.
When you added the HeaderText, a new RowType was added to the gridview. You'll need to check what type of row raised the OnRowDataBound event and take the appropriate action. In your case, just checking if the e.Row.RowType is a DataRow should solve your problem:
protected void grdResults_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
if ((bool)rowData[displayEditLink])
{
var hypEdit = (HyperLink)row.FindControl("hypEdit");
hypEdit.NavigateUrl = "~/Pages/Edit.aspx?action=Edit&objectType=" + rowData[objectTypeLiteral] + "&id=" + rowData[objectIdLiteral];
hypEdit.Visible = true;
}
}
}
Its because the control you are searching for is contained within another control. FindControl() does not look inside control collections of controls. You will need to write a recursiveFindControl() method.
Hope this helps a little!

Resources