change value of cell in gridview when in edit mode - c#

I have a grid view with a column:
<asp:BoundField DataField="ClosedDate" HeaderText="ClosedDate" SortExpression="ClosedDate" ReadOnly="True" ItemStyle-Width="11%" />
In gridview edit mode when a value is selected in a dropdown then I want to give this ClosedDate cell a value
I have the following code:
protected void ddlState_SelectedIndexChanged(object sender, EventArgs e)
{
GridViewRow gvr = (GridViewRow)(((Control)sender).NamingContainer);
DropDownList duty = (DropDownList)gvr.FindControl("ddlState");
stateValue = duty.SelectedItem.Value;
if (stateValue == "3")
{
}
}
I only want to update the current edited cell.
I am not sure how to do this.
The row has a few columns but closedDate is empty until state = 3 then give the closedDate cell a date a value or now()

you may use asp:TemplateField with a TextBox instead of asp:BoundField. Then in your DropDownlist_selectedIndexChanged update the value of TextBox
<asp:TemplateField HeaderText="ClosedDate" SortExpression="ClosedDate" ItemStyle-Wrap="false">
<ItemTemplate>
<asp:Label ID="lblCD" runat="server" Text='<%# Eval("ClosedDate") %>'/>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtCD" runat="server" Text='<%# Bind("ClosedDate") %>'/>
</EditItemTemplate>
</asp:TemplateField>

Related

Can't update a column in a GridView with a DropDownList in its EditItemTemplate

I'm trying to do a simple To-Do list application in ASP.NET with C# and I have a problem when I want to update the GridView with a value from a DropDownList. I've read a lot of solved question about this problem on this site but none of them worked so far or I must have missed something. Based on those answers I tried 2 method:
Method: I added a GridView to display and a FormView to add the Tasks. I created a database with a table for Tasks with Id, Name, Priority, DueDate, Completed columns and one table for priority possibilities(Low-Medium-High)
My code looks this was:
ASP.NET GridView part:
<asp:GridView ID="grdTasks" runat="server" AutoGenerateColumns="False" OnRowDataBound="grdTasks_RowDataBound" BackColor="White" BorderColor="#999999" BorderStyle="Solid" BorderWidth="1px" CellPadding="3" ForeColor="Black" GridLines="Vertical" OnRowEditing="grdTasks_RowEditing" AutoGenerateDeleteButton="True" AutoGenerateEditButton="True" OnRowCancelingEdit="grdTasks_RowCancelingEdit" OnRowUpdating="grdTasks_RowUpdating">
<Columns>
<asp:TemplateField HeaderText="Id">
<EditItemTemplate>
<asp:TextBox ID="txtId" runat="server" Text='<%# Bind("Id") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lblId" runat="server" Text='<%# Bind("Id") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Name" HeaderText="Name" />
<asp:TemplateField HeaderText="Priority">
<EditItemTemplate>
<asp:DropDownList ID="ddlPriority" runat="server" AppendDataBoundItems="True">
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lblPriority" runat="server" Text='<%# Bind("Priority") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="DueDate" HeaderText="DueDate" />
<asp:TemplateField HeaderText="Completed">
<EditItemTemplate>
<asp:Checkbox ID="chkCompleted" runat="server" Text='<%# Bind("Completed") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:TextBox ID="txtCompleted1" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
C# part:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindTasks();
}
}
private void BindTasks()
{
SqlDataSource sqlDtsTasks = new SqlDataSource();
sqlDtsTasks.ID = "sqlDtsTasks";
this.Page.Controls.Add(sqlDtsTasks);
sqlDtsTasks.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
sqlDtsTasks.SelectCommand = "SELECT * FROM Tasks";
grdTasks.DataSource = sqlDtsTasks;
grdTasks.DataBind();
}
protected void grdTasks_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if ((e.Row.RowState & DataControlRowState.Edit) > 0)
{
DropDownList ddlPriority =
(DropDownList)e.Row.FindControl("ddlPriority");
SqlDataSource sqlDtsTasks = new SqlDataSource();
SsqlDtsTasks.ID = "sqlDtsTasks";
this.Page.Controls.Add(sqlDtsTasks);
sqlDtsTasks.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
sqlDtsTasks.SelectCommand = "SELECT [States] FROM [Reference]";
ddlPriority.DataSource = sqlDtsTasks;
ddlPriority.DataTextField = "States";
ddlPriority.DataValueField = "States";
ddlPriority.DataBind();
DataRowView dr = e.Row.DataItem as DataRowView;
ddlPriority.SelectedValue =
dr["Priority"].ToString();
}
}
}
protected void grdTasks_RowEditing(object sender, GridViewEditEventArgs e)
{
grdTasks.EditIndex = e.NewEditIndex;
BindTasks();
}
protected void grdTasks_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
grdTasks.EditIndex = -1;
BindTasks();
}
protected void grdTasks_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
SqlDataSource sqlDtsTasks = new SqlDataSource();
sqlDtsTasks.ID = "sqlDtsTasks";
this.Page.Controls.Add(sqlDtsTasks);
sqlDtsTasks.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
string Priotext = (grdTasks.Rows[e.RowIndex].Cells[2].FindControl("ddlPriority") as DropDownList).SelectedItem.Value;
string Id = (grdTasks.Rows[e.RowIndex].Cells[0].FindControl("txtId") as TextBox).Text;
sqlDtsTasks.UpdateCommand = "UPDATE Tasks SET [Priority] = #Priority WHERE [Id] = #Id";
--> SqlDataSource2.UpdateParameters["Id"].DefaultValue = Id;
--> SqlDataSource2.UpdateParameters["Priority"].DefaultValue = Priotext;
grdTasks.DataSource = sqlDtsTasks;
grdTasks.DataBind();
}
This way I get the following error from the line marked with the arrow:
System.NullReferenceException - Object reference not set to an instance of an object.
This should mean that I got a null value from the ddl and the textbox but I dont know why, when I try to display the values of the ddl and textbox with a label, it displays it correctly.
Method: I basically did the same, but instead of doing it from code, I added 2 SqlDataSource. The first is binded to the GridView to display the Tasks. The second is binded to the DropDownList to display the Priority possibilities(Low-Medium-High). Also, I used the DataBindings from the smart tag of the DropDownList to bind the SelectedValue to the Priority column. This way, I can choose a priority when editing the row and I can update the Priority column if the current value in the db is null. BUT, when I want to update again, e.g. from Low to High I get this error:
System.ArgumentOutOfRangeException 'ddlPriority' has a SelectedValue which is invalid because it does not exist in the list of items.
As I've read about this many people pointed out that I should add a code like this and set the AppendDataBoundItems to true:
"<asp:ListItem Value=""></asp:ListItem>"
I even tried to add a line for each value like the one above, still the same error. What do I missing?

GridView onRowUpdating Event access to textBox

I got i strange situations.
This is a part of the ascx code of my gridview
<asp:gridview ID="grdBooks" class="grdBooks" runat="server" width="100%" DataKeyNames="RecId,RefAuthorsRecId,RefBooksTypeRecId" autogeneratecolumns="false" onDataBound="grdBooks_dataBound" onPreRender="grdBooks_preRender" onrowediting="grdBooks_RowEdit" onrowupdating="grbBooks_onRowUpdating" onrowupdated="grdBooks_onUpdated" autogenerateeditbutton="true" onrowcancelingedit="grdBooks_onCancelingEdit">
<Columns>
<asp:TemplateField HeaderText="Title">
<EditItemTemplate>
<asp:TextBox ID="txtgrdTitle" runat="server" width="200px"></asp:TextBox>
<asp:Label ID="lblgrdTitle2" runat="server" visible="false" Text='<%# Eval("Title") %>'></asp:Label>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lblgrdTitle" runat="server" Text='<%# Bind("Title") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>.....
This is a part of the "onRowEdit" and "onRowUpdating"
protected void grdBooks_RowEdit(object sender, GridViewEditEventArgs e)
{
grdBooks.EditIndex = e.NewEditIndex;
grdBooks.DataSource = book;
grdBooks.DataBind();
TextBox txtTitle = grdBooks.Rows[e.NewEditIndex].FindControl("txtgrdTitle") as TextBox;
Label lblTitle = grdBooks.Rows[e.NewEditIndex].FindControl("lblgrdTitle") as Label;
txtTitle.Text = lblTitle.Text;
}
protected void grbBooks_onRowUpdating(object sender, GridViewUpdateEventArgs e)
{
TextBox txtTitle = grdBooks.Rows[e.RowIndex].FindControl("txtgrdTitle") as TextBox;
....
}
The problem is:
the rowEdit works fine, change all the row of the grid in editable textboxes. The problem is that i write something in the text boxes and when i press "update" and go into the "onRowUpdate" method i haven't the new text(that i have inserted) in the textbox object that i have initialize. I got the old one.
(as u see now i use a not visible label in the editTemplate that carry the value of the original Title. Before i had Eval("title") on the textbox text but i thought that this was the probl so i try this other way)
As your datasource is book.Get the currentrow of the datatable and update values in that row.Then bind the grid again.
GridViewRow gridEditRow = this.grdBooks.Rows[e.RowIndex];
DataRow CurentRow = book.Rows[gridEditRow.DataItemIndex];
CurentRow["Title"] = (gridEditRow.FindControl("txtgrdTitle") as TextBox).Text;

How to know in which row a button is clicked in asp.net gridView

This is a simple gridView I m using in aspx web page
<asp:GridView ID="Order" runat="server" AutoGenerateColumns="False" ShowFooter="True" GridLines="none"
ItemType="MyProject.Models.TempList" SelectMethod="GetList" >
<Columns>
<asp:BoundField DataField="ItemID" HeaderText="ID" SortExpression="ItemID" />
<asp:TemplateField HeaderText="ItemName">
<ItemTemplate>
<asp:Label runat="server" ID="ItemName" Width="40" Visible="true" text="<%#: Item.Item.ItemName %>"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Price(each)">
<ItemTemplate>
<%#: String.Format("{0:c}", Convert.ToDouble(Item.Item.UnitPrice))%>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete">
<ItemTemplate>
<div style="float:left">
<asp:Button ID="DeleteBtn" runat="server" Text="Delete" OnClick="DeleteBtn_Click"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
I have 2+ items in a list<> which is populating the gridView, how can I tell (in the codeBehind.cs) that which Row the "DeleteBtn" was clicked on?
I was using a for loop to iterate every item in gridView using Rows[i] and used a check box to know which item wants to be deleted using a Update button.
But I want to do it directly on a custom created deletebutton.
Thanks in advance, I know I'm missing something silly.
The best way to do that is using CommandName and CommandArgument in your button declaration like that
<asp:Button ID="AddButton" runat="server" CommandName="AddToCart"
CommandArgument="<%# ((GridViewRow) Container).RowIndex %>" Text="Add to Cart" />
you can pass any value in the case we pass the rowIndex, you can get a propertie from your object like that CommandArgument="<%# Eval("id") %>" after that you will handle the onRowCommand method
protected void GridView1_RowCommand(object sender,GridViewCommandEventArgs e)
{
if (e.CommandName == "AddToCart")
{
// Retrieve the row index stored in the
// CommandArgument property.
int index = Convert.ToInt32(e.CommandArgument);
// Retrieve the row that contains the button
// from the Rows collection.
GridViewRow row = GridView1.Rows[index];
// Add code here to add the item to the shopping cart.
}
}
hope it helps :)
Use the button's CommandArgument property; assign Container.DataItemIndex to it. Then use the OnRowCommand event of the gridview and grab the index.
Sample aspx:
<asp:Label runat="server" ID="lblMsg" />
<asp:GridView runat="server" id="gvSample" AutoGenerateColumns="false" OnRowCommand="PerformOperation">
<Columns>
<asp:BoundField DataField="RowValue"/>
<asp:TemplateField>
<ItemTemplate>
<asp:Button Text="Delete" runat="server" CommandName="MyCustomCommand" CommandArgument="<%# Container.DataItemIndex %>" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
PopulateGrid();
}
}
private void PopulateGrid()
{
gvSample.DataSource = Enumerable.Range(0, 10).Select(i => new { RowValue = i });
gvSample.DataBind();
}
protected void PerformOperation(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "MyCustomCommand")
{
var rowIndex = int.Parse(e.CommandArgument);
lblMsg.Text = string.Format("Button on row index: {0} was clicked!", rowIndex);
}
}
Let the button field be given a CommandName, say for example a unique string myCommandName in the Edit columns dialog box. Don't worry about the CommandArgument. Then, in the Grid view Row command event, you can check which button (i.e. column) is clicked by tracing the command name like if e.commandname = "mycommandname", at the same time the CommandArgument will also be available as String and all we have to do is to converttoint32, something like intSelectedRow = convert.ToInt32(e.CommandArgument) which will give us the selected row's index.

Dropdownlist selection doesn't persist data on AddRow button click

I have an editable GridView.
I have an AddRow button, which adds a row which consists of 3 text boxes and one dropdown list.
Also, I have a Delete button, which removes the whole row when clicked.
Whenever I click on AddRow button, the selection of my dropdownlist doesn't persist, the selected value is realigned to the very first item.
Below are the codes:
<asp:GridView ID="GridView1" runat="server" ShowFooter="true" AutoGenerateColumns="false"
OnRowDeleting="GridView1_RowDeleting">
<Columns>
<asp:TemplateField HeaderText="Serial No">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Container.DataItemIndex + 1 %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Col1">
<ItemTemplate>
<asp:TextBox runat="server" ID="txt1" Text='<%# Eval("Column1") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Col2">
<ItemTemplate>
<asp:TextBox ID="txt2" runat="server" Text='<%# Eval("Column2") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Col3">
<ItemTemplate>
<asp:TextBox ID="txt3" runat="server" Text='<%# Eval("Column3") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="DropDown">
<ItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server" DataTextField='<%# Eval("Column4") %>'>
<asp:ListItem>London</asp:ListItem>
<asp:ListItem>Paris</asp:ListItem>
<asp:ListItem>New Delhi</asp:ListItem>
<asp:ListItem>New York</asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
<FooterStyle HorizontalAlign="Right" />
<FooterTemplate>
<asp:Button ID="btnAddNewRow" runat="server" Text="AddRow" OnClick="Add" />
</FooterTemplate>
</asp:TemplateField>
<asp:CommandField ButtonType="Button" ShowDeleteButton="true" />
</Columns>
</asp:GridView>
<asp:Button ID="btnSavetoDB" runat="server" Text="save" OnClick="btnSavetoDB_Click" />
EDITED CODE:
List<string> newList = new List<string>();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var table = CreateDataTable();
table.Rows.Add("", "", "");
BindGridView(table);
}
}
//Called on AddRow button click
protected void Add(object sender, EventArgs e)
{
var newTable = PopulateTableFromGridView();
newTable.Rows.Add("", "", "");
BindGridView(newTable);
}
private DataTable PopulateTableFromGridView()
{
var table = CreateDataTable();
for (int i = 0; i < GridView1.Rows.Count; i++)
{
//extract the TextBox values
TextBox box1 = (TextBox)GridView1.Rows[i].FindControl("txt1");
TextBox box2 = (TextBox)GridView1.Rows[i].FindControl("txt2");
TextBox box3 = (TextBox)GridView1.Rows[i].FindControl("txt3");
DropDownList ddl = (DropDownList)GridView1.Rows[i].FindControl("DropDownList1");
table.Rows.Add(box1.Text, box2.Text, box3.Text,ddl.SelectedItem.Text);
}
newList.Add(ddl.SelectedItem.Text);//add selecteditems to a global list
return table;
}
//Sets the first empty row to the grid view
private DataTable CreateDataTable()
{
var dt = new DataTable
{
Columns = { "Column1", "Column2", "Column3","Column4" }
};
return dt;
}
private void BindGridView(DataTable table)
{
GridView1.DataSource = table;
GridView1.DataBind();
for(int i=0;i<GridView1.Rows.Count-1;i++)
{
DropDownList ddl2=(DropDownList)GridView1.Rows[i].FindControl("DropDownList1");
ddl2.ClearSelection();
ddl2.Items.FindByText(newList[i]).Selected = true;
}
}
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
var dt = PopulateTableFromGridView();
if (dt.Rows.Count > 1)
{
dt.Rows[e.RowIndex].Delete();
}
BindGridView(dt);
}
The first screenshot, I have selected NewDelhi from the dropdownlist, which is the 3rd item:
The second screenshot, wherein a new row has been added after AddRow button is clicked, the dropdownlist is realigned in the first row, shows London.
How to make the code persist the dropdownlist selection when AddRow and Delete button is clicked?
I tried disabling the AutoPostBack property of the dropdownlist to false, but to no effect.
Experts please help.
SUCCESSFUL SCREENSHOTS:
I have solved the problem after some R&D.
I have created a new instance of dropdownlist after the gridview is bound, and in that new instance, I am preserving the previous selection using a List from the PopulateGridView method.
Please see the edit of the code.
Hope this helps some body.
Every time you hit the addrow button you are performing a postback.
every postback rebuilds then entire page including the grid based on your table. You can see that in your own code.
But part of this is that the controls within each row are rebuilt too. This includes your DDL's, but you are not saving/restoring the selected values from each drop down. More correctly, the selected values are saved but are invalidated when you recreate the table. you have to handle the RowDatabound event and in each row restore the selected value in the ddl.
But you may have a bigger problem. You are using the same instance of the DDL in each row. this may cause selection/persistence issues. If you find that selecting an item from the ddl causes all rows to have the same selected item, that's the problem in action.
Take a look at the rendered output for your ddl's and make sure the id's are unique for each row.
if the ddl has it's own datasource then you need to create a new instance of a DropDownlist in each row and assign it the same datasource rather than using find control.
if the control has it's list items hard coded then you should just check for unique ddl id's

ASP.NET GridView RowCommand TextBox empty

Hi I have a grid view with a textbox in each row that im trying to get the value of in the RowCommand event. The below code works fine for all rows expect the first one. The textbox.text value for the first row in always empty.
<asp:GridView ID="GridView1" runat="server" OnRowCommand="GridView1_OnRowCommand" >
<Columns>
<asp:TemplateField>
<ItemTemplate>
Title <%# Eval("Title")%>
<asp:TextBox ID="TextBoxAddPost" runat="server"></asp:TextBox>
<asp:LinkButton ID="LinkButtonAddPost" CommandName="AddPost" CommandArgument='<%# Eval("postId") %>' runat="server">Add Post</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code-behind:
protected void Page_Load(object sender, EventArgs e)
{
if(IsPostBack)
bindGridView();
}
protected void GridView1_OnRowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "AddPost")
{
GridViewRow row = (GridViewRow)(((LinkButton)e.CommandSource).NamingContainer);
TextBox textBox = (TextBox)row.FindControl("TextBoxAddPost");
//Empty for first row but works for all others
Debug.WriteLine("row: " + row.RowIndex + ", textBox:" + textBox.Text.Trim());
GridView1.DataBind();
}
}
The above code has been simplified for illustration purposes. Each row actually contains a child gridview, hence why in need the text box in each row. I fear that the binding in the page_load is overwriting the value of the text box, however, without the page_load binding, the rowCommand Event is not fired.
I find i a bit strange the it works fine for all rows except the first.
For getting data from textbox, You have to set text property first by putting below code.
<asp:TextBox ID="TextBoxAddPost" runat="server" Text='<%# Eval("Title") %>'></asp:TextBox>
It will definitely give value from textbox.
Either way, You can also set datakeynames property of gridview.Click here for datakeynames
I tried this and it works fine,GridView1_OnRowCommand fires by clicking on LinkButtonAddPost:
<asp:GridView ID="GridView1" runat="server" OnRowCommand="GridView1_RowCommand">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox ID="TextBoxAddPost" runat="server" Text='<%# Eval("ID") %>'></asp:TextBox>
<asp:LinkButton ID="LinkButtonAddPost" CommandName="AddPost" CommandArgument='<%# Eval("ID") %>' runat="server">Add Post</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
and change your page_load event like this:
protected void Page_Load(object sender, EventArgs e)
{
GridView1.DataSource = Data.RequestPaymentDB.GetRequestPaymentByRequestID(9208060001);
GridView1.DataBind();
}
compare your code with mine.

Categories