Asp.Net WebForms Gridview OnRowCommand Event not hitting code behind method - c#

I am trying to incorporate an edit button in a grid view.
However the on row command does not seem to be firing.
I put a break point on the onrowcommand method i have implemented in the code behind.
Here is the View (i substituted the imageurl with xxx's as privacy concern on here):
<asp:GridView ID="GridViewContacts1" runat="server" CssClass="data_table" AutoGenerateColumns="false" OnRowCommand="GridViewContacts1_OnRowCommand" EmptyDataText="There are no contacts for this prospect." >
<AlternatingRowStyle CssClass="alternating_row" />
<Columns>
<asp:BoundField DataField="ContactName" HeaderText="Name" />
<asp:BoundField DataField="ContactTitle" HeaderText="Title" />
<asp:TemplateField HeaderText="Phone" SortExpression="PhoneNumber">
<ItemTemplate>
<%# FormatPhone(Eval("PhoneNumber").ToString()) %>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email"></asp:BoundField>
<asp:TemplateField HeaderText="Edit" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:ImageButton ID="icmdEditContact" Runat="server" ImageUrl="xxxxx" BorderStyle="None" CommandName="EditContact" CommandArgument='<%# Eval("ContactId") %>'/>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:LinkButton CommandArgument='<%# Eval("ContactId") %>' CausesValidation="false" CommandName="DeleteItem" OnClientClick="javascript:return confirm('Are you sure you want to delete this record?')" Runat="server" ID="Linkbutton1"><img src="xxxxx" border="0"/></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
As you will see the OnRowCommand Property of the grid view is : GridViewContacts1_OnRowCommand
Here is the code behind
The problem i'm having is this isn't getting hit :
Any ideas or suggestions ?
I even tried to incorporate without the rowcommand by just using a normal button and click event and it still wouldn't hit the designated codebehind method for that click event.

Do both buttons not work, or just the delete button?
Make sure viewstate is not turned off for the GV, and "always" give each button a "id" - your delete button is missing one.
On the other hand?
I often, and in fact BEYOND often just dump the built in commands for the GV. You actually don't need them.
For any button, image button etc that you drop into your GV (templated column), then you can just add/use/have a plain jane click event, and then use that.
The "bonus" then is you are free to add new buttons, and you don't have to use nor mumble jumpble all of the commands into that one on-row command routine anyway.
So, do check:
make sure view state of gv not turned off
make sure each button has a "id"
make sure you not re-binding the gv on page load each time
(you look to have the all important !IsPostback (good).
However, as noted, I don't use the row commands anymore.
You can do it this way:
Say this GV.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" width="40%" CssClass="table table-hover" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chkActive" runat="server"
Checked='<%# Eval("Active") %>'/>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="cmdView" runat="server" Text="View" CssClass="btn"
OnClick="cmdView_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And code to load:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL =
#"SELECT * FROM tblHotelsA ORDER BY HotelName";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
DataTable rstData = new DataTable();
rstData.Load(cmdSQL.ExecuteReader());
GridView1.DataSource = rstData;
GridView1.DataBind();
}
}
}
And we see/get this:
Button click code - each button is SEPERATED - nice!!
So, this code:
protected void cmdView_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
GridViewRow gRow = (GridViewRow)btn.NamingContainer;
int iPK = (int)GridView1.DataKeys[gRow.RowIndex]["ID"];
Debug.Print("Database PK = " + iPK);
Debug.Print("Row index click = " + gRow.RowIndex);
Debug.Print("Hotel Name = " + gRow.Cells[3].Text); // non template values
// get value of check box control on this row
CheckBox chkActive = (CheckBox)gRow.FindControl("chkActive");
Debug.Print("Value of active check box control = " + chkActive.Checked);
// hide gv, show edit area.
// bla bla bal
}
Now clicking on a button, we get this output:
Database PK = 16
Row index click = 0
Hotel Name = Batman's Cave
Value of active check box control = True
So,
Note how we use database "datakeys" option. This is VERY improant for secuirty, since the database row PK is NEVER exposted client side.
However, as above shows:
You can easy get the datakeys (row PK id)
You can easy get the row index
you have full use of the row (namingcontainer)
you can use find control etc.
So, really, I see LITTLE reason to use the built in row index command.
You ARE free to add/use/have/enjoy the command arugument for a button, or image button, or link buttion and I'll often use that to add/supply extra information to pass to the button).
But for the public and history?
Check viewestate, add "id" to those buttons that don't have one.
However, all in all, since you can just use/add/have a button click like any other button you drop into a page, then I just continue to use simple plain jane button clicks, and not bother with the GV event model.
Note that naming container trick used above works for repeaters/listview/datalist etc.

Related

Problem with being able to access certain elements in GridView -> TemplateField -> EditItemTemplate

I have this problem with being able to access certain elements in
GridView -> TemplateField -> EditItemTemplate.
To be more clear, I have textbox and button
(in GridView -> TemplateField -> EditItemTemplate) and only one of them must be visible depending on operation. If I want to edit, button must be visible and if I want to add new user then textbox must be visible. I have added my aspx code for you to check and also C# code-behind. The method in C# code is the one which gets called immidiately when I press "Edit" button which lets to edit account details and permissions for one user. And I want that this method would decide whenever to show textbox or button (I have IsUserInsertMode property for that.)
I would be really grateful for someone who would help me out with this.
<asp:GridView CssClass="grid" ID="gridUsers" runat="server"
AutoGenerateColumns="False" DataKeyNames="id"
DataSourceID="dsrcUserList" GridLines="None"
OnRowCommand="gridUsers_RowCommand" OnDataBound="gridUsers_DataBound"
OnRowUpdating="gridUsers_Updating" OnRowUpdated="gridUsers_Updated" EnableModelValidation="True">
<Columns>
<asp:TemplateField HeaderText="Password" ItemStyle-HorizontalAlign="center" ItemStyle-Width="80px">
<ItemTemplate>
*******
</ItemTemplate>
<EditItemTemplate>
**NEED REFERENCES TO THESE TWO ITEMS IN ORDER TO SET THEIR VISIBILITY**
<asp:Button ID="btnEditPassword" Text="Change" runat="server" CausesValidation="false" OnClick="btnEditPassword_Click" Visible="false"/>
<asp:TextBox ID="txtPassword" runat="server" TextMode="Password" Text='<%# Bind("Password") %>' Width="74px" MaxLength="50" Visible="true" />
</EditItemTemplate>
</asp:TemplateField>
**LOTS OF CHECKBOXES LIKE THOSE**
<asp:CheckBoxField DataField="AccessTowsRelease" HeaderText="TowsRelease" ItemStyle-HorizontalAlign="Center">
<ItemStyle HorizontalAlign="Center"></ItemStyle>
</asp:CheckBoxField>
<asp:CheckBoxField DataField="AccessTowsView" HeaderText="TowsView" ItemStyle-HorizontalAlign="Center">
<ItemStyle HorizontalAlign="Center"></ItemStyle>
</asp:CheckBoxField>
<asp:CheckBoxField DataField="AccessSMS" HeaderText="SMS"
ItemStyle-HorizontalAlign="Center">
<ItemStyle HorizontalAlign="Center"></ItemStyle>
</asp:CheckBoxField>
**MY EDIT BUTTON**
<asp:CommandField ButtonType="Link"
ShowEditButton="true" EditText="Edit"
CancelText="Cancel" UpdateText="Save" />
</Columns>
</asp:GridView>
C# code-behind (I have added some of the stuff that I have tried)
// this is called when I press some button which lets me to edit one user data including password
// but when I want to change password, there should be button which would redirect to different
// window to do the password change procedure.
// And when I want to add new user there should be textbox for password, not the button.
protected void gridUsers_RowCommand(Object sender, GridViewCommandEventArgs e)
{
//Found the way to get the index of current row (represents one row of information which is visible for the client in browser)
int rowIndex = Convert.ToInt32(e.CommandArgument);
//if those would be working I wouldn't be here asking for help
btnEditPassword.Visible = true;
txtPassword.Visible = false;
//Can't cast 'System.Web.UI.WebControls.GridView' to type 'System.Web.UI.WebControls.GridViewRow'
Button btnEditPassword = (Button)((GridViewRow)sender).FindControl("btnEditPassword");
//every attempt to use FindControl gets me null
Button btnEditPassword = (Button)this.gridUsers.Rows[rowIndex].FindControl("btnEditPassword");
// my way to check if it works - if its null then I do can't anything (prints to browser console).
if (btnEditPassword != null) Response.Write("<script>console.log('not null')</script>");
else Response.Write("<script>console.log('null')</script>");
}
The RowCommand-event is raised too early for your case. It's raised before the row is going into edit mode, that's why you don't find the controls of your edit-item-template.
First change your markup to handle the RowDataBound-event:
<asp:GridView ... OnRowDataBound="gridUsers_OnRowDataBound" ...>
Then handle this in the OnRowDataBound-event like this:
protected void gridUsers_OnRowDataBound(object sender, GridViewRowEventArgs e) {
// check if row is in edit state
if ((e.Row.RowState == DataControlRowState.Edit) || (e.Row.RowState == (DataControlRowState.Alternate | DataControlRowState.Edit))) {
// look for the control in the row
Button btnEditPassword = (Button)e.Row.FindControl("btnEditPassword");
}
}

Why is textbox.Text returning an empty string?

First let me preface this with the fact that I know this question has been asked a slew of times. I've tried implementing everything I've read and have not resolved my issue yet.
I have a shopping cart being displayed in a GridView and I am trying to get the update function to work. After I click edit (on the row in question) and I change the value in the textbox, and then click update, I am always getting an empty string returned.
I've read countless posts about it being a PostBack issue, however I have encapsulated my DataBind method within an if(!Page.IsPostBack){} so I dont believe that is my issue.
These are the relevant methods in my CodeFile:
protected void Page_Load(object sender, EventArgs e)
{
if (Session["thisCart"] == null)
{
Session["thisCart"] = new ShoppingCart();
}
thisCart = (ShoppingCart)Session["thisCart"];
if (!Page.IsPostBack)
{
FillData();
}
}
private void FillData()
{
gvShoppingCart.DataSource = thisCart.Items;
gvShoppingCart.DataBind();
if (thisCart.Items.Count == 0)
{
lblGrandTotal.Visible = false;
}
else
{
lblGrandTotal.Text = string.Format("Grand Total = {0,19:C}", thisCart.GrandTotal);
lblGrandTotal.Visible = true;
}
}
protected void gvShoppingCart_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
TextBox txtQuantity = (TextBox)gvShoppingCart.Rows[e.RowIndex].Cells[3].Controls[0];
int quantity = Int32.Parse(txtQuantity.Text);
thisCart.Update(e.RowIndex, quantity);
gvShoppingCart.EditIndex = -1;
FillData();
}
And this is the aspx file:
<asp:GridView ID="gvShoppingCart" runat="server" AutoGenerateColumns="False" OnRowCancelingEdit="gvShoppingCart_RowCancelingEdit" OnRowDeleting="gvShoppingCart_RowDeleting" OnRowEditing="gvShoppingCart_RowEditing" OnRowUpdating="gvShoppingCart_RowUpdating" ClientIDMode="AutoID">
<Columns>
<asp:BoundField DataField="NAME" HeaderText="Product name" ReadOnly="True" />
<asp:ImageField DataImageUrlField="IMAGE" DataImageUrlFormatString="~\Images\{0}" HeaderText="Image" ReadOnly="True">
</asp:ImageField>
<asp:BoundField DataField="PRICE" HeaderText="Price" ReadOnly="True" />
<asp:BoundField DataField="QUANTITY" HeaderText="Quantity" />
<asp:TemplateField HeaderText="Total">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Double.Parse(Eval("PRICE").ToString()) * Int32.Parse(Eval("QUANTITY").ToString()) %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ShowHeader="False">
<EditItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="True" CommandName="Update" Text="Update"></asp:LinkButton>
<asp:LinkButton ID="LinkButton2" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel"></asp:LinkButton>
</EditItemTemplate>
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False" CommandName="Edit" Text="Edit"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowDeleteButton="True" />
</Columns>
</asp:GridView>
I'm usually pretty good at finding answers, but this one has got me stumped.
The site crashes after clicking update because the returned value from int quantity = Int32.Parse(txtQuantity.Text); is "" and obviously you cant parse an int from that.
As for the tag of possible duplicate of "ASP.NET validation error message to change labels text." I was unable to find anything that points me in the direction of an answer.
Call FillData() in Page_PreInit. Otherwise, when the ASP.Net runtime goes to restore ViewState for the grid, including your new Textbox data, there's nowhere to put it yet. Remember that every single server event uses a brand new instance of your page class and must rebuild the entire page from scratch.
This was a royal pain to figure out since I'm just learning ASP.net and C#.
When I was able to make this work on an earlier assignment I wasn't using a Master page, with this project I am. The problem lies in the fact that I am using a <form runat="server"> tag in the Master page. Since you can only have one <form runat="server"> tag per page, my GridView wasn't wrapped in one. Once I removed the Master page and added the <form runat="server"> wrapper around the GridView, everything works as intended.

Foreach not getting all the values from gridview because of datatable pagination

So I have a function that loops through a GridView, which is using a JQuery DataTable with pagination. It shows ten rows for every page, so it is necessary to edit all the textboxes you want and click on a button named "Save" that calls the function mentioned before. The issue is that only the page that is displayed on the screen at the moment of clicking on the button "Save" is sending the textbox values and not all gridview texbox instead. For instance, if I edit "gridview page 1", "gridview page 2" and "gridview page 3" fields and click on the button "Save" while "gridview page 3" is displayed then "gridview page 1" and "gridview page 2" textbox values are not saved. If I'm explaining myself wrongly let me know please.
ASPX Inline code
<asp:GridView ID="grvServicio" runat="server" AutoGenerateColumns="false" class="display" >
<Columns>
<asp:BoundField DataField="intIdServicio" HeaderText="ID" />
<asp:BoundField DataField="vchServicio" HeaderText="Servicio" />
<asp:TemplateField HeaderText="Cantidad">
<ItemTemplate>
<asp:TextBox ID="txtCantidad" runat="server" ClientIDMode="Static" Text='<%# Bind("intCantidad")%>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Precio">
<ItemTemplate>
<asp:TextBox ID="txtPrecio" runat="server" ClientIDMode="Static" Text='<%# Bind("decPrecio")%>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Estatus">
<ItemTemplate>
<asp:CheckBox ID="chkServEstatus" Checked='<%# Convert.ToBoolean(Eval("intEstatus"))%>' enabled="true" runat="server" CssClass="ChkBoxClass"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
ASPX Behind code (I've removed the code saving process but if necessary let me know)
protected void btnGuardarServicio_Click(object sender, EventArgs e)
{
foreach (GridViewRow row in grvServicio.Rows)
{
for (int i = 0; i < grvServicio.Columns.Count; i++)
{
string idEvento = row.Cells[0].Text;
TextBox cant = (TextBox)row.Cells[2].FindControl("txtCantidad");
TextBox prec = (TextBox)row.Cells[3].FindControl("txtPrecio");
prec.Text = prec.Text.Replace(",", ".");
}
}
}
Here is how my GridView looks like using datatable JQuery plug-in
With a paginated grid, data is rendered and loaded (if it is a server -side pagination) only when you change the page. Maybe you can save the data on value changed event so when you change to next page and back again you have data updated.

Change AutoGeneratedDelete LinkButton of Gridview to an Image Button

i have a gridview with AutoGenerateDeleteButton Property set true.
Of course this property auto generates a linkbutton at the leftmost of the gridview, my question is, how can i change it to an Image Button?? i wanted my gridview to look more presentable by making the control buttons an image.
Thanks! :)
You can do by using template in grid...
for more info
http://p2p.wrox.com/asp-net-2-0-professional/46216-image-button-template-field-gridview-control.html
You can create a TemplateField and use autogeneratecolumns="false".
Here's an example of a GridView:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns ="false">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="Link" runat="server" Text="click" OnClick="link_Click"/>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="field1" HeaderText="My Column 1" />
<asp:BoundField DataField="field2" HeaderText="My Column 2" />
</Columns>
</asp:GridView>
Where field1 and field2 are headers from your DataTable
And to access the row within the event handler:
protected void link_Click(object sender, EventArgs e)
{
int rowindex = ((GridViewRow)((Control)sender).NamingContainer).RowIndex;
//do something with rowindex etc
}
Add new Template Column and in add image button and set CommandName='Delete' it'll raise the delete event automatically.
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="imgDelete" ImageUrl="~/imgs/Delete.png"
CommandName="Delete" runat="server" />
</ItemTemplate>
</asp:TemplateField>
Try this
<Columns>
<asp:CommandField ButtonType="Image" DeleteImageUrl="~/Images/DeleteImage.png"
ShowDeleteButton="true"/>
</Columns>
And set AutoGenerateDeleteButton="false"
Or Refer this too

how to find out the selected row in a gridview

I am doing a project in .net with c#. in that there is a registration form of new users into the site. admin should approve the registration. for that I'm using a GridView. How to find out the selected row in the grid view?
Use the GridView.SelectedRow property.
Alternatively, you can get the index of the selected row with the GridView.SelectedIndex property.
are you perhaps referring to a DATAGRIDVIEW?
if so, to find the content of a certain column of the selected row
datagridviewname.item(0, datagridviewname.currentrow.index).value
where 0 = first column of your datagrid
Use following gridview property>
gvTradeFile.SelectedRows[0].Cells[10].Value.ToString();
Hope this will help you.
Normally I use RowCommand for this type of thing:
<asp:GridView runat="server" id="gvUsers" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="username" HeaderText="Username" />
<asp:BoundField DataField="dateregistered" HeaderText="Date" />
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton runat="server" id="lnkApprove" CommandName="Approve" CommandArgument='<%# Eval("userid") %>' Text="Approve"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton runat="server" id="lnkDeny" CommandName="Deny" CommandArgument='<%# Eval("userid") %>' Text="Deny"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Now you need to pass instructions through on RowCommand...
private void gvUsers_RowCommand(Object sender, GridViewCommandEventArgs e)
{
switch (e.CommandName)
{
case "Approve":
// Executes code to update the users table,
// setting the approved flag to true
// Usage: ApproveUser(integer userid);
ApproveUser(e.CommandArgument);
break;
case else:
// do whatever if the user registration wasn't approved
break;
}
}
The switch is a good idea in case you need to do a few things with the data here. It evaluates the primary key value for the row (in this case, that's the value of the userid column in the database) for the selected row (automatically determined when you click the link) along with the CommandName to tell it what to do with that information.
Hope this helps.

Categories

Resources