I have a gridview on my aspx page set up the OnRowCommand event using a series of ASP.NET LinkButton object to handle the logic using the CommandName property. I need to access the GridViewRow.RowIndex to retrieve values from the selected row and notice it is a non-public members of the GridViewCommandEventArgs object while debugging the application
Is there a way I can access this property of is theere a better implementation?
Here is my source code:
aspx page:
<asp:GridView ID="MyGridView" runat="server" OnRowCommand="MyGirdView_OnRowCommand">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton
id="MyLinkButton"
runat="server"
CommandName="MyCommand"
/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
code behind
protected void MyGirdView_OnRowCommand(object sender, GridViewCommandEventArgs e)
{
//need to access row index here....
}
UPDATE:
#brendan - I got the following compilation error on the following line of code:
"Cannot convert type
'System.Web.UI.WebControls.GridViewCommandEventArgs'
to
'System.Web.UI.WebControls.LinkButton'"
LinkButton lb = (LinkButton) ((GridViewCommandEventArgs)e.CommandSource);
I slightly modified the code and the following solution worked:
LinkButton lb = e.CommandSource as LinkButton;
GridViewRow gvr = lb.Parent.Parent as GridViewRow;
int gvr = gvr.RowIndex;
Not the cleanest thing in the world but this is how I've done it in the past. Usually I'll make it all one line but I'll break it down here so it's more clear.
LinkButton lb = (LinkButton) ((GridViewCommandEventArgs)e.CommandSource);
GridViewRow gr = (GridViewRow) lb.Parent.Parent;
var id = gr.RowIndex;
Basically you get your button and move up the chain from button to cell, from cell to row.
Here is the one row version:
var id = ((GridViewRow)((LinkButton)((GridViewCommandEventArgs)e).CommandSource).Parent.Parent).RowIndex;
Related
I have a nested GridView(GvMP_Summary_Items). Each row contains a DropDownList. The DropDownList is bounded on the RowDataBound event of the nested GridView.
Each row also contains 1 Button. Upon pressing this button on the RowCommand event, I would like to find the current selected value of the DropDownList so I can use it further on in the code.
The code I have will only get the default value of the DropDownList on each row, which is currently set at 0 for each row.
Below is the RowCommand Event:
Protected Sub GvMP_Summary_Items_RowCommand(sender As Object, e As GridViewCommandEventArgs)
Dim lb As ImageButton = CType(e.CommandSource, ImageButton)
Dim gvRow As GridViewRow = lb.BindingContainer //Getting current row to get index
Dim GvMP_Summary_Items As GridView = CType(gvRow.FindControl("GvMP_Summary_Items"), GridView)
Dim intMPItem_Qty As Integer = CType(gvRow.FindControl("cboMPItem_Qty"), DropDownList).SelectedValue
Dim strMPItem_Qty As String = CType(gvRow.FindControl("txtMPItem_Qty"), TextBox).Text
End Sub
I have even included a TextBox in the GridView row which default value is empty "". Although on the row if something is entered the on RowCommand event brings back the value with a comma(,) in front of it.
This proves that I am picking up the correct row and can retrieve a value from a TextBox but not a DropDownList.
Is there something I am missing? Why can I return a value entered in a TextBox but not the selected value of a DropDownList? Also why the comma(,) in front of the TextBox value?
Note: In above case code has been written using VB so answers in VB over C# but I can accept both.
This can be done very easily by casting the CommandSource of the RowCommand back to a button and then get the correct row from that. Once you have the row you can use FindControl to locate the DropDownList. This works on every level of nested items and also on the top Control.
VB
Protected Sub GMP_Summary_Items_RowCommand(ByVal sender As Object, ByVal e As GridViewCommandEventArgs)
'cast the commandsource back to a button
Dim btn As Button = CType(e.CommandSource,Button)
'get the current gridviewrow from the button namingcontainer
Dim row As GridViewRow = CType(btn.NamingContainer,GridViewRow)
'use findcontrol to locate the dropdownlist in that row
Dim ddl As DropDownList = CType(row.FindControl("cboMPItem_Qty"),DropDownList)
'show the selected value of the dropdownlist
Label1.Text = ddl.SelectedValue
End Sub
Code was translated from C# with a code translator, so it may not be 100% accurate.
C#
protected void GMP_Summary_Items_RowCommand(object sender, GridViewCommandEventArgs e)
{
//cast the commandsource back to a button
Button btn = e.CommandSource as Button;
//get the current gridviewrow from the button namingcontainer
GridViewRow row = btn.NamingContainer as GridViewRow;
//use findcontrol to locate the dropdownlist in that row
DropDownList ddl = row.FindControl("cboMPItem_Qty") as DropDownList;
//show the selected value of the dropdownlist
Label1.Text = ddl.SelectedValue;
}
You do need to bind data to the GridView and the DropDownLists in an
IsPostBack check, otherwise the data will be rebound to the DDL on every PostBack and the selected value is lost
Important things:
Bind parent GridView in Page_Load method
Bind child GridView in parent GridView 's RowDataBound event
Bind DropDownList in child GridView 's RowDataBound event
Add CommandName to the Button which is inside child GridView
Finally, in RowCommand event of child GridView
Get child GridView 's row
Then find all controls inside child GridView from child GridView 's row
I'm not so aware of VB.NET so I have added an example (C#) of Nested GridView with RowCommand event (hope OP can use it in VB.NET):
HTML code (.Aspx):
<form id="form1" runat="server">
<asp:GridView ID="GridView_Outer" OnRowDataBound="GridView_Outer_RowDataBound" AutoGenerateColumns="false" runat="server">
<Columns>
<asp:TemplateField HeaderText="Outer Column1">
<ItemTemplate>
<asp:Label ID="Label_Outer" runat="server" Text='<%# Eval("Label_Outer") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Outer Column2">
<ItemTemplate>
<asp:GridView ID="GridView_Inner" OnRowDataBound="GridView_Inner_RowDataBound" OnRowCommand="GridView_Inner_RowCommand" AutoGenerateColumns="false" runat="server">
<Columns>
<asp:TemplateField HeaderText="Inner Column1">
<ItemTemplate>
<asp:Label ID="Label_Inner" runat="server" Text='<%# Eval("Label_Inner") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Inner Column2">
<ItemTemplate>
<asp:TextBox ID="TextBox_Inner" Text='<%# Eval("TextBox_Inner") %>' runat="server"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Inner Column3">
<ItemTemplate>
<asp:DropDownList ID="DropDownList_Inner" runat="server"></asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Inner Column4">
<ItemTemplate>
<asp:Button ID="Button_Inner" runat="server" CommandName="BtnInnerCmd" Text="Inner Button" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<br />
<asp:Label ID="Label_Result" runat="server"></asp:Label>
</form>
Code-Behind (.Aspx.cs):
DataTable TempDT = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
CreateDataTable();
if (!IsPostBack)
{
GridView_Outer.DataSource = TempDT;
GridView_Outer.DataBind();
}
}
// create DataTable
public void CreateDataTable()
{
TempDT = new DataTable();
TempDT.Columns.Add("Label_Outer");
TempDT.Columns.Add("Label_Inner");
TempDT.Columns.Add("TextBox_Inner");
TempDT.Rows.Add("OuterLabel", "InnerLabel", "");
TempDT.Rows.Add("OuterLabel", "InnerLabel", "");
// store DataTable into ViewState to prevent data loss on PostBack
ViewState["DT"] = TempDT;
}
// Calls Outer GridView on Data Binding
protected void GridView_Outer_RowDataBound(object sender, GridViewRowEventArgs e)
{
// check if gridview row is not in edit mode
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Get Outer GrridView 's controls
Label Label_Outer = (Label)e.Row.FindControl("Label_Outer");
GridView GridView_Inner = (GridView)e.Row.FindControl("GridView_Inner");
// get DataTable from ViewState and set to Inner GridView
GridView_Inner.DataSource = (DataTable)ViewState["DT"];
GridView_Inner.DataBind();
}
}
// Calls Inner GridView on Data Binding
protected void GridView_Inner_RowDataBound(object sender, GridViewRowEventArgs e)
{
// check if gridview row is not in edit mode
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Get Outer GrridView 's controls
DropDownList DropDownList_Inner = (DropDownList)e.Row.FindControl("DropDownList_Inner");
// Create a DataTable to Bind data for DropDownlist
DataTable TempDDLDT = new DataTable();
TempDDLDT.Columns.Add("ItemText");
TempDDLDT.Columns.Add("ItemValue");
TempDDLDT.Rows.Add("ItemText1", "ItemValue1");
TempDDLDT.Rows.Add("ItemText2", "ItemValue2");
// bind DataTable to the DropDownList
DropDownList_Inner.DataSource = TempDDLDT;
DropDownList_Inner.DataTextField = "ItemText";
DropDownList_Inner.DataValueField = "ItemValue";
DropDownList_Inner.DataBind();
}
}
// Calls when Inner GridView 's button clicked
protected void GridView_Inner_RowCommand(object sender, GridViewCommandEventArgs e)
{
// get Inner GridView 's clicked row
GridViewRow InnerGridViewRow = (GridViewRow)(((Control)e.CommandSource).NamingContainer);
// get Inner GridView 's controls from clicked row
TextBox TextBox_Inner = (TextBox)InnerGridViewRow.FindControl("TextBox_Inner");
DropDownList DropDownList_Inner = (DropDownList)InnerGridViewRow.FindControl("DropDownList_Inner");
// check if correct button is clicked
if (e.CommandName == "BtnInnerCmd")
{
string DropDownListValue = DropDownList_Inner.SelectedValue;
string TextBoxValue = TextBox_Inner.Text;
Label_Result.Text = "DropDownList 's Selected Value is " + DropDownListValue +
"<br />TextBox 's Entered Value is " + TextBoxValue;
}
}
Demo Image:
Note: Above DropDownList selects Selected Value not Text.
While getting the value I'm getting Object reference not set to an instance of an object. how to get labeled label value in code behind. How to get the value in custom event
<asp:GridView runat="server" ID="gridviewQuoteDetails" EmptyDataText="No records Found..." AutoGenerateEditButton="false" OnRowEditing="gridviewQuoteDetails_RowEditing" OnRowUpdating="gridviewQuoteDetails_RowUpdating" DataKeyNames="id" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<a href='Quote.aspx?val=<%#Eval("id")%>'>
<asp:Label ID="lblid" runat="server" Text='<%#Eval ("id")%>'></asp:Label>
</a>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" Text="Edit" runat="server" CommandName="Edit" />
</ItemTemplate>
<EditItemTemplate>
<asp:LinkButton ID="LinkButton2" Text="Update" runat="server" OnClick="OnUpdate" />
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
code behind
protected void OnUpdate(object sender, EventArgs e)
{
string qouteid = ((Label)gridviewQuoteDetails.FindControl("lblid")).Text;
GridViewRow row = (sender as LinkButton).NamingContainer as GridViewRow;
string id = (row.Cells[0].Controls[0] as TextBox).Text;
string Description = (row.Cells[1].Controls[0] as TextBox).Text;
}
Gridview is a collection of rows right, but you are trying to search the control directly within the gridview thus ((LinkButton)gridviewQuoteDetails.FindControl("lbllnknm")) will be null and when you are trying to access the Text property of LinkButton you are getting NRE error.
You need to loop through the rows of your gridview control to access each linkbutton present in each row like this:-
foreach (GridViewRow row in gridviewQuoteDetails.Rows)
{
LinkButton lbllnknm= row.FindControl("lbllnknm") as LinkButton;
}
But ideally you would not be needing this. I guess you are trying to get the value in OnRowEditing event handler. If that is the case then you can fetch the value of linkbutton like this:-
protected void gridviewQuoteDetails_RowEditing(object sender, GridViewUpdateEventArgs e)
{
string qouteid = ((Label)gridviewQuoteDetails.Rows[e.NewEditIndex]
.FindControl("lbllnknm")).Text;
}
Update 2:
As per your comment you are trying to access the LinkButton text on click of LinkButton itself which means the event is raised by LinkButton itself. You can simply use the sender object like this:-
protected void OnUpdate(object sender, EventArgs e)
{
LinkButton LinkButton2 = sender as LinkButton;
GridViewRow row = LinkButton2.NamingContainer as GridViewRow; //Get the gridview row
Label lblid = row.FindControl("lblid") as Label;
string qouteid = lblid.Text;
}
This is the code in UI
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btn" runat="server" CommandName="Edit" Text="AFE" />
</ItemTemplate>
</asp:TemplateField>
--</Columns>
I Want to Get the Details of All Fields in Text boxes in Same page when ever I click on the Button Edit. I Tried using :
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Edit")
{
GridViewRow Row = (GridViewRow)(((Button)e.CommandSource).NamingContainer);
string text = Row.Cells[2].Text;
}
But I am getting "" in string text..
This is screenshot of my grid view
You can use the row index stored in command argument to find a row where Edit button is clicked.
Now you can find the TextBox in that row where cell index location is 2.
Then get the Text of your TextBox.
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if(e.CommandName == "Edit")
{
int index = Convert.ToInt32(e.CommandArgument);
GridViewRow clickedRow = CustomersGridView.Rows[index];
TextBox myTextBox = (TextBox)clickedRow.Cells[2].FindControl("TextBoxName");
string text = myTextBox.Text;
}
}
In ASPX page, you need to handle row command event like this:
<asp:gridview id="GridView1"
datasourceid="DataSource"
autogeneratecolumns="false"
onrowcommand="GridView1_RowCommand"
runat="server">
</asp:gridview>
You can access to GridViewRow using following code (note: the Button must be the control that has CommandName/CommandArgument):
var row = (GridViewRow)(((Button)e.CommandSource).NamingContainer);
Then simply use FindControl method on found row to find your target control, for ex.:
var txtSomething = (TextBox)row.FindControl("txtSomething");
Also you can access to RowIndex using row.RowIndex.
I recommended avoid using row.Cells[INDEX].FindControl(), just row.FindControl works just fine, targeting specific cell isn't good, if you change the markup and add/remove some columns, (maybe) you need to update the INDEX too, so don't do that :)
You need to find the TextBox control in the cell and get the value from it.
string text = (TextBox)Row.FindControl["MyTextBoxId"].Text;
I am confused with this problem.
I have put a button in side the template field of a gridview and want to return the data from that specific GridView Row when that corresponding button is clicked.
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="Button2" CssClass ="btnSkin" runat="server" Text="Answer" Width="117px" onclick="Button2_Click" />
</ItemTemplate>
</asp:TemplateField>
In the button click event fireup, I want to read that data by creating a GridViewRow Element.
protected void Button2_Click(object sender, EventArgs e)
{
GridViewRow gvr = (GridViewRow)(sender as Control).Parent.Parent;
Label8.Text = gvr.Cells[1].Text;
Label10.Text = gvr.Cells[2].Text;
Label12.Text = gvr.Cells[3].Text;
}
Now the problem is, the GridViewRow Cells are returning empty strings.
What should I do?????
When using <asp:TemplateFields>, you actually need to find the text which is inside your controls such as <asp:Label> you used inside your <ItemTemplate>.
Cells won't have text, its the Controls inside the cells that have text.
So, If suppose , you have a Label inside one of your <ItemTemplate> as:
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("CustomerID") %>'>
</asp:Label>
</ItemTemplate>
Then access the Text of this Label control using below code in your button Click event:[ assuming, 2nd Column contains the above <ItemTemplate> defined ]
protected void Button2_Click(object sender, EventArgs e)
{
GridViewRow gvr = (GridViewRow)(sender as Control).Parent.Parent;
String str = ((Label)gvr.Cells[1].FindControl("Label1")).Text;
}
I found the reason behind the empty strings error.
Gridview.Cells[i].Text will return the string value only when it is a <asp:BoundField>
If it is a <asp:TemplateField> and you have some ASP control inside the <ItemTemplate>, you must follow the FindControl("<control_id>") approach.
Here, basically we look for the control object in that particular GridviewRow Cell by its ID and cast it into the corresponding Control Type. Now, we can use that as we call any other asp control from code-behind.
String str = ((Label)gvr.Cells[1].FindControl("Label1")).Text;
Try using GridView.RowCommand Event and refer the following link for the same
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.rowcommand.aspx
hope this helps you.
Please check whether you are binding the grid properly on Page Load.
if(!IsPostBack)
{
BindgridView();
}
Hope this helps..Give a try..
I have a gridview in my form. I am working with RowDataBound event to the grid. Now I have a template field inside columns of the gridview. A label has been taken inside template field. I want to add a link to this label on RowDataBound event at runtime, but .System.Web.UI.WebControls.LinkButton is showing instead of link button.
How do I add a link button with label text in the grid view?
Just add a linkbutton inside your templatefield
<asp:GridView runat="server" ID="gridView">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton runat="server" ID="lnkTest"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Then in your rowdatabound event you can find it and do whatever you want
void gridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
Entity entity = e.Row.DataItem as Entity;
LinkButton lnkTest = e.Row.FindControl("lnkTest") as LinkButton;
lnkTest.CommandArgument = entity.ID.ToString();
lnkTest.Text = entity.Name;
}
}
You can then subscribe to gridview Command event and correct CommandArgument will be passed when clicking by linkbutton.
Hope this helps.