Getting row index from an ImageButton click in a GridView - asp.net

I have a Gridview with ImageButtons added to a column via a templatefield. I've attached a function to the "OnClick" event.
Once in this function, how can I get the index of the row that has the button that has been clicked. It appears that all I have is the mouse coordinates on the page.

Instead of looping through the rows you can use this
<asp:ImageButton runat="server" id="ibtn1" ... RowIndex='<%# Container.DisplayIndex %>'
OnClick="button_click"/>
...
protected void button_click(object sender, EventArgs e){
ImageButton ibtn1 = sender as ImageButton;
int rowIndex = Convert.ToInt32(ibtn1.Attributes["RowIndex"]);
//Use this rowIndex in your code
}

Cast the sender to an ImageButton then cast the image button's NamingContainer to a row:
VB:
Dim btn as ImageButton = CType(sender, ImageButton)
Dim row as GridViewRow = CType(btn.NamingContainer, GridViewRow)
C#:
ImageButton btn = (ImageButton)sender;
GridViewRow row = (GridViewRow)btn.NamingContainer;

Would agree with bdukes that the simplest option is to use the CommandArgument. Bind your data's unique ID number into that property, then handle the _RowCommand event.
For example:
<asp:TemplateField >
<HeaderStyle Width="20" />
<ItemTemplate>
<asp:ImageButton ImageUrl="images/icons/iCal.png" CommandArgument='<%# Eval("Event_ID") %>' ToolTip="iCal" runat="server" Height="18" Width="18" />
</ItemTemplate>
</asp:TemplateField>
Protected Sub gv_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles gv.RowCommand
e.CommandArgument 'use this value in whatever way you like
End Sub

This is very good trick.
I have another trick also.
You can try it...
protected void userGridview_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{
GridViewRow rowSelect = (GridViewRow)(((Button)e.CommandSource).NamingContainer);
int rowindex = rowSelect.RowIndex;
}
}
It's a also good method.

The easiest way that I've found is to use the Command event over the Click event, and send the item ID as the command argument.
You could also loop over the rows in the GridView and compare the ImageButton in the row to the sender argument in your Click event.

Related

pass ID value to OnCheckedChange event in code behind

I have a gridview that has one checkbox for each row of data.
When the checkbox is checked or unchecked, I need to update a bit flag in my database.
I'm trying to use the OnCheckedChanged event.
It does fire, however I am getting a null error which has to do with an ID.
My problem is, I'm not quite sure how to get the needed ID to the OnCheckedChanged event code.
I need this ID to update the appropriate row in my database.
I found a few relavent questions on StackOverflow but none of the supplied answers really helped me out.
Thanks!
My gridview code:
<asp:GridView ID="gvlisting" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="Item Is Ready">
<ItemTemplate>
<asp:CheckBox ID="isReady" runat="server" AutoPostBack="true" OnCheckedChanged="isReady_CheckedChanged" Checked='<%#isReady(CInt(Eval("isReady")))%>'/>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Item Name">
<ItemTemplate>
<asp:Label ID="itemName" runat="server" Text='<%#cleanString(Eval("itemName").ToString())%>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
code behind:
Public Sub isReady_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim box As CheckBox = DirectCast(sender, CheckBox)
If box.Checked = True Then
'custom code for executing an SQL UPDATE statement
db.ExecuteNonQuery(AddIsreadyFlag, New SqlParameter("#itemID", Me.ID))
Else
db.ExecuteNonQuery(RemoveIsreadyFlag, New SqlParameter("#itemID", Me.ID))
End If
End Sub
Me.ID is the ID of the Page since Me is the current page-instance.
You could add another template-field with the ID:
<asp:TemplateField HeaderText="Item-ID" Visible="false">
<ItemTemplate>
<asp:Label ID="itemID" runat="server" Text='<%# Eval("itemID") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
Now you can use the NamingContainer to get the row and FindControl to get the label:
Public Sub isReady_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim box As CheckBox = DirectCast(sender, CheckBox)
Dim row = DirectCast(box.NamingContainer, GridViewRow)
Dim itemID = DirectCast(row.FindControl("itemID"), Label).Text
If box.Checked = True Then
'custom code for executing an SQL UPDATE statement
db.ExecuteNonQuery(AddIsreadyFlag, New SqlParameter("#itemID", itemID))
Else
db.ExecuteNonQuery(RemoveIsreadyFlag, New SqlParameter("#itemID", itemID))
End If
End Sub
You can also try to add a custom attribute in the OnDataBinding event and retrieve the value in de CheckChanged event.
protected void chkEnabled_DataBinding(object sender, EventArgs e)
{
CheckBox chk = (CheckBox)sender;
string id = Eval("Id").ToString();
chk.Attributes.Add("data-id", id);
}
protected void chkEnabled_CheckedChanged(object sender, EventArgs e)
{
CheckBox chk = (CheckBox)sender;
string id = chk.Attributes["data-id"];
}
Add the ID column to the grid, then if needed set it's visible property to false.
You can get the Gridview's selected row then get cell the value for ID column (the column does not need to be visisble, but it needs to exist in the grid).
var someVar = gvlisting.SelectedRow.Cells[0].Text; //change 0 to correct column
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.selectedrow(v=vs.110).aspx
You may need to do this in a SelectedIndexChanged but i doubt that, if that is the case you can easily get the data from the cell using the above or findcontrol like...How to find control in TemplateField of GridView?

How to fire a button event from inside a repeater?

I have done my research but can't find an efficient way to do the following in VB:
Each button should fire the same event.
The button event saves every repeater item and so each event is not unique.
I am aware I can use the ItemCommand option but have not been able to get it working as desired.
ASP.NET
Inside Repeater Item
<asp:Button ID="btnSave" RunAt="Server"/>
VB.NET
Protected Sub btnSave_Click(ByVal sender As Object, ByVal e As System.EventArgs)
sqlConn.Open()
For Each Item As RepeaterItem In rpt.Items
...
Next
sqlConn.Close()
End Sub
Edit:
After some research here on SO, I found that others events than ItemCommand are not caught by Asp:Repeater, as FlySwat said on his answer. So you'll need to write your VB.NET code like this:
First, declare the ItemCommand event on your page with something like this:
Protected Sub rpt_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles rpt.ItemCommand
If e.CommandName = "Save" Then
'Save
End If
End Sub
Then, on Asp:Button markup inside the Asp:Repeater, you must set its CommandName property like this:
<Asp:Button ID="btnSave" runat="server" CommandName="Save" UseSubmitBehavior="false"/>
Take a look here to learn more about the UseSubmitBehavior.
Try it.
When the button is inside a Repeater template, you need to add OnClick event, you can add event on ItemDataBound event of the Repeater control.
Your .aspx code will look something like this:
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:Button ID="btnSave" runat="server" Text="SomeText" />
</ItemTemplate>
</asp:Repeater>
code-behind
void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == Repeater1.AlternatingItem || e.Item.ItemType == Repeater1.Item)
{
var btn = e.Item.FindControl("btnSave") as Button;
if (btn != null)
{ // adding button event
btn.Click += new EventHandler(btn_Click);
}
}
}
void btn_Click(object sender, EventArgs e)
{
//write your code
}
in vb.net
Private Sub Repeater1_ItemDataBound(sender As Object, e As RepeaterItemEventArgs)
If e.Item.ItemType = Repeater1.AlternatingItem OrElse e.Item.ItemType = Repeater1.Item Then
Dim btn = TryCast(e.Item.FindControl("btnSave"), Button)
If btn IsNot Nothing Then
' adding button event
btn.Click += New EventHandler(btn_Click)
End If
End If
End Sub
Private Sub btn_Click(sender As Object, e As EventArgs)
'write your code
End Sub

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 %>'>

Can't find dropdown list in RowDataBound event

I'm following this example http://www.codeproject.com/KB/webforms/Editable_GridView.aspx to build an editable GridView control.
I have this code in my GridView:
<asp:TemplateField HeaderText="Negócio">
<ItemTemplate>
<asp:Label ID="lblNegocio" runat="server" Text='<%# Eval("Negocio") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="ddlNegocio" runat="server" />
</EditItemTemplate>
<FooterTemplate>
<asp:DropDownList ID="ddlNewNegocio" runat="server" />
</FooterTemplate>
Now, I'm trying to fill the dropdown in the EditItemTemplate with some dynamic values just as the example says, in the RowDataBound Event of the grid. But when I do this, the FindControl method always returns Nothing:
Protected Sub gdvRegraRotationDefault_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gdvRegraRotationDefault.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim ddlNegocio As DropDownList = e.Row.FindControl("ddlNegocio")
End If
End Sub
If I can't find the Dropdown I can't load the values in it and when I'm going to edit de entry it will be empty.
Can someone help me?
Thank you (:
Please use the RowEditing-Event, as your DropDownList should only be shown when clicking Edit.
But first, you have to bind the GridView newly as the GridView now needs to render different controls for the edit row:
protected void gdvRegraRotationDefault_RowEditing(object sender, GridViewEditEventArgs e)
{
gdvRegraRotationDefault.EditIndex = e.NewEditIndex;
gdvRegraRotationDefault.DataBind();
GridViewRow row = gdvRegraRotationDefault.Rows[e.NewEditIndex];
DropDownList ddl = row.FindControl("ddlNegocio") as DropDownList;
//now do databinding for DropDownList
}
The FindControl always return null because when your in the RowDataBound event you can get the label only.
If you want to fill the DropDownList when you click the edit button on the grid, then you have to use the GridViewRowEditing event.
In the RowDataBound event, simply add the following conditional:
if (myGridView.EditIndex == e.Row.RowIndex)
{
//do work
}

use a imageButton in GridView to select the row

I am trying to use a image button in a grid view to select a row so that i can then use the SelectedIndexChanged function to do other things. i have tried this:
<asp:ImageButton ID="Image1" CommandName="SelectRowGrid2" runat="server" ImageUrl="~/images/select.png" />
Protected Sub GridView2_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles GridView2.RowCommand
Select Case e.CommandName
Case "SelectRowGrid2"
'some code for selecting the index?
Label1.Text = GridView2.SelectedIndex
End Select
End Sub
but it didn't even step in to the RowCommand sub when i went to debug it.
You could set GridView's AutoGenerateSelectButton to true MSDN
You could set LinkButton's CommandName to "Select" MSDN
Or you could try following:
Protected Sub ImgSelect_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs)
Dim row As GridViewRow = DirectCast(DirectCast(sender, ImageButton).NamingContainer, GridViewRow)
DirectCast(row.NamingContainer, GridView).SelectedIndex = row.RowIndex
End Sub
aspx:
<asp:TemplateField HeaderText="Select">
<ItemTemplate >
<asp:ImageButton ID="ImgSelect" OnClick="ImgSelect_Click" runat="server" />
</ItemTemplate>
</asp:TemplateField>
I have done this plenty times in c#. Maybe I can help you out.
Some things I do different than you:
I call CellContentClick opposed to RowCommand.
2. I think check to see, which cell in the row was clicked
3. Check that the row is not null
4. If it was my image button cell, get my row data
1.
private void dgv_CellContentClick(object sender, DataGridViewCellEventArgs e)
2.
if (e.ColumnIndex == dgv.Columns["btnClmn"].Index)
3.
if (dgvAllApplication.CurrentRow != null)
4.
txtName.Text = dgv.CurrentRow.Cells["App_Name"].Value.ToString();
Good Luck!
you can create on click event on the imagebutton and do whatever you need to do on that row from there
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
ImageButton img = (ImageButton)sender;
GridViewRow row = (GridViewRow)img.Parent.Parent;
//do stuff
//find label in the same row
Label lbl = (Label)row.FindControl("Label1");
}

Resources