I have an asp.net GridView:
<asp:TemplateField HeaderText="View Faktor" ShowHeader="False" Visible="True">
<ItemTemplate>
<asp:ImageButton ID="imgBtn1" CssClass="SelectRow" runat="server" CausesValidation="false"
CommandArgument='<%#(eval("mprID")) %>' CommandName="ViewFactors" ImageUrl="~/tadarokat/Images/factor.png"
Text="" />
</ItemTemplate>
</asp:TemplateField>
How Can I get rowIndex on row command event?
I want to highlight (select) target row when RowCommand fires.
this is answer for your question.
GridViewRow gvr = (GridViewRow)((ImageButton)e.CommandSource).NamingContainer;
int RowIndex = gvr.RowIndex;
ImageButton \ Button etc.
CommandArgument='<%# Container.DataItemIndex%>'
code-behind
protected void gvProductsList_RowCommand(object sender, GridViewCommandEventArgs e)
{
int index = e.CommandArgument;
}
Or, you can use a control class instead of their types:
GridViewRow row = (GridViewRow)(((Control)e.CommandSource).NamingContainer);
int RowIndex = row.RowIndex;
If you have a built-in command of GridView like insert, update or delete, on row command you can use the following code to get the index:
int index = Convert.ToInt32(e.CommandArgument);
In a custom command, you can set the command argument to yourRow.RowIndex.ToString() and then get it back in the RowCommand event handler. Unless, of course, you need the command argument for another purpose.
I was able to use #rahularyansharma's answer above in my own project, with one minor modification. I needed to get the value of particular cells on the row on which the user clicks a LinkButton. The second line can be modified to get the value of as many cells as you wish.
Here is my solution:
GridViewRow gvr = (GridViewRow)(((LinkButton)e.CommandSource).NamingContainer);
string typecore = gvr.Cells[3].Text.ToString().Trim();
protected void gvProductsList_RowCommand(object sender, GridViewCommandEventArgs e)
{
try
{
if (e.CommandName == "Delete")
{
GridViewRow gvr = (GridViewRow)(((ImageButton)e.CommandSource).NamingContainer);
int RemoveAt = gvr.RowIndex;
DataTable dt = new DataTable();
dt = (DataTable)ViewState["Products"];
dt.Rows.RemoveAt(RemoveAt);
dt.AcceptChanges();
ViewState["Products"] = dt;
}
}
catch (Exception ex)
{
throw;
}
}
protected void gvProductsList_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
try
{
gvProductsList.DataSource = ViewState["Products"];
gvProductsList.DataBind();
}
catch (Exception ex)
{
}
}
Related
I am developing a Web Form, where I show Gridview with data. One of the column consists of CheckBox. How can I update data in particular row.
so my question is:
How to unidentified particular row and send an sql request with UPDATE when user Check or Uncheck the CheckBox?
Update:
Here is my code that i have. It doesn't update value of CheckBox.
namespace:
public partial class Call_Bills : System.Web.UI.Page
{
SqlConnection con = new SqlConnection();
string check;
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button_Submit(object sender, EventArgs e)
{
foreach (GridViewRow row in GridView2.Rows)
{
con.ConnectionString = ConfigurationManager.ConnectionStrings["TestDeductionsConnectionString2"].ToString();
con.Open();
bool private1 = (row.FindControl("CheckBox1") as CheckBox).Checked;
if (private1 == true)
{
check = "1";
}
else
{
check = "0";
}
SqlCommand cmd = new SqlCommand("insert into DetailCosts(private) values(#private)", con);
cmd.Parameters.AddWithValue("#private", check);
cmd.ExecuteNonQuery();
}}
name of GridView is: GridView2;
name of Checkbox in the Table: private;
id of CheckBox in Gridview is:
<asp:TemplateField HeaderText="Private" SortExpression="private">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" Checked='<%# Eval("private") %>' />
</ItemTemplate>
<HeaderStyle HorizontalAlign="Center" />
</asp:TemplateField>
you can manually define a method to handle a postback generated by a control inside a gridview column. To do that you just need to add the tags AutoPostBack=True and OnCheckedChanged=YourMethodName to the control.
On the code-behind, define this method as public void, and define the parameters that usually would be there (sender as object and e as EventArgs), like:
public void YourMethodName(object sender, EventArgs e)
On the method, you may need to get the GridViewRow which contains the control that has generated the event. To do that, just parse the sender parameter (which will be the checkbox) and get 2 parent levels (GridViewCell and GridViewRow), it would be something like:
GridViewRow row = ((CheckBox)sender).parent.parent;
Since you have the row, you may get any control inside it with the FindControl method. If you need an id to identify the entitiy being updated, you may store it in a hidden field inside the row.
Hope it helps!
I have a problem that's been driving me nuts. Any help would be much appreciated. I have a grid view that displays what research items are assigned to what people. It should be possible to change the assignments using a dropdown. Here's the markup:
<asp:GridView ID="assignmentsGridView" runat="server" AutoGenerateColumns="false" CellPadding="2" Font-Size="Smaller"
OnRowDataBound="assignmentsGridView_RowDataBound" OnRowCommand="assignmentsGridView_RowCommand">
<Columns>
<asp:BoundField HeaderText="Ticker" DataField="Item" />
<asp:BoundField HeaderText="Name" DataField="Name" />
<asp:TemplateField HeaderText="Assignment" ItemStyle-HorizontalAlign="Center" ControlStyle-Font-Size="Small">
<ItemTemplate>
<asp:DropDownList ID="assignmentDropDown" runat="server" Visible="true"
OnSelectedIndexChanged="assignmentDropDown_SelectedIndexChanged" AutoPostBack="true" >
<asp:ListItem Text="Joe" Value="Joe"></asp:ListItem>
<asp:ListItem Text="Aron" Value="Aron"></asp:ListItem>
<asp:ListItem Text="Frank" Value="Frank"></asp:ListItem>
<asp:ListItem Text="Ross" Value="Ross"></asp:ListItem>
<asp:ListItem Text="Alex" Value="Alex"></asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="Analyst Complete" DataField="AnalystComplete" ItemStyle-HorizontalAlign="Center" ControlStyle-Font-Size="Smaller"/>
<asp:TemplateField HeaderText="Mark Complete" ControlStyle-Font-Size="Smaller">
<ItemTemplate>
<asp:Button ID="completeButton" runat="server" Text="Incomplete" CommandArgument='<%# Eval("Item") %>'
CommandName="Complete" Font-Size="Smaller" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
I want to update the database when the user changes the SelectedIndex of the dropdown. I'm handling that here:
protected void assignmentDropDown_SelectedIndexChanged(object sender, EventArgs e)
{
if (Session["IsCompany"] == null)
{
Session["IsCompany"] = assignmentsDropDown.SelectedValue == "Company";
}
bool? isCompany = Session["IsCompany"] as bool?;
int isCo = (isCompany == true) ? 1 : 0;
DropDownList ddl = sender as DropDownList;
GridViewRow gvr = ddl.NamingContainer as GridViewRow;
//ri is always 0!
int ri = gvr.RowIndex;
gvr = (GridViewRow)(((Control)sender).NamingContainer);
//ri is always 0!
ri = gvr.RowIndex;
gvr = ((GridViewRow)ddl.Parent.Parent);
//ri is always 0!
ri = gvr.RowIndex;
string selAnalyst = ddl.SelectedValue;
//selAnalsyt always = initial value!
selAnalyst = ddl.SelectedItem.Value;
//selAnalsyt always = initial value!
string ticker = gvr.Cells[0].Text;
//ticker always is first data row
}
As you can see in the comments, no matter what row I click, the GridViewRow associated with the sender argument is always the first row. Also, the selected value of the dropdown is always its initial value, not the value selected by the user that fired off the SelectedIndexChanged event.
I've searched for a solution to this problem online and found that it is often caused by (1) the databind event getting fired on postback and (2) duplicate rows in the source data. I have checked for duplicate data and solved that problem and put primary keys on the appropriate table. I'm also making sure not to rebind the data on postback. Here's the Page_Load method:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.User.Identity.IsAuthenticated)
{
FormsAuthentication.RedirectToLoginPage();
}
else
{
string userName = Page.User.Identity.Name;
if (Session["UserMod"] == null)
{
this.userMod = new userModel(userName);
}
else
{
this.userMod = Session["UserMod"] as userModel;
}
if (!IsPostBack)
{
getPeopleList(userName);
getTickerList(userName);
if (this.userMod.IsResearchAdmin)
{
getAdminList();
}
else
{
assignmentsDropDown.Visible = false;
assignmentsGridView.Visible = false;
assignmentsButton.Visible = false;
assignmentsLabel.Visible = false;
addTextBox.Visible = false;
Image1.Visible = true;
analystDropdown.Visible = false;
}
}
}
}
I've got a RowDataBound method as well which sets the selected value of the dropdown for each row. When debugging, I have verified that the method is only running on the initial page load, not after the postback from SelectedIndexChanged. I was using an Update Panel as well, but removed that while trying to debug this.
I'm all outta ideas now, so I'm open to any suggestions. Thanks in advance
It looks like I've discovered an odd idiosyncrasy of asp.net. I had the following code in the RowDataBound method:
if (IsCompany)
{
e.Row.Cells.Remove(e.Row.Cells[1]);
}
I removed this code and the dropdown SelectedIndexChanged method now works correctly. All 3 methods of getting the parent GridViewRow of the dropdownlist are working after changing the RowDataBound method so that it does not remove any cells in the gridview.
I now believe that adding or removing cells during databinding causes unexpected problems with the SelectedIndexChanged event for dropdowns within GridViews. Here is the full code of the RowDataBoundMethod:
protected void assignmentsGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (Session["IsCompany"] == null)
{
Session["IsCompany"] = entityDropDown.SelectedValue == "Company";
}
bool? isCompany = Session["IsCompany"] as bool?;
bool IsCompany = (bool)isCompany;
TableCell cell;
if (e.Row.RowType == DataControlRowType.DataRow)
{
cell = e.Row.Cells[0];
HyperLink link = new HyperLink();
if (IsCompany)
{
link.NavigateUrl = "~/CompanyPage.aspx?Ticker=" + cell.Text;
}
else
{
link.NavigateUrl = "~/PeoplePage.aspx?PersonId=" + cell.Text;
}
link.Text = cell.Text;
cell.Controls.Clear();
cell.Controls.Add(link);
/* with this code included, I experience problems with the SelectedIndexChanged event of the dropdown
if (IsCompany)
{
e.Row.Cells.Remove(e.Row.Cells[1]);
}
*/
cell = e.Row.Cells[2];
var dd = e.Row.FindControl("assignmentDropDown") as DropDownList;
string assignment = ((DataRowView)e.Row.DataItem)["Assignment"].ToString();
foreach (ListItem li in dd.Items)
{
if (li.Value == assignment)
{
li.Selected = true;
break;
}
}
cell = e.Row.Cells[4];
if (cell.Text == "False")
{
//"completeButton"
var cb = e.Row.FindControl("completeButton") as Button;
cb.Enabled = false;
cb.Visible = false;
}
else
{
((Button)cell.FindControl("completeButton")).CommandArgument = e.Row.RowIndex.ToString();
}
}
}
If someone could confirm that removing cells inside rowdatabound causes problems with the selected index change event in asp.net I'd appreciate it.
I have a gridview that pulls data from local SQL server. I chose 3 columns to be displayed on the gridview. I added a fourth column (select command). I would like to get the data from the first column which is an id when I click the select command but i always get an error "An exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll but was not handled in user code Additional information: Index was out of range. Must be non-negative and less than the size of the collection."
Basically I would like to get the id from the first column then assign it to a session variable then redirect to a second page and then use the content of that session variable to populate another textbox.
protected void grdClients_RowCommand(object sender, GridViewCommandEventArgs e)
{
string id = grdClients.Rows[grdClients.SelectedIndex].Cells[0].Text.ToString();
Session["ID"] = id;
Response.Redirect("secondPage.aspx");
}
Any suggestions?
Thanks
1- add attribute to the GridView
DataKeyNames="aboutusID"
2- add a templatefield to your columns
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" CommandName="SelectSession" Text="EDIT" CommandArgument='<%# DataBinder.Eval(Container,"RowIndex")%>' ></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
3- in your code behind
protected void GridViewAbout_RowCommand(object sender, GridViewCommandEventArgs e)
{
// this to skip on paging or sorting command
if (e.CommandName != "Sort" & e.CommandName != "Page")
{
// Get the command argument where the index of the clicked button is stored
int index = Convert.ToInt32(e.CommandArgument);
// Get the data key of the index where the id is stored
int id = Convert.ToInt32(GridViewAbout.DataKeys[index].Value);
if (e.CommandName == "SelectSession")
{
// Your Code
}
}
}
i think you should use the SelectedIndexChanged event for that.
Then you assign the GridviewRow property to the selected row "GridViewRow row = grdClients.SelectedRow;"
After that you can use row to get the value of the first cell and assign it to your session or where ever you want. "row.Cells[0].Text;"
protected void grdClients_SelectedIndexChanged(object sender, EventArgs e)
{
GridViewRow row = grdClients.SelectedRow;
string id = row.Cells[0].Text;
Session["ID"] = id;
Response.Redirect("secondPage.aspx");
}
Thank you everyone,
I was able to come up with a solution by taking pieces from every solution you provided. Thanks very much.
Below is my solution:
protected void grdClients_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{
int index = Convert.ToInt32(e.CommandArgument);
string id = grdClients.Rows[index].Cells[0].Text.ToString();
Session["ID"] = id;
Response.Redirect("secondForm.aspx");
}
}
If I have two buttons on gridview and each performing different function. For example my code below,
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{
//Do something else
}
else if (e.CommandName == "View Cert")
{
int index = Convert.ToInt32(e.CommandArgument);
GridViewRow row = GridView1.Rows[index];
errorlab.Text = row.Cells[3].Text;
}
}
The value of cell 3 is a hidden field and there is a value in the database that's binding to hidden field but with my code I couldn't get the value. The errorlab label is showing nothing. Maybe I'm missing something.
I would like to suggest an answer, the command argument will not fetch you the row index. Instead it will give you what you bind during gridview data binding.
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{
//Do something else
}
else if (e.CommandName == "View Cert")
{
//The hidden field id is hdnProgramId
HiddenField hdnProgramId = (((e.CommandSource as LinkButton).Parent.FindControl("hdnProgramId")) as HiddenField);
}
}
This will try to locate the hidden field from the gridview row context.
If you have futher controls on the gridview cell then you have to access them using the Controls property
HiddenField hiddenField =row.Cells[3].Controls[0] as HiddenField;
if(hiddenField != null)
errorlab.Text = hiddenField.Value;
You have to use the correct index for the controls. Debug the code and check what is position of the control in row.Cells[3].Controls.
Always try to avoid referring cells by it's index position in gridview as it may result in changing the code if you happen to add/delete few more columns in the grid in the future which might result in undesired result. Also note that hiddenfield does not have a Text property but rather a Value property to access it's value.
If you know the hiddenfield's name then better try accessing it by it's name. Let's say you have your hiddenfield defined as below in your gridview
<ItemTemplate>
<asp:HiddenField ID ="hdnField" runat="server" Value='<%# Bind("ErrorLab") %>'/>
</ItemTemplate>
Then in your GridView1_RowCommand you can do
int index = Convert.ToInt32(e.CommandArgument);
GridViewRow row = GridView1.Rows[index];
HiddenField hdnField = (HiddenField)row.FindControl("hdnField");
errorlab.Text = hdnField.Value;
I'm trying to take a GridView and get back the data from the row that was clicked. I've tried the code below and when I click the row I get back the selected index but when I look at the actual rows in the GridView they show empty. Not sure what I am missing.
.ASP make my grid.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="True"
CssClass="datatables" Width="100%"
DataSourceID="SqlDataSource1"
GridLines="None" ShowFooter="True" AllowSorting="True"
onrowcreated="GridView1_RowCreated"
onrowdatabound="GridView1_RowDataBound" ShowHeaderWhenEmpty="True"
onrowcommand="GridView1_RowCommand"
onselectedindexchanged="GridView1_SelectedIndexChanged">
<HeaderStyle CssClass="hdrow" />
<RowStyle CssClass="datarow" />
<PagerStyle CssClass="cssPager" />
</asp:GridView>
On each row data bound I make sure that the click should set the selected index.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["onclick"] = Page.ClientScript.GetPostBackClientHyperlink(GridView1, "Select$" + e.Row.RowIndex);
}
}
Then when the selected index changes by clicking this gets fired which I can put a breakpoint on the first line and I see the index of what I clicked on get stored in a. However when I get to the foreach it skips right past it because it shows GridView1 having a Count of 0 rows. In theory it should have a couple hundred rows and when the index matches it should grab the data in the 6th cell over and store it in string b. Why am I getting no rows on the click?
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
int a = GridView1.SelectedIndex
foreach (GridViewRow row in GridView1.Rows)
{
if (row.RowIndex == a)
{
b = row.Cells[6].Text;
}
}
}
Here is my page load.
protected void Page_Load(object sender, EventArgs e)
{
c = HttpContext.Current.Session["c"].ToString();
SqlDataSource1.ConnectionString = //My secret
string strSelect = "SELECT columnnames from tablenames where c in (#c)
SqlDataSource1.SelectParameters.Clear();
SqlDataSource1.SelectCommand = strSelect;
SqlDataSource1.SelectParameters.Add("c", c);
try
{
GridView1.DataBind();
}
catch (Exception e)
{
}
GridView1.AutoGenerateColumns = true;
}
Try just grabbing the row from the SelectedRow property:
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
GridViewRow row = GridView1.SelectedRow;
string b = row.Cells[6].Text;
}
It's my understanding that the Rows collection doesn't get repopulated on PostBacks when you're using those data source controls (like SqlDataSource).
You could probably use your existing code if you called .DataBind() on your GridView prior to trying to iterate through the Rows:
GridView1.DataSourceID="SqlDataSource1";
GridView1.DataBind();
But that seems a little hacky.
After seeing your Page_Load, I see that you need to wrap your databinding code in an if(!Page.IsPostBack) block. Databinding on every postback is interrupting the process of ASP.NET maintaining the state of your controls via the ViewState.