How do I get the row I clicked with a button - c#

I have a grid view and when I click on the button I wanted to do a SQL command to see which Order number was pressed. How do I get the row I have clicked on?
asp
<asp:GridView ID="GridView1" runat="server"
DataKeyNames="No_" AutoGenerateColumns="false" style="color:Black;border-collapse:collapse;margin-right: auto;display: table;text-align: center;" OnPageIndexChanging="MyGrid_PageIndexChanging" OnRowDataBound="MyGrid_RowDataBound" AllowPaging="True" PageSize="20" AllowCustomPaging="False" >
<Columns>
<asp:BoundField DataField="No_" HeaderText="No_Encomenda" />
<asp:BoundField DataField="[Item No_]" HeaderText="Item number" />
<asp:BoundField DataField="Quantity" HeaderText="Quantity" />
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" OnCheckedChanged="CheckBox1_CheckedChanged" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<PagerSettings Mode="NumericFirstLast" PageButtonCount="4" FirstPageText="First" LastPageText="Last"/>
<PagerStyle CssClass="gridview" HorizontalAlign="Center" VerticalAlign="Middle"/>
</asp:GridView>
cs
protected void ButtonDetails_Click(object sender, EventArgs e)
{
MyGrid.Visible = false;
GridView1.Visible = true;
}
Gridview image:

Well, first of all, in your markup, I don't see a button in your markup. So the picture you have, and the markup don't agree with each other.
There are about 3 great ways to get the row click with a button.
Most common:
Drop in a the button. Say like this:
<asp:TemplateField HeaderText="View">
<ItemTemplate>
<asp:Button ID="cmdView" runat="server" Text="Details" CommandName="Select" />
</ItemTemplate>
</asp:TemplateField>
Note how we added the CommandName = "select". This is a special option that will trigger the Gridivew RowIndexed changed. It ALSO triggers the row command. But, in row command the "selected row event" has not yet triggered. So, I just ignore the row command event, and put your code in the selected index changed event.
protected void MyGrid_SelectedIndexChanged(object sender, EventArgs e)
{
// Get selected row
GridViewRow dG = MyGrid.SelectedRow;
Response.Write("Row index was " + dG.RowIndex.ToString());
// get non templated columns - they appear in cells
Response.Write("2nd colum value = " + dG.Cells[1].Text);
// get templated fields - say a combo box for city
DropDownList CityComboBox = (DropDownList)dG.FindControl("DropDownList1");
Response.Write("City selected from combo box = " + CityComboBox.SelectedValue);
}
So by JUST adding the CommandName = "Select", then this will trigger the SelectedinddexChanged event.
Another way is to use the row command (but you have to pass the row index to that event).
But, a really slick way is to 100% ignore the grid events, and JUST use your button.
You can do it this way:
Drop in the button. But now you can't double click on the button to wire up the click event, but you CAN STILL set the event for the click.
While in the markup you can thus type in OnClick= NOTE VERY careful the intli-sense that pops up - it looks like this:
So in the above choices - choose the create new event - it SEEMS like nothing occurred, but when you flip back to code-behind, you have a nice simple clean, good old regular button click event.
Droop a button - create click event. You can now just 100% ignore the complex GridView events (and that select command etc.).
You do this way now:
protected void Button3_Click(object sender, EventArgs e)
{
Button MyButton = (Button)sender;
GridViewRow dG = (GridViewRow)MyButton.Parent.Parent;
Response.Write("Row index was " + dG.RowIndex.ToString());
// get non templated columns - they appear in cells
Response.Write("2nd colum value = " + dG.Cells[1].Text);
// get templated fields - say a combo box for city
DropDownList CityComboBox = (DropDownList)dG.FindControl("DropDownList1");
Response.Write("City selected from combo box = " + CityComboBox.SelectedValue);
}
I find the above is less hassle, but also LESS learning curve to use. We drop in a button - click event. You just pick up the "sender" into a button, and then get parent.parent which turns out to be the grid row we want.
The first parent is I think some cell divider. In fact I use this .parent trick all the time. Thus buttons are a simple button dropped into the grid markup, and we use the standard button click event and code approach.
But, hey, we really don't care about the GridVieew row command, and we really dont' care about the Selected index changed.
We have a button click. So now you can use this slick trick to save world poverty's, save using complex GridView events, and just code up a simple button like any other button.
And we get FULL USE of the grid view row with this trick.

Related

Assigning a cell value to NavigateUrl in GridView

GridView allows to create a virtual HyperLinkField column that converts another column assigned to it (and its cell values) into hyperlinks, but NavigateUrl must be assigned a "predetermined" url address.
However, in the GridView, the cells of the columns I created (Column_name) - are generated each time by running a function that creates a hyperlink address - as a relative address of the type
./(directory_with_different_name_each_time_when_the_value_is_generated)/index.aspx
Is it possible to make this content a "clickable" link to the newly generated subpage?
Any particular reason why say you don't just drop in a plane jane button, and use that?
create a virtual HyperLinkField column that converts another column assigned to it (and its cell values) into hyperlinks
Hum, that seems beyond confusing here??? If you asking can I create a hyper link for each row based on information from that data row that binds to the one row? Sure, no problem. You can use a messy Eval expression, but often it really OH SO MUCH easier to simple use the GV data bound event, and setup any kind of hyper link you want for that one button (or hyper link button).
I mean, we can have this gv:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID"
cssclass="table" Width="30%" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" />
<asp:BoundField DataField="Animal" HeaderText="Animal" />
<asp:BoundField DataField="PictureName" HeaderText="Picture" />
<asp:TemplateField HeaderText="Example Hyperlink" ItemStyle-HorizontalAlign="Center" >
<ItemTemplate>
<asp:HyperLink ID="HyperLink1" runat="server">View</asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Example Button" ItemStyle-HorizontalAlign="Center" >
<ItemTemplate>
<asp:Button ID="Button1" runat="server" Text="View" CssClass="btn"
OnClick="Button1_Click"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
In above, for this demo, I dropped in a hyper link, and for good measure a plane jane button.
We will take the data FROM the data row.
I cannot beyond the mountains of Everst note how I grab the DATA source and NOT the grid view row. This allows me FULL USE of ANY and ALL columns for the data bound event. This means I do NOT even have to include the addtional columns in the grid, but ONLY IN THE DATA SOURCE!!
However, for this example, I have the columns in the gv.
So, with above, I did add a plane jane button with a button click even.
So, our code to fill the grid is this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand("SELECT ID, Animal, PictureName from tblAnimals", conn))
{
conn.Open();
DataTable rstData = new DataTable();
rstData.Load(cmdSQL.ExecuteReader());
GridView1.DataSource = rstData;
GridView1.DataBind();
}
}
}
Output:
Ok, so lets cook up a hyper ink url for each hyper link button.
And lets ALSO do this for the button click.
So, in the gv row data bind event, we now have this:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// get data row
DataRowView gData = (DataRowView)e.Row.DataItem;
// example set hyper link
HyperLink myHyper = (HyperLink)e.Row.FindControl("HyperLink1");
// create URL based on row data
myHyper.NavigateUrl = "~/Content/Animals/" + gData["PictureName"];
// example buttion click
Button myBtn = (Button)e.Row.FindControl("Button1");
myBtn.CommandArgument = "~/Content/Animals/" + gData["PictureName"];
}
}
As you can see, we are free to cook up and create ANY kind of hyper link URL in code based on the columns in the data we feed to the grid.
As noted, I also tossed in a plane jane button - it has a click even, but NOTE close how I set the command argument for that button.
And thus the button click code does this:
protected void Button1_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
Response.Redirect(btn.CommandArgument);
}
So, both the hyper link, and the button click quite much wind up doing the same thing - navagating to a url of our choice for each row, and that url can be anything you wish to cook up in code based on the one data row.
Also, my code used SqlProvider, and you are likly using oleDB or ODBC provider, so just swap out the sqlcommand, Sqlconnection to the oleDB one, or ODBC one - the code will work much the same regardless of what provider you are using.

Getting the value of a Textbox in a TemplateField in a gridview

i'm gonna keep it short and simple
I'm a software engineering student in the 12th grade and as my final project I have decided to make a website. What the website is about doesn't really matter. The problem is this:
In the picture attached there is a textbox inside a templatefield inside that gridview. I need to get the value that the user writes inside. After you write a value you press Purchase. I've looked at similar questions and none offered a working solution. What happens is the value just disappears. I find the right control with FindControl, but the value gets deleted somehow. How do I know I am at the right control? I went to the client side and added to the asp:TextBox the following:
Text="5"
This works perfectly, so I know it gets to the right control but something makes it disappear. My gridview is being populated by a DataSet that is two datasets combined, and I put the Merge command and the DataSource and DataBind are both in if (!this.IsPostBack). I am completely lost and have no idea what to do, Help is much appreciated.The Picture of the Gridview
All the controls in a GridView are accessible by searching the correct row with FindControl. For that you can send the row number as a CommandArgument and use that in code behind. So first start by using OnCommand instead on OnClick and set the CommandArgument on the aspx page.
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Purchase" OnCommand="Button1_Command" CommandArgument='<%# Container.DataItemIndex %>' />
</ItemTemplate>
</asp:TemplateField>
And then in code behind
protected void Button1_Command(object sender, CommandEventArgs e)
{
//get the rownumber from the command argument
int rowIndex = Convert.ToInt32(e.CommandArgument);
//find the textbox in the corrext row with findcontrol
TextBox tb = GridView1.Rows[rowIndex].FindControl("TextBox1") as TextBox;
//get the value from the textbox
try
{
int numberOfTickets = Convert.ToInt32(tb.Text);
}
catch
{
//textbox is empty or not a number
}
}

ASP.NET GridView requires two clicks of edit command - why?

Firstly, I realise the question of how to avoid two clicks has been asked multiple times with ths same answer - "re-bind the gridview" (eg here and here). However I'm after an explanation of WHY this occurs and if there's an alternative solution.
When using a Gridview, clicking the Edit button once fires the OnRowEditing event, yet makes no visual changes to the gridview, upon clicking for a second time, the OnRowEditing executes again, but this time on return the GridView row is now editable and has the Update and Cancel buttons.
If within the OnRowEditing method there is a manual DataBind() of the gridview, then a second click is not required.
Why is this occuring?
So, the scenario:
GridView:
<asp:GridView ID="gvMain" runat="server"
OnRowEditing="gvMain_RowEditing"
OnRowCancelingEdit="gvMain_RowCancelingEdit"
OnRowUpdating="gvMain_RowUpdating">
<Columns>
<asp:CommandField ShowEditButton="true" EditText="Edit" />
<asp:BoundField DataField="location" HeaderText="Location" />
</Columns>
</asp:GridView>
CodeBedhind:
protected void gvMain_RowEditing(object sender, GridViewEditEventArgs e)
{
gvMain.EditIndex = i;
}

GridView.SelectedIndexChanged doesn't fire

Hello i have a gridview that is connected to the event selectedindexchanged and is on a hidden panel but when i try to fire the event don't do anything.
This is the code of the gridview:
<asp:GridView ID="GridView1" runat="server" CssClass="mGrid"
Width="847px" onselectedindexchanged="GridView1_SelectedIndexChanged2">
<Columns>
<asp:ButtonField Text="Borrar" />
</Columns>
</asp:GridView>
This is the code on the event:
protected void GridView1_SelectedIndexChanged2(object sender, EventArgs e)
{
GridViewRow row = GridView1.SelectedRow;
Response.Write(row.Cells[2].Text);
}
That's because that button isn't a SelectButton, one approach would be to set the AutoGeneratesSelectButton property on the GridView to true. You could then get rid of that other button you're trying to make work.
If you need that other button then you'll need to make it a CommandField and set the ShowSelectButton to true. With that configuration you can set the SelectText and have some custom text for the button.
Either way, a Button isn't going to do anything for SelectedIndexChanged.

Selecting multiple rows in GridView with checkboxes: Program not pulling data

I have been coming across a strange bug/error in my code when attempting to select and pull data from multiple rows in GridView controls.
Background:
In short, I have a GridView item, populated with rows of different equipment items that are "checked in" and available to check out of our system. I want to have the user able to select multiple items and check them out at once, rather than doing it X times.
I am using a check box item on each row to do this, like so: http://i.imgur.com/fPYV2.png
There is a button at the bottom to check the equipment out of our database.
Code:
The code I am using to generate the ASPX page is:
<asp:GridView ID="grdEquipment" runat="server" AutoGenerateColumns="false" ShowHeaderWhenEmpty="true" CssClass="table table-bordered">
<Columns>
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox ID="chkMultiSelect_Out" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="Equipment Name" DataField="Name" />
<asp:BoundField HeaderText="Category" DataField="Category.Name" />
</Columns>
<EmptyDataTemplate>
There is no equipment to display.
</EmptyDataTemplate>
</asp:GridView>
<div class="well">
<asp:Button ID="btnCheckOut" runat="server" CssClass="btn btn-small btn-inverse" Text="Check Out" OnClick="btnCheckOut_Click" />
</div>
This works and compiles with no problem.
The code running the button to check everything out is:
protected void btnCheckOut_Click(object sender, EventArgs e)
{
int checkoutNumber = 0;
//string id = (sender as Button).Attributes["data-id"].ToString();
SortedBindingList<Tracker.Business.Equipment> eqList = Tracker.Business.EquipmentList.FetchAll();
foreach (GridViewRow row in this.grdEquipment.Rows)
{
CheckBox chkMultiSelect_Out = (CheckBox)row.FindControl("chkMultiSelect_Out") ;
if (chkMultiSelect_Out.Checked)
{
checkoutNumber++;
Tracker.Business.Equipment equip = Tracker.Business.Equipment.GetByIdentification(Int32.Parse(row.ID.ToString()));
eqList.Add(equip);
}
}
//If checkoutNumber is 0, do nothing.
//If checkoutNumber is 1, launch popup for only 1 item
//If checkoutNumber is more than 1, launch popup for multiple items.
if (checkoutNumber == 0)
{
Response.Redirect("~/Equipment/CheckInOut/Default.aspx");
}
else if (checkoutNumber == 1)
{
}
else if (checkoutNumber > 1)
{
}
}
Now, OBVIOUSLY, this code isn't finished. I am debugging as I go to make my life easier.
The important code is the foreach loop where I check each row for the control item, and see if it is checked or not.
The Problem:
When I run the code, and test with some check boxes checked, it looks at all the rows, and ALL of them have "Checked = false" as an attribute. What's worse, I found out later that it doesn't even grab the data from the row, as shown in this screen shot here: http://i.imgur.com/clRuk.png
The text should be "Optimus Prime" or "Switch #1", however it is not! And both are checked when I run the code, yet the code sees only false checked items.
The code runs through the foreach loop for each row, i.e., 3 rows, it runs through the loop 3 times. So it sees each row, yet it is not pulling the data...
Where should I start looking?
I fixed my problem. As Tim Schmelter said, I was postbacking the page on every click, so I changed my code to databind the gridview table only on a page load, and not on a post back. Works now!

Categories