Trouble grabbing Row Number from GridView - c#

I have the following GridView:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="SysInvoiceID" DataSourceID="SqlDataSource1">
<Columns>
<asp:BoundField DataField="SysInvoiceID" HeaderText="SysInvoiceID" ReadOnly="True" SortExpression="SysInvoiceID" />
<asp:BoundField DataField="BillMonth" HeaderText="BillMonth" SortExpression="BillMonth" />
<asp:BoundField DataField="InvoiceDate" HeaderText="InvoiceDate" ReadOnly="True" SortExpression="InvoiceDate" />
<asp:BoundField DataField="InvoiceNumber" HeaderText="InvoiceNumber" SortExpression="InvoiceNumber" />
<asp:BoundField DataField="Net" HeaderText="Net" SortExpression="Net" />
<asp:BoundField DataField="VAT" HeaderText="VAT" SortExpression="VAT" />
<asp:BoundField DataField="Gross" HeaderText="Gross" SortExpression="Gross" />
<asp:ButtonField CommandName="ViewInvoice" HeaderText=" " ShowHeader="True" Text="View" />
</Columns>
</asp:GridView>
Here is the code behind the page:
public partial class PagingTest01 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
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 == "ViewInvoice")
{
// 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 = GridView1.Rows[index];
// Now you have access to the gridviewrow.
ViewButton_Click(row);
}
}
protected void ViewButton_Click(GridViewRow row)
{
byte[] FileImage = GetImageData(0,row);
if (FileImage != null)
{
base.Response.Clear();
base.Response.Buffer = true;
base.Response.ContentType = "Application/x-pdf";
base.Response.ContentEncoding = Encoding.Default;
string attachment = string.Format("attachment;filename=\"Invoice_{0}.pdf\"", "Customer1");
base.Response.AddHeader("content-disposition", attachment);
base.Response.BinaryWrite(FileImage);
base.Response.Flush();
base.Response.Close();
base.Response.End();
}
}
public byte[] GetImageData(int sysInvoiceID, GridViewRow row)
{
string strUserID = CommonCode.GetCurrentUserID().ToString();
string strCustomerID = CommonCode.GetCurrentCustomerID().ToString();
byte[] numArray;
string strConnectionString = "Data Source=TESTSERV;Initial Catalog=DB_Invoices;Persist Security Info=True";
SqlConnection connection = new SqlConnection(strConnectionString);
SqlCommand command = new SqlCommand("select FileImage from DB_Invoices.dbo.Bills WHERE (FileType = 'PDF' AND SysInvoiceID = #ID)", connection);
command.Parameters.AddWithValue("#ID", GridView1.Rows[row].Cells[0].Text);
SqlDataAdapter da = new SqlDataAdapter(command);
DataSet ds = new DataSet();
try
{
connection.Open();
da.Fill(ds);
DataRow item = ds.Tables[0].Rows[0];
byte[] item1 = (byte[])item["FileImage"];
ds.Tables.Clear();
numArray = item1;
}
catch (Exception ex)
{
throw ex;
}
finally
{
connection.Close();
}
return numArray;
}
}
So basically I have a GridView with a lot of rows, each one with a 'View' Buttonfield next to it. When 'View' is clicked, I attempted to make use of GridView1_RowCommand which should hopefully grab the row clicked before passing it onto ViewButton_Click. This will then call GetImageData and pass the row number onto this line:
command.Parameters.AddWithValue("#ID", GridView1.Rows[row].Cells[0].Text);
Cell 0 is the SysInvoiceID column, so if the correct row is passed, #ID will be assigned a SysInvoiceID.
'Row' however doesn't seem to be a valid argument, though I can't think why not... Unless I have to explicitly convert it into a int? Any help would be really appreciated! Thanks.

I have just commented this as side-note but maybe it's your issue because you mention that "it doesn't seem to be a valid argument, though I can't think why not... Unless I have to explicitly convert it into a int".
If ID is an int you should use int.Parse(celltext), othwerwise the database gets the wrong type since AddWithValue needs to infer the type from the value.
So use:
command.Parameters.AddWithValue("#ID", int.Parse(GridView1.Rows[row].Cells[0].Text));
Apart from that, you haven't added the event handler GridView1_RowCommand.
<asp:GridView ID="GridView1" OnRowCommand="GridView1_RowCommand" runat="server" AutoGenerateColumns="False" DataKeyNames="SysInvoiceID" DataSourceID="SqlDataSource1">
....
and you are also not setting the CommandArgument to the index of the row. I would use a different approach anyway if you need the row-index. Use a templatefield and a control, for example a Button. Then use it's NamingContainer property to get the reference to the 'GridViewRow`, here is an example: Get Row Index on Asp.net Rowcommand event

use this:
int index = ((GridViewRow)((WebControl)sender)).RowIndex;
in place of
int index = Convert.ToInt32(e.CommandArgument);

Related

Dynamically adding button to grid view

My scenario is that i am creating a data table dynamically and adding the latter to a data set and displaying it in a grid view. I want to add a button "Add to chart" at the end of each row which will have additional functionality.
My code for creating the dynamic data table :
try
{
response = client.query(a);
///List of fields
var fields = response.#return.fields;
//loop through each column
foreach (String column in fields)
{
dtservice.Columns.Add(column);
}
///List of value return as list of object
var values = response.#return.values.ToList();
///get the first object from the list of object
foreach (object item in values)
{
if (item == null) continue;
foreach (PropertyInfo property in item.GetType().GetProperties())
{
// do something with the property
List<string> valueList = (List<string>)(property.GetValue(item, null));
dtservice.Rows.Add(valueList.ToArray());
}
}
}
catch (Exception error)
{
var b = error.ToString();
}
//create dataset
DataSet test= new DataSet();
test.Tables.Add(dtservice);
return test;
}
I have tried using the below code but the button dissapear on click.
protected void WorkList_RowDataBound(object sender, GridViewRowEventArgs e)
{
// CHECK IF ROW IS NOT IN EDIT MODE
if (e.Row.RowType == DataControlRowType.DataRow)
{
// CREATE A Button
Button btn = new Button();
btn.ID = "btnEstados";
btn.Text = "Estados";
// ADD BUTTON TO EACH ROW IN 2ND COLUMN
e.Row.Cells[7].Controls.Add(btn);
}
}
second problem now i was able to get the button on each row, but using the code below,i get the count of column equal to 1. It is actually reading only the static column added in the html and not the one generated dynamically.
//adding column to datatable
for (int row = 0; row < test.Columns.Count - 1; row++)
{
ServiceName.Columns.Add(test.HeaderRow.Cells[row].Text, typeof(string));
}
This is the other way on how to add button in Gridview.
<asp:GridView ID="WorkList" runat="server" Width="100%" AutoGenerateColumns="false" AllowPaging="false" AllowSorting="false"
EmptyDataText="No Record Found"
OnRowCreated="WorkList_RowCreated"
OnRowCommand="WorkList_RowCommand"
OnRowCancelingEdit="WorkList_RowCancelingEdit"
OnRowEditing="WorkList_RowEditing">
<AlternatingRowStyle CssClass="alt" BackColor="#CCFF99"></AlternatingRowStyle>
<Columns>
<asp:ButtonField ButtonType="Button" CommandName="Estados" HeaderText="" ShowHeader="True" Text="Estados" ItemStyle-Width="30px" />
</Columns>
<HeaderStyle BackColor="#808080" ForeColor="#48D1CC" />
</asp:GridView>
In WorkList_RowCommand:
int index = Convert.ToInt32(e.CommandArgument);
GridViewRow gvRow = WorkList.Rows[index];
WorkList.Rows[index];
if (e.CommandName == "Estados")
{
//your code here like `gvRow.Cells[0].Text`
}
Make sure the property declared of your WorkList is exists in your code behind.
Hope it helps.

How to get a specific data in gridview using c#?

I was wondering how to retrieve a specific data from gridview. My database consists of columns like id, type and name. Lets say the contents of my gridview is like this example below:
Id Type Name
1 Guitar Ibanez
2 Guitar Gibson
What i want to happen is to get the value under Name, Lets say "Ibanez". I was able to retrieve the value for Id using datakeys but I can't figure out how to get the value of Name in Gridview. I included code below to better understand what i mean.
protected void GuitarBrandsGridViewBtn_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
GridViewRow gridrow = btn.NamingContainer as GridViewRow;
int id = Convert.ToInt32(GuitarBrandsGridView.DataKeys[gridrow.RowIndex].Value.ToString());
con.Open();
cmd.CommandText = "DELETE FROM [guitarBrands] WHERE id=" + id;
cmd.Connection = con;
int a = cmd.ExecuteNonQuery();
con.Close();
if (a > 0)
{
bindgridviewguitarbrands();
}
System.IO.File.Delete(#"C:\Users\User1\Documents\Visual Studio 2015\WebSites\MusicStore\Pages\GuitarItemsIbanezDetails" + id + ".aspx");
System.IO.File.Delete(#"C:\Users\User1\Documents\Visual Studio 2015\WebSites\MusicStore\Pages\GuitarItemsIbanezDetails" + id + ".aspx.cs");
}
You can access specific columns like this
GuitarBrandsGridView.Rows[gridrow.RowIndex].Cells[1].Text;
you can use template field in the grid view instead of bound field like this :
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:Label ID="lblName" runat="server" Text='<%# Eval("ColumnNameOfYourDatasourceForName") %>' />
</ItemTemplate>
</asp:TemplateField>
and then get the label and its text in code behind from following code :
protected void GuitarBrandsGridViewBtn_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
GridViewRow gridrow = btn.NamingContainer as GridViewRow;
Label lblName = gridrow.FindControl("lblName");
string name = lblName.Text;
}

Remove Row from GridView

I have a grid view on my page and I want to allow the user to add / remove items to it. How it works, and the add functionality does work albeit probably not great, is that a user selects a product from a drop down list, then clicks Add.
This creates a new row in grid with the select Product text and ID. The GridView markup is:
<asp:GridView runat="server" ID="grdSelectedProducts" BorderWidth="1px" CellPadding="3" CellSpacing="2" AutoGenerateColumns="False" OnRowDataBound="grdSelectedProducts_OnRowDataBound" ShowHeaderWhenEmpty="True" DataKeyNames="ProductId"
OnRowCommand="grdSelectedProducts_RowCommand" OnRowDeleted="grdSelectedProducts_RowDeleted" OnRowDeleting="grdSelectedProducts_RowDeleting">
<Columns>
<asp:BoundField DataField="Product" HeaderText="Product" ReadOnly="False" />
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton runat="server" ID="linkDelete" runat="server" CommandName="Delete" CommandArgument="<%# Container.DataItemIndex %>">Remove</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="ProductId" HeaderText="ProductId" ReadOnly="False" Visible="False" />
</Columns>
</asp:GridView>
The data in the grid is bound but there is no connection to a database, as it's just the information from the drop down.
The linkDelete is where I want to allow the user to remove an item, so my question is, how can I actually delete the row? I've got the RowCommand event up which I've tried to remove it, but it just doesn't seem to work correctly as the table either 1) gets rebound with the same data as before or 2) all rows are removed due to the binding of a new DataTable. I'm missing something obvious, but this type of grid is new to me.
Any example I've seen here or on Google has been around gridviews which are databound from SQL, or some other database, which seems to make the rebinding easier. However my version doesn't use that so binding again doesn't seem to work correctly.
protected void grdSelectedProducts_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
if (!string.IsNullOrEmpty(e.CommandArgument.ToString()))
{
int rowIndex = Convert.ToInt32(e.CommandArgument);
grdSelectedProducts.DeleteRow(rowIndex);
CountryDataTable = (DataTable)grdSelectedProducts.DataSource;
DataTable table = CreateDataTable(false, string.Empty, string.Empty);
grdSelectedProducts.DataSource = table;
grdSelectedProducts.DataBind();
}
}
}
private DataTable CreateDataTable(bool isAddingValue, string selectedProduct, string selectedId)
{
// if isAddingValue is FALSE then it isn't from a button click to add a Product, it is just
// a call to create the datatable
DataTable dataTable = ProductDataTable;
if (!dataTable.Columns.Contains("Product"))
{
dataTable.Columns.Add("Product");
dataTable.Columns.Add("ProductId");
}
if (isAddingValue)
{
// Get the data from ViewState
DataRow dataRow;
dataRow = dataTable.NewRow();
dataRow["Product"] = selectedProduct;
dataRow["ProductId"] = selectedId;
dataTable.Rows.Add(dataRow);
}
else
{
grdSelectedProducts.DataSource = null;
grdSelectedProducts.DataSource = ProductDataTable;
grdSelectedProducts.DataBind();
}
// Save the data back to ViewState
ProductDataTable = dataTable;
return dataTable;
}
private DataTable ProductDataTable
{
get {return ViewState["ProductDataTable"] as DataTable ?? new DataTable(); }
set { ViewState["ProductDataTable"] = value; }
}
I do have the RowDeleting & RowDeleted events but I don't have any code in it.
First thing you should note is you are deleting the row from grid not from the data table
Then you again bind the data table which may not give you any change, What you should do is instead of deleting from grid delete it from datatable
Rewrite it like
if (e.CommandName == "Delete")
{
if (!string.IsNullOrEmpty(e.CommandArgument.ToString()))
{
int rowIndex = Convert.ToInt32(e.CommandArgument);
DataTable table = CreateDataTable(false, string.Empty, string.Empty);
table.Rows.RemoveAt(rowIndex)
grdSelectedProducts.DataSource = table;
grdSelectedProducts.DataBind();
}
}
If you need it to remove it from DB , DOnt forget to do that , And also note that the above code each time when u fetch the table it will give u everything from DB
so you can make it global , or you can just remove from DB
try this code
if (e.CommandName == "Delete")
{
if (!string.IsNullOrEmpty(e.CommandArgument.ToString()))
{
int rowIndex = Convert.ToInt32(e.CommandArgument);
grdSelectedProducts.DeleteRow(rowIndex);
SqlCommand cmd = new SqlCommand ("Delete from table where id='"+ rowIndex )+"'",ConnectionObject);
cmd.ExecutenonQuery();
CountryDataTable = (DataTable)grdSelectedProducts.DataSource;
DataTable table = CreateDataTable(false, string.Empty, string.Empty);
grdSelectedProducts.DataSource = table;
grdSelectedProducts.DataBind();
}
}

Putting the output of a SQL query in a table

I just cant figure out how to get the output of a query and be able to manipulate it, meaning that i have a database and i have a table named CoursePages that contain all the coursePages in my university, so when a student or somebody wants to subscribe to a course page i want to view all the records in the table(coursePages) and make them clickable just in order to know which one he/she pressed and save it. So is there any way to generate such thing ?
Here is my code :
protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Data Source=JASONTT-PC\\SQLSERVER;Initial Catalog=GNetwork;Integrated Security=True";
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.Connection.Open();
String query = "SELECT * FROM Course_Pages ";
comm.CommandText = query;
SqlDataReader reader = comm.ExecuteReader();
// i don't know what to do after i executed the reader ..
}
maybe like a gridView or sthg ... i just want for every record i will take the name (String ) and put it in a checkbox so that i can tell which ones the user clicked
while (reader.Read()){
//now you can get any values by column index like
int i = reader.GetInt32(0);
string s = reader.GetString(1);
double d = reader.GetInt32(2);
DateTime dt = reader.GetDateTime(3);
}
If you're asking how to translate these results into links on your web page, you should look at creating a gridview and Binding your reader to it.
Here's a sample:
using (SqlDataReader reader = comm.ExecuteReader()) {
gv1.DataSource = reader;
gv1.DataBind();
}
<asp:GridView runat="server" AutoGenerateColumns="false" ID="gv1">
<Columns>
<asp:BoundField DataField="Title" HeaderText="Title" />
<asp:TemplateField>
<ItemTemplate>
<a href='foo.aspx?id=<%# Eval("id") %>'>Link</a>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Finally, note that if you have a field in your returned query that represents the url in toto, you can use a HyperLinkField
<asp:HyperLinkField DataNavigateUrlFields="linkHref" Text="BoundLink" />
DataNavigateUrlFields is the field from your results you're binding the url to.

asp.net GridView isn't updating properly

I have a Gridview with these parameters:
<asp:GridView runat="server" ID="ItemGrid" CssClass="Grid"
AutoGenerateColumns="false"
AutoGenerateDeleteButton="true" OnRowDeleting="RowDeleting"
AutoGenerateEditButton="true" onRowEditing="RowEdit"
OnRowCancelingEdit="CancelRowEdit" onRowUpdating="RowUpdating"
DataKeyNames="Item_ID">
<Columns>
<asp:BoundField HeaderText="Item" DataField="Item"/>
<asp:BoundField HeaderText="Family" DataField="Family"/>
<asp:BoundField HeaderText="Structure" DataField="Structure"/>
<asp:BoundField HeaderText="Updated" ReadOnly="true" DataFormatString="{0:d}" DataField="Updated"/>
</Columns>
</asp:GridView>
On updating it calls:
protected void RowUpdating(object sender, GridViewUpdateEventArgs e){
int Item_ID = (int)this.ItemGrid.DataKeys[e.RowIndex][0];
//Problem is something right here:
string Item = ((TextBox)ItemGrid.Rows[e.RowIndex].Cells[1].Controls[0]).Text;
string Family = ((TextBox)ItemGrid.Rows[e.RowIndex].Cells[2].Controls[0]).Text;
string Structure = ((TextBox)ItemGrid.Rows[e.RowIndex].Cells[3].Controls[0]).Text;
ItemTableAdapter taItem = new ItemTableAdapter();
taItem.UpdateItem(Item, Family, Structure, DateTime.Now, Item_ID);
//just a <asp:Label> for seeing some output.
Alert.Text= string.Format("Item:{0}Family:{1}Structure:{2}",Item,Family,Structure);
this.ItemGrid.EditIndex = -1;
dataBind();
}
It generates the Update/Edit/Delete buttons, my Delete function is working exactly how I want and the 'Edit' button generates editable TextBoxes as it should.
My problem is in the updating part, the strings Item, Family, Structure are getting the old values, not the new values I put in the generated text boxes.
If I hard code in values they are updated to the database and the DateTime.Now is always updating correctly in the database so the update query is working.
I've been looking at this/reading forums testing things for a couple days now. I'm sure I'm just missing something simple that I have overlooked.
Thanks for any help.
Edit:
It has been answered but for those who were curious this is my dataBind();
protected void dataBind()
{
ItemTableAdapter taItem = new ItemTableAdapter();
this.ItemGrid.DataSource = taItem.GetActive();
this.ItemGrid.DataBind();
}
Are you re-binding your GridView on postback by mistake? You should only fetch the data from the database on initial load:
if (!IsPostBack)
{
Gridview1.Datasource = BLL.SomeClass.Load(SomeRecordId);
GridView1.DataBind();
}
RowUpdating and RowUpdated fire at different times. See if that isn't your problem.
Try using the following method to get your new values:
//string Item = ((TextBox)ItemGrid.Rows[e.RowIndex].Cells[1].Controls[0]).Text;
//string Family = ((TextBox)ItemGrid.Rows[e.RowIndex].Cells[2].Controls[0]).Text;
//string Structure = ((TextBox)ItemGrid.Rows[e.RowIndex].Cells[3].Controls[0]).Text;
string Item = e.NewValues["Item"].ToString();
string Family = e.NewValues["Family"].ToString();
string Structure = e.NewValues["Structure"].ToString();

Categories