gridview linkbutton CommandArgument value not changing - c#

I have a grid view with a list of data and a LinkButton to delete the row.
<asp:GridView ID="gridApartment" EmptyDataText="No Records Found" runat="server" AutoGenerateColumns="False" BorderWidth="0"
AllowPaging="true" ShowFooter="false" PageSize="15" Width="100%" OnPageIndexChanging="gridApartment_PageIndexChanging"
CssClass="mGrid"
OnRowDeleting="gridApartment_RowDeleting" OnRowCommand="gridApartment_RowCommand">
<AlternatingRowStyle CssClass="alt" />
<PagerStyle CssClass="pgr" />
<Columns>
<asp:TemplateField HeaderText="Building">
<ItemTemplate>
<asp:Label ID="BuildingName" runat="server" Text='<%#Eval("BuildingName") %>'></asp:Label>
</ItemTemplate>
<HeaderStyle Width="25%"></HeaderStyle>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="lnkDelete" CssClass="aDelete" ToolTip="Delete" runat="server" CommandName="delete" OnClientClick=' javascript:return confirm("Are you sure you want to delete?"); '
CommandArgument='<%# Eval("RoomDetailsId") %>'>Delete</asp:LinkButton>
</ItemTemplate>
<HeaderStyle Width="8%"></HeaderStyle>
</asp:TemplateField>
</Columns>
</asp:GridView>
onload data filled by this code
gridApartment.DataSource = masterManager.GetAllRooms();
gridApartment.DataBind();
now i have a search box, and when i search, the filters result will get bind by this code.
gridApartment.DataSource = conobj.GetSearchDetails("usp_RoomDetailsSearch", "#SearchName", txtSearchterm.Text.Trim());
gridApartment.DataBind();
for delete the code is
protected void gridApartment_RowCommand(object sender, System.Web.UI.WebControls.GridViewCommandEventArgs e)
{
if (e.CommandName == "delete")
{
var masterManager = new MasterEntryManager();
int res = masterManager.DeletRoom(e.CommandArgument.ToString());
Search();
}
}
when the first time the grid get loaded e.CommandArgument has the right ID and i can delete the right row. But when i search and re bind the gridview, the e.CommandArgument value is not updated with new ID. It still return the same ID which is loaded first on page load.
For eg:
when the grid is first loaded, when i try delete the first row, e.CommandArgument has an ID say, 1001 and I deleted the record with ID 1001.
Now I load the gridview second time. Now the 1st row linkbutton e.CommandArgument has ID 1500.
I perform a search and the result grid has only 5 rows
Now i try to delete the first row, the expected linkbutton e.CommandArgument ID is say 2001, but i get the linkbutton e.CommandArgument ID as 1500, the value of first row ID when the gridview first loaded
Id is not get updated.
How can I get the updated e.CommandArgument value.?

Counter to expectations, the CommandArgument is not associated with the control that does the post back. Rather, the DataSource is returned as part of the ViewState, and the CommandArgument is referenced by the index of the control. If either the GridView or DataSource change, the index will no longer be correct.
You need to make sure that the GridView and DataSource are not updated prior referencing the CommandArgument, but then updated after the delete (it looks like you have this part). Remember that the post back event occurs after the page load.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
gridApartment.DataSource = masterManager.GetAllRooms();
gridApartment.DataBind();
}
}

Related

Get column value from GridView

I'm new to ASP.NET and I am using GridView to display data on a web page. I also added a button in Gridview called process orders.
<asp:GridView ID="GridView1" runat="server" autogenerateselectbutton="True" GridLines="None" AllowPaging ="true"
OnRowCommand="GridView1_RowCommand" OnSelectedIndexChanged="GridView1_SelectedIndexChanged"
>
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="Process" runat="server"
CommandName="processorders"
CommandArgument="<%# ((GridViewRow) Container).RowIndex %>"
Text="Process orders" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
I used the row command method to get the selected index of the row.
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "processorders")
{
// Retrieve the row index stored in the
// CommandArgument property.
int index = Convert.ToInt32(e.CommandArgument);
}
Also I've implemented selectedIndexChanged method for the default select button:
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
GridViewRow row = GridView1.SelectedRow;
txtbox.Text = "You selected " + row.Cells[3].Text + ".";
}
If I try to use the GridViewRow in GridView1_RowCommand I get a null pointer exception. The row is always null but it works fine in GridView1_SelectedIndexChanged.
What am I trying to achieve is, get the column value from the selected row using my Process button and then use that value to update a database. I don't want to do it using Select.
And is there any way I can use row.Cells[] without specifying the index. I want to get the value of a column name.
Help? Please ??

How do I pass the number of rows in GridView as an argument to OnRowCommand call

I am trying to make a button & checkbox display on a GridView dynamically only if there is more than 1 row in the GridView. (The view is results based on a search for users, so the number of rows is dynamic based on the search results)
The purpose of button and checkbox allow me to combine 2 or more user accounts. There is no point showing this button if there is only 1 row in the GridView (its confusing), so I set "Visible" parameter using a function. However, using GridViewID.Rows.Count in this function does not work. (What I figure it is actually the max number of rows displayed from when the call to function is taking place). ie: call from 2nd row of Gridview gives me Row.Count=2. So I am trying to pass a hidden control instead, but it is not working.
Here is my code:
<asp:GridView ID="GridView1" runat="server" OnRowCommand="GridView1_RowCommand">
<Columns>
<asp:TemplateField ShowHeader="false">
<ItemTemplate>
<asp:HiddenField ID="HiddenUserID" runat="server" Visible="false" Value= '<%#Eval("UserID") %>' ></asp:HiddenField>
<asp:HiddenField ID="NumberRowsGridView" runat="server" Visible="false" Value='<%#Bind("NumberRowsGridView") %>'></asp:HiddenField>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="UserName" HeaderText="User Name"/>
<asp:BoundField DataField="Email" HeaderText="Email Address"/>
<asp:TemplateField ShowHeader="false">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" Visible='<%# ShowMergeUserButton((String)Eval("UserName"),(String)Eval("Email"),(String)Eval("NumberRowsGridView")) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ShowHeader="True" HeaderText="Merging Actions">
<ItemTemplate>
<asp:Button ID="Button3" runat="server" CausesValidation="false" CommandName="MergeIntoUser"
Text="Merge Into This Account" CommandArgument='<%# Container.DataItemIndex + "," + Eval("UserID")%>' Visible='<%# ShowMergeUserButton((String)Eval("UserName"),(String)Eval("Email"),(String)Eval("NumberRowsGridView")) %>'/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
The code behind function:
protected Boolean ShowMergeUserButton(String Username, String Email, String NumRows)
{
return (Username == Email && Convert.ToInt32(NumRows) > 1);
}
I have created a Hidden field and tried to insert it into the GridView, but my code has a runtime error: (Note, I'm new to ASP :)
protected System.Web.UI.WebControls.HiddenField NumberRowsGridView;
-- in function that populates GridView
-- dt is the data source
GridView1.DataSource = dt;
GridView1.DataBind();
NumberRowsGridView.Value = dt.Count<items>().ToString();
The error I get is:
System.Web.HttpException: DataBinding: 'MyASPPageName+dt' does not contain a property with the name 'NumberRowsGridView'.
So I'm basically doing this completely wrong.
This won't answer your question about how to do it in the markup, but when things get complicated like that, I like to go a simpler route. What you could do instead is hide/show the buttons once the entire GridView is bound.
Add the DataBound event to your GridView.
<asp:GridView ID="GridView1" runat="server"
OnRowCommand="GridView1_RowCommand"
OnDataBound="GridView1_DataBound">
Then in this event, all your rows will have been bound. So if you have more than one row, show the button. If not, hide the button. This should give you an idea.
protected void GridView1_DataBound(object sender, EventArgs e)
{
if (GridView1.Rows.Count > 1)
{
foreach (GridViewRow row in GridView1.Rows)
{
Button Button3 = (Button)row.FindControl("Button3");
Button3.Visible = true;
}
}
}
If you must do it in the markup, Enrique Zavaleta's answer should get you there.
I'm not sure what you are trying to accomplish, but this should solve your problem:
Add a property like this in your code, the ViewState will keep your value through the life-cycle of the page.
public string NumberRowsGridView
{
get { return ViewState["NumberRowsGridView"] == null ? null : ViewState["NumberRowsGridView"].ToString(); }
set { ViewState["NumberRowsGridView"] = value; }
}
now edit this part of your code like this
NumberRowsGridView = dt.Count<items>().ToString();
GridView1.DataSource = dt;
GridView1.DataBind();
and the button markup like this
<asp:Button ID="Button3" runat="server" ... Visible='<%# ShowMergeUserButton((String)Eval("UserName"),(String)Eval("Email"), NumberRowsGridView) %>'/>
it should work properly
Since OnRowCommand is an event you can get that information from your event handler. In your codebehind find the GridView1_RowCommand event handler and cast the object sender to GridView like this...
void GridView1_RowCommand(Object sender, GridViewCommandEventArgs e)
{
GridView gridView = (GridView)sender;
int numOfRows = gridView.Rows.Count;
// Now you can do something with numOfRows!
}
As far as the other things you are wanting to do, you may want to create a new question that is more specific to those other tasks. But there is no need to pass the number of rows to the event handlers of a GridView because the sender object(the GridView that fired the event) will have all these properties. Hope this helps.

How to get cell data from gridview?

I am trying to fetch data from certain GridView row when I click link in that row...
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="AccessDataSource1" AllowPaging="True">
<Columns>
<asp:BoundField DataField="nazivTeme" HeaderText="nazivTeme"
SortExpression="nazivTeme" />
<asp:BoundField DataField="datum" HeaderText="datum" SortExpression="datum" />
<asp:TemplateField HeaderText="View">
<ItemTemplate>
<asp:LinkButton runat="server" ID="lnkView" commandname="view"
OnClick="lnkView_Click">Komentiraj</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
I would like to get data from the row where I click the LinkButton (only first cell).
I hope you understand what I want :)
Do not subscribe to Click event of the button. Instead, subscribe to the RowCommand event of the grid view. Then, in the event handler, you can evaluate which command was received and which row was affected. Once you get the row, you can get its cell value by cell index or ID:
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "view")
{
// Retrieve the row index
int index = Convert.ToInt32(e.CommandArgument);
// Retrieve the row by its index
GridViewRow row = this.GridView1.Rows[index];
// Get the 1st cell value from the row
string cellValue = r.Cells[0].Text;
}
}

How to add dynamic hyperlink in Grid View according to certain condition [duplicate]

In my Website, I currently use a grid view which generates data from 3 tables namely status, Project_glance, Application_header. SQL Query returns 4 columns but in my grid-view i only shows 3 columns. The last column returns the Status_id of the project.The following is my .aspx code:
<asp:GridView ID="grdProf" runat="server" AllowPaging="True" AutoGenerateColumns="false" OnPageIndexChanging="grdProf_PageIndexChanging">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:HyperLink ID="hlnkView" Visible="true" Text="View" runat="server" > </asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="ApplicationID" HeaderText="ApplicantionID" />
<asp:BoundField DataField="PRGLProjectTitle" HeaderText="Project Title" />
<asp:BoundField DataField="Status" HeaderText="Project Status" />
</Columns>
</asp:GridView>
If the Status_id > 15 then only view hyperlink will visible otherwise the View hyperlink text will be changed to 'Edit' and a navigate URL will add to this hyperlink and another hyperlink 'Delete' will show to allow user to delete the project detail.
Please help me to find the correct solution for this..
First, add the delete Hyperlink to your ItemTemplate.
Then, to be able to access your Status_id field, you'll want to add that to your GridView's DataKeys.
Then, you can subscribe to your GridView's RowDataBound method, grab the Hyperlinks, check the status_id, and set the Hyperlinks' visibility accordingly.
<asp:GridView DataKeyNames="status_id"
<ItemTemplate>
<asp:HyperLink ID="hlnkView" Visible="true" Text="View" runat="server" >
<asp:HyperLink ID="hlnkDelete" Visible="false" Text="Delete" runat="server" >
</asp:HyperLink>
void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) {
HyperLink delHl = e.Row.Cells[0].FindControl("hlnkDelete") as HyperLink;
int statusId = (int)(sender as GridView).DataKeys[e.Row.RowIndex].Value;
delHl.Visible = statusId <= 15;
}
Like this
protected void grdProf_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView rowView = (DataRowView)e.Row.DataItem;
// Retrieve the status value for the current row.
string status = rowView["Status"].ToString();
//Now you have the status
//get a reference to view hyperlink and hide it if that's the case
Hyperlink hlnkView = e.Row.FindControl("hlnkView") as HyperLink;
//example:
if(int.Parse(status)>15)
hlnkView .Visible=false;//you are done
}
}
As far as displaying an "edit" hyperlink, I would have an extra column next to the "view" column and hide or display this other hyperlink as necessary since in some cases you'll need one hyperlink column and in some cases you'll need two.

Get GridView Row

I have a GridView which I bind to a SqlDataReader on Page_Load. It has a column with buttons and I am trying to get the row when a button is clicked with the following code:
int index = Convert.ToInt32(e.CommandArgument);
GridViewRow row = GridView1.Rows[index];
EDIT : Pasting the .aspx page from the comments sectio
<asp:GridView ID="GridView1" runat="server" CellPadding="4" ForeColor="#333333" OnRowCommand="GridView1_RowCommand" DataKeyNames="id" GridLines="None"> <AlternatingRowStyle BackColor="White" />
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btnChange" runat="server" Text="Change" CommandName="Test" Visible='<%# Convert.ToBoolean(Eval("Tested")) == true ? true : false %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</aspx:GridView>
I get the following error: 'System.FormatException: Input string was not in a correct format.' on line 'int index = Convert.ToInt32(e.CommandArgument);'.
Any ideas?
You need to check which command in the GridView row has been clicked. Your markup should correspondingly map. See egs below.
The e.CommandArgument you are getting may not correspond to your button click.
In CodeBehind:
void GridView1_RowCommand(Object sender, GridViewCommandEventArgs e)
{
// If multiple buttons are used in a GridView control, use the CommandName property to determine which button was clicked.
if(e.CommandName=="Add")
{
// Convert the row index stored in the CommandArgument property to an Integer.
int index = Convert.ToInt32(e.CommandArgument);
// Retrieve the row that contains the button clicked by the user from the Rows collection.
GridViewRow row = CustomersGridView.Rows[index];
// additional logic...
}
// additional logic...
}
In Markup:
Also please ensure you have set your CommandArgument attribute appropriately. Example below:
<asp:Button (...) CommandArgument="<%# Container.DataItemIndex %>" />
OR use a buttonfield
<asp:ButtonField ButtonType="button" CommandName="Add" Text="Add" />
Can u post the whole markup code,it would be helpful to solve. according to your question
in gridview aspx code you have to use Command Name, and command Argument for the Button Control and it should bind to the one of the column of db. and use Row Command event of gridview. And also Try to use ItemTemplate to put Control Inside the gridview.
Click here for MSDN Documentation. Row Command in GridView
protected void Grid_RowCommand( object sender, GridViewCommandEventArgs e )
{
int index = Convert.ToInt32( e.CommandArgument );
your logic .......
}
You have not added value to the command Argument. For your Button event in .aspx page
<asp:Button ID="btnChange" runat="server" Text="Change" CommandName="Test" CommandArgument = 1 Visible='<%# Convert.ToBoolean(Eval("Tested")) == true ? true : false %>' />
In the code behind i.e the RowCommand Event
if(e.CommandName == "Test")
{
int index = Convert.ToInt32(e.CommandArgument);
}
This will work only for value 1. To make it generic you can bind the command Argument to the value you want using one of the binding techniques for example : CommandArgument ='<%# Eval("ID") %>' (Assuming ID is present in the GridView)
Check out this code
void ContactsGridView_RowCommand(Object sender,GridViewCommandEventArgs e)
{
// If multiple buttons are used in a GridView control, use the
// CommandName property to determine which button was clicked.
if(e.CommandName=="Add")
{
// Convert the row index stored in the CommandArgument
// property to an Integer.
int index = Convert.ToInt32(e.CommandArgument);
// Retrieve the row that contains the button clicked
// by the user from the Rows collection.
GridViewRow row = ContactsGridView.Rows[index];
// Create a new ListItem object for the contact in the row.
ListItem item = new ListItem();
item.Text = Server.HtmlDecode(row.Cells[2].Text) + " " +
Server.HtmlDecode(row.Cells[3].Text);
// If the contact is not already in the ListBox, add the ListItem
// object to the Items collection of the ListBox control.
if (!ContactsListBox.Items.Contains(item))
{
ContactsListBox.Items.Add(item);
}
}
}
Below html code for gridview
<asp:gridview id="ContactsGridView"
datasourceid="ContactsSource"
allowpaging="true"
autogeneratecolumns="false"
onrowcommand="ContactsGridView_RowCommand"
runat="server">
<columns>
<asp:buttonfield buttontype="Link"
commandname="Add"
text="Add"/>
<asp:boundfield datafield="ContactID"
headertext="Contact ID"/>
<asp:boundfield datafield="FirstName"
headertext="First Name"/>
<asp:boundfield datafield="LastName"
headertext="Last Name"/>
</columns>
</asp:gridview>
Check link Gridview commands
Hope this answer helps you.

Categories

Resources