GridView RowCommand Event and Saving Text - asp.net

I have a GridView set up:
<asp:GridView id="GridView1" Runat="server" AutoGenerateColumns="False" OnRowCommand = "GridView1_RowCommand" EnableViewState="true">
<Columns>
<asp:TemplateField HeaderText="Delete" ItemStyle-HorizontalAlign="Center">
<ItemTemplate><asp:Button runat="server" ID="Delete" ImageUrl="~/images/Close.gif" CommandName="DeleteRow" CommandArgument="<%# CType(Container,GridViewRow).RowIndex %>"/></ItemTemplate></asp:TemplateField>
<asp:TemplateField HeaderText="Comment" ItemStyle-Width="175px">
<ItemTemplate><textarea class="raTextBox" id="txtItemComment" rows="4" cols="30"></textarea></ItemTemplate></asp:TemplateField>
</Columns>
</asp:GridView>
The RowCommand in code-behind is setup like:
Protected Sub GridView1_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs)
If (e.CommandName = "DeleteRow") Then
//do stuff here
The GridView is data bound on Page Load as follows:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If Not IsPostBack Then
Session("CalledModule") = "RCMT0021"
Else
With ViewState
_intRepor = CInt(.Item("Report"))
End With
End If
DataBind() //Gridview Load
End Sub
My questions:
The row command event is never fired. The page just goes into the ELSE (of Not is Postback) in Page_Load
How can I keep track of what all is typed in the "Comments" column of each row (a TEXTAREA), and save the data to the database when a SAVE CHANGES (form) button is clicked?
Thanks!
UPDATE:
The Grid-View's Databinding is as follows:
Public Sub DataBind()
Dim clsDatabase As New clsDatabase
Dim cmd As New OleDbCommand()
Try
cmd.CommandText = "SELECT A, B FROM WHERE C = ? ORDER BY A"
Dim report As New OleDbParameter("#Report", _intReportNumber)
cmd.Parameters.Add(report)
cmd.Connection = clsDatabase.Open_DB()
Dim dReader As OleDbDataReader
dReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
Dim dt As New DataTable
dt.Columns.Add(New DataColumn("PictureURL", GetType(String)))
dt.Columns.Add(New DataColumn("Seq", GetType(Int16)))
dt.Columns.Add(New DataColumn("ReportNumber", GetType(String)))
Do While (dReader.Read())
Dim dr As DataRow = dt.NewRow()
_strComments = dReader(0).ToString
dr("Seq") = dReader.GetInt16(1)
dr("PictureURL") = "GetImages.aspx?report=" + _intReportNumber.ToString + "&seq=" + dReader.GetInt16(1).ToString
dr("ReportNumber") = _intReportNumber.ToString
dt.Rows.Add(dr)
Loop
GridView1.DataSource = dt
GridView1.DataBind()
Catch err As Exception
End Try
End Sub
So basically, the GridView has three visible columns - a comments field, a picture field, and a field with a delete button (image) to delete the picture (and comments, if any) from the database. The 4th column is a hidden one, keeping track of the the Image ID of the images. I didn't include the picture and other columns for simplicity sake.
The user can add comments, and when he clicks a 'SAVE CHANGES' button, the corresponding comments should get saved for the picture.
The 'SELECT IMAGE' opens up a ModalDialogBox which enables the user to select the image. When closed, it causes a postback, and rebinds the gridview to display the image the user just selected. Therefore, I need the GridView to rebind on postback, or a way around this.
The delete imagebutton (in gridview) should delete the image and comments from the database.
Thanks again!

try this structure...
aspx page: (note textarea has runat="server")
<body>
<form runat="server">
<asp:ScriptManager runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" OnRowCommand="GridView1_RowCommand"
EnableViewState="true" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Delete" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Button runat="server" ID="Delete" Text="Delete" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Comment" ItemStyle-Width="175px">
<ItemTemplate>
<textarea runat="server" class="raTextBox" id="txtItemComment" rows="4" cols="30"></textarea></ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
BindGrid();
}
}
protected void BindGrid()
{
var items = new List<string>();
for (int i = 0; i < 10; i++)
{
items.Add(i + ";comment" + i.ToString());
}
GridView1.DataSource = items;
GridView1.DataBind();
}
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "DeleteRow")
{
var idx = Convert.ToInt32(e.CommandArgument);
var cmt = GridView1.Rows[idx].FindControl("txtItemComment") as System.Web.UI.HtmlControls.HtmlTextArea;
cmt.Value = DateTime.Now.ToString();
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var item = e.Row.DataItem.ToString().Split(";".ToCharArray());
var del = e.Row.FindControl("Delete") as Button;
del.CommandName = "DeleteRow";
del.CommandArgument = item[0];
var cmt = e.Row.FindControl("txtItemComment") as System.Web.UI.HtmlControls.HtmlTextArea;
cmt.Value = item[1];
}
}

Related

add date to database if checkbox checked in gridview

I have an Ordering system showing Orders that have been received and also orders that are outstanding. If the Order is received and the checkbox is then checked I would like to add the date to the database when the order was received. Obviously I would only like to add the date to the row that has been checked. Thanks in advance.
relevant HTML as follows:
<asp:GridView ID="gvOpenOrders" runat="server" AutoGenerateColumns="False" Width="100%" CellPadding="4" ForeColor="#333333"
GridLines="None" DataKeyNames="PurchaseOrderID" AllowPaging="True" AllowSorting="True"
OnSorting="gvOpenOrders_Sorting" EnableViewState="true" OnPageIndexChanging="OnPageIndexChanging" PageSize="15" ViewStateMode="Enabled">
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:TemplateField HeaderText="Is Received" SortExpression="IsReceived">
<ItemTemplate>
<asp:CheckBox ID="chkRcvd" runat="server" AutoPostBack="true" Checked='<%# Bind("IsReceived") %>' Enabled='<%# Eval("IsReceived") = False %>' OnCheckedChanged="chkRcvd_CheckedChanged" />
</ItemTemplate>
</asp:TemplateField>
I am currently updating the database when a Update Received button is clicked, see below:
Protected Sub btnUpdateReceived_Click(sender As Object, e As EventArgs) Handles btnUpdateReceived.Click
con.Open()
For Each row As GridViewRow In gvOpenOrders.Rows
Dim purchaseOrderID As Integer = Convert.ToInt32(gvOpenOrders.DataKeys(row.RowIndex).Values(0))
Dim isReceived As Boolean = TryCast(row.FindControl("chkRcvd"), CheckBox).Checked
cmd.CommandText = "usp_UpdatePurchaseOrder"
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Clear()
cmd.Parameters.AddWithValue("#OrderID", purchaseOrderID)
cmd.Parameters.AddWithValue("#IsReceived", isReceived)
cmd.ExecuteNonQuery()
Next
con.Close()
Response.Redirect(Request.Url.AbsoluteUri)
End Sub
I know that there is a checkbox_CheckedChanged event but I am unsure how to use it.
You can add this code in CheckedChanged event:
CheckBox chkSelect = (CheckBox)sender;
if (chkSelect.Checked)
{
string date = DateTime.Today.ToString("dd-MM-yyyy");
}
Hope could convert it into VB's code.
As I think only one modification can find your solution.
Try this:
string strDate=stirng.Empty;
foreach (GridViewRow rw in grid1.Rows)
{
CheckBox chkBx = (CheckBox)rw.FindControl("Check");
if (chkBx != null && chkBx.Checked)
{
strDate = ((Label)rw.FindControl("lblDate")).Text;
}
}
protected void chkRcvd_CheckedChanged(object sender, EventArgs e)
{
CheckBox chkSelect = (CheckBox)sender;
if (chkSelect.Checked)
{
string date = DateTime.Today.ToString("dd-MM-yyyy");
}
}

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.

dropdownlist in gridview row data bound is not executing properly

I have a dropdownlist in my gridview. The datas in dropdownlist are "Y" and "N".These two letters. If I select Y then the cell value 6 will be need to become zero. But its not working. Here is my code.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList DropDownList3=(DropDownList)e.Row.FindControl("DropDownList");
//if (DropDownList3 == null)
//if (DropDownList3.SelectedValue == "Y")
if(DropDownList3.SelectedItem.Text == "Y")
{
e.Row.Cells[6].Text = "0";
}
else
{
e.Row.Cells[6].Text = "1";
}
}
}
This is my dropdowlist template field
<asp:TemplateField HeaderText="Alt">
<EditItemTemplate>
<asp:DropDownList ID="DropDownList3" runat="server" >
<asp:ListItem>Y</asp:ListItem>
<asp:ListItem>N</asp:ListItem>
</asp:DropDownList>
</EditItemTemplate>
<FooterTemplate>
<asp:DropDownList ID="DropDownList3" runat="server" >
<asp:ListItem>Y</asp:ListItem>
<asp:ListItem>N</asp:ListItem>
</asp:DropDownList>
</FooterTemplate>
<ItemTemplate>
<asp:DropDownList ID="DropDownList3" runat="server" >
<asp:ListItem>Y</asp:ListItem>
<asp:ListItem>N</asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
First, You have to set AutoPostBack="true" for DropDownList3, and You have to create EventHandler for ddl, but in RowCreated not in RowDataBound.
There is example (it's vb.net) :
aspx:
<asp:TemplateField HeaderText="Alt">
<ItemTemplate>
<asp:DropDownList ID="DropDownList3" runat="server" AutoPostBack="true">
<asp:ListItem>Y</asp:ListItem>
<asp:ListItem>N</asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
and then, code behind :
Private Sub GridView1_RowCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles grid1.RowCreated
If e.Row.RowType = DataControlRowType.DataRow Then
Dim ddl As DropDownList = CType(e.Row.FindControl("DropDownList3"), DropDownList)
AddHandler ddl.SelectedIndexChanged, AddressOf ddlChange
End If
End Sub
Private Sub ddlChange(ByVal sender As Object, ByVal e As EventArgs)
Dim ddl As DropDownList = DirectCast(sender, DropDownList)
Dim row As GridViewRow = ddl.NamingContainer
If ddl.SelectedItem.Text = "Y" Then
row.Cells(6).Text = "0"
Else
' do what You want
End If
End Sub
It's very important You don't bind Your GridView after every PostBack, and, of course, EnableViewState must be set to True.
Since I'm working in vb.net, I'll try to convert this code into c#.
Update :
There is c# code (I used online converter) :
private void GridView1_RowCreated(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e) {
if ((e.Row.RowType == DataControlRowType.DataRow)) {
DropDownList ddl = ((DropDownList)(e.Row.FindControl("DropDownList3")));
ddl.SelectedIndexChanged += new System.EventHandler(this.ddlChange);
}
}
private void ddlChange(object sender, EventArgs e) {
DropDownList ddl = ((DropDownList)(sender));
GridViewRow row = ddl.NamingContainer;
if ((ddl.SelectedItem.Text == "Y")) {
row.Cells[6].Text = "0";
} else {
// do what You want
}
}

Linkbutton click in a asp:GridView cell does not trigger OnRowCommand event

UI Feature: I have a GridView with few columns. Most important column is PcCode, which shows a string value for each row.
Expected: When I click on one of the cell from a row of that PcCode column another GridView should be displayed. However, when I am trying to use a asp:LinkButton for a cell, things just don't work. RowCommand does not get triggered when I click on a asp:LinkButton in the GridView cell. Where am I doing things wrong? Which way the expected functionality can be achieved? Thanks in advance for helping out a newbie.
In the following code I was trying to get a RowIndex and pass it through the CommandArgument and use a CommandName.
.aspx code
<asp:GridView ID="_UIProfitcenterTotalGridView" runat="server" CellPadding="4" ForeColor="#333333" GridLines="None" AllowPaging="True" PageSize="22" ShowFooter="True" AutoGenerateColumns="False"
DataKeyNames="ProfitcenterCode" EnableViewState="False"
OnRowDataBound="_UIProfitcenterTotalGridView_RowDataBound"
OnPageIndexChanging="_UIProfitcenterTotalGridView_PageIndexChanging"
OnRowCommand="_UIProfitcenterTotalGridView_OnRowCommand">
<Columns>
<asp:TemplateField HeaderText="PcCode" InsertVisible="False"
ShowHeader="False" SortExpression="ProfitcenterCode" FooterText="Total" FooterStyle-HorizontalAlign="Left">
<ItemTemplate>
<asp:LinkButton ID="_UIPCCodeLinkButton" runat="server" Text='<%# Eval("ProfitcenterCode") %>'
CommandName="Select"
CommandArgument='<%# ((GridViewRow) Container).RowIndex %>'>
</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
...
code behind for aspx.cs
protected void _UIProfitcenterTotalGridView_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{
int index = Convert.ToInt32(e.CommandArgument);
GridViewRow row = _UIProfitcenterTotalGridView.Rows[index];
string ProfitcenterCode = _UIProfitcenterTotalGridView.DataKeys[_UIProfitcenterTotalGridView.SelectedIndex].Values["ProfitcenterCode"].ToString();
}
}
After the row is selected I need to take the selected row's value as a string and compare with a listitem to show a new GridView.
Tried
Using Link_Button_Click(Object sender, EventArgs e) and the following but failed.
protected void _UIProfitcenterTotalGridView_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{string ProfitcenterCode = ((GridViewRow)(((LinkButton)e.CommandSource).NamingContainer)).Cells[2].Text;
}
}
I tried to use LinkButton_Click() event instead of RowCommand as jason suggested:
protected void LinkButton_Click(Object sender, EventArgs e)
{
LinkButton button = (LinkButton)sender;
GridViewRow row = (GridViewRow)button.NamingContainer;
if (row != null)
{
string theValue = ((LinkButton)sender).CommandArgument.ToString();
...
...
//code for the extra thing I needed to do after selecting a cell value.
}
}
However I still had the problem, which I figured out. The problem was the LinkButton was not binding to the rows thefore, it could not pass any value on selection. What was missing was the following code:
if (e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton linkButton = new LinkButton();
linkButton.Text = e.Row.Cells[0].Text; //value of the first column from the grid
linkButton.Enabled = true;
linkButton.Click += new EventHandler(LinkButton_Click); //triggering the LinkButton event here.
e.Row.Cells[0].Controls.Add(linkButton);
}
You can use the sender object ( the link button that calls the event) and get the parent row from the gridview. Example:
Protected Sub linkButton_click(ByVal sender As Object, ByVal e As EventArgs)
'First cast the sender to a link button
Dim btn As LinkButton = CType(sender, LinkButton)
'now, if there is a command arguement, you can get that like this
Dim id As String = btn.CommandArgument
'to get the gridviewrow that the button is on:
Dim row As GridViewRow = CType(btn.NamingContainer, GridViewRow)
End Sub
It was hard to follow exactly what you were looking for, so if i missed something let me know and I will add it.
protected void linkButton_click(object sender, EventArgs e)
{
//First cast the sender to a link button
LinkButton btn = (LinkButton)sender;
//now, if there is a command arguement, you can get that like this
string id = btn.CommandArgument;
//to get the gridviewrow that the button is on:
GridViewRow row = (GridViewRow)btn.NamingContainer;
}
And change your linkbutton to:
<asp:LinkButton OnClick="linkButton_click" ID="_UIPCCodeLinkButton"
runat="server" Text='<%# Eval("ProfitcenterCode") %>'
CommandName="Select"
CommandArgument='<%# ((GridViewRow) Container).RowIndex %>'>

Accessing Controls Inside ASP.NET View Controls (Event Handling)

If I have the following ListView, how can I attach a SelectedIndexChanged event listener to the DropDownList so I can perform a command on the respective object? Imagine I have a list of new users and I want to add them to a usergroup by selecting the group from the DropDownList.
<asp:ListView ID="NewUsers" runat="server" DataSourceID="NewUsersSDS" DataKeyNames="ID">
<LayoutTemplate>
<asp:Table ID="groupPlaceholder" runat="server"><asp:TableRow></asp:TableRow></asp:Table>
</LayoutTemplate>
<GroupTemplate>
<asp:TableCell ID="itemPlaceholder" runat="server"></asp:TableCell>
</GroupTemplate>
<ItemTemplate>
<asp:Table ID="NewUsersTable" runat="server" Width="32%" CssClass="inlineTable">
<asp:TableRow>
<asp:TableCell Width="100px"><%# Eval("FullName").ToString.Trim()%></asp:TableCell>
<asp:TableCell>
<asp:HiddenField ID="RowIndex" runat="server" Value="<%# Container.DisplayIndex %>" />
<asp:DropDownList ID="UserGroupSelect" runat="server" DataSourceID="UserGroupSelectSDS" DataValueField="ID" DataTextField="UserGroup"
OnSelectedIndexChanged="UserGroupSelect_SelectedIndexChanged" AutoPostBack="True">
</asp:DropDownList>
</asp:TableCell>
</asp:TableRow>
</asp:Table>
</ItemTemplate>
</asp:ListView>
I've been having issues accessing controls inside of __View controls. I read in a few places that you could access them by NewUsers.FindControl([ControlID as String]) but this doesn't seem to be working for me. I guess this is what's called a dynamic control? Not really sure, feeling a bit lost.
As always, your help is greatly appreciated. ;)
Additional Info / Code
'Now working code, thanks to James :)
Protected Sub ItemBind(ByVal sender As Object, ByVal e As ListViewItemEventArgs) Handles NewUsers.ItemDataBound
Dim lv As ListView = DirectCast(sender, ListView)
If e.Item.ItemType = ListViewItemType.DataItem Then
lv.DataKeys(e.Item.DataItemIndex).Value.ToString() 'get the datakey
End If
End Sub
Protected Sub UserGroupSelect_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim RowIndex As Integer = CInt(DirectCast(DirectCast(sender, DropDownList).Parent.FindControl("RowIndex"), HiddenField).Value)
Dim pk As Integer = CInt(NewUsers.DataKeys(RowIndex)("ID"))
Try
MessageBox("Update key " + pk.ToString, "Update Key") 'Custom js "alert" box function
Catch ex As Exception
MessageBox("Something went wrong, is the update key empty?")
End Try
End Sub
To access controls in a ListView (or any databound control), you need to use FindControl on the item/row:
ListViewItem item = ListView1.Items[0];
if (item != null)
{
DropDownList ddl = item.FindControl("DropDownList1") as DropDownList;
if (ddl != null)
{
string value = ddl.SelectedValue;
}
}
As for attaching a SelectedIndexChanged event, you can do it like this:
<ItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server"
AutoPostBack="true"
OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
</asp:DropDownList>
<asp:HiddenField ID="HiddenField1" runat="server" Value='<%# Container.DisplayIndex %>' />
</ItemTemplate>
Code-behind:
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
int rowIndex = Convert.ToInt32(((HiddenField)((DropDownList)sender).Parent.FindControl("HiddenField1")).Value);
ListViewItem item = ListView1.Items[rowIndex];
if (item != null)
{
//your logic here
}
}
To retrieve a datakey:
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
int rowIndex = Convert.ToInt32(((HiddenField)((DropDownList)sender).Parent.FindControl("HiddenField1")).Value);
int pk = (int)ListView1.DataKeys[rowIndex]["PrimaryKey"];
}

Resources