Button click pulls wrong DataTable for export into Excel - c#

I'm pulling company schedule data from a web API and formatting the data so it can be displayed neatly on a local site and also available to export onto an excel template for distribution across the company.
I've added a button on the bottom of the site to display the previous weeks schedule and another to export the data to excel. When "Previous Week" is clicked it populates the same Gridview1 table with last weeks data. But When I click the export button it exports the data from the current week into Excel.
Here's some of my code, let me know what else I need to post for help.
The datatable gets set on page load into a gridview:
protected void Page_Load(object sender, EventArgs e)
{
// ..... bunch of code above to call web API for date range and format table....
DataView view = table.AsDataView();
view.Sort = "Sort ASC";
GridView1.DataSource = view;
GridView1.DataBind();
if (GridView1.Columns.Count > 0)
GridView1.Columns[8].Visible = false;
else
{
GridView1.HeaderRow.Cells[8].Visible = false;
foreach (GridViewRow gvr in GridView1.Rows)
{
gvr.Cells[8].Visible = false;
}
}
and the gridview gets pulled into a datatable and sent to an excel spreadsheet
protected void ExportExcel(object sender, EventArgs e)
{
DataTable dt = new DataTable("Resident Schedule");
foreach (TableCell cell in GridView1.HeaderRow.Cells)
{
dt.Columns.Add(cell.Text);
}
foreach (GridViewRow row in GridView1.Rows)
{
dt.Rows.Add();
for (int i = 0; i < row.Cells.Count; i++)
{
dt.Rows[dt.Rows.Count - 1][i] = row.Cells[i].Text;
}
}
dt.Columns.Remove("Rotation");
dt.Columns.Remove("Sort");
using (XLWorkbook wb = new XLWorkbook(#"C:\template.xlsx"))
{
IXLWorksheet ws = wb.Worksheet("Resident Schedule");
var rangeWithStrings = ws.Cell(5, 2).InsertTable(dt.AsEnumerable(), false);
// ..... bunch of code below
now I have a button click method that gets called to load the previous week into GridView:
protected void PreviousWeek(object sender, EventArgs e)
{
// ..... bunch of code above to pull and sort last weeks schedule....
DataView view = table.AsDataView();
view.Sort = "Sort ASC";
GridView1.DataSource = view;
GridView1.DataBind();
if (GridView1.Columns.Count > 0)
GridView1.Columns[8].Visible = false;
else
{
GridView1.HeaderRow.Cells[8].Visible = false;
foreach (GridViewRow gvr in GridView1.Rows)
{
gvr.Cells[8].Visible = false;
}
}
So, my question is, if the button click is repopulating GridView1 data, why is the ExportExcel method is going back to the Page Load data?

Click on button, send postback event and seems you missed to check whether request is postback or not. so whenever you click on button then always gridview populated with current week data. Check postback request and then poulate gridview on load event.
if (!IsPostBack)
{
// GridView Populate code
}

Related

How can I be able to pass the data in the textbox into the gridview after clicking submit button(

When I click the submit button,I cannot see the data in the gridview.What changes do I need to make in order to see the data in the GridView?
protected void Button1_Click(object sender, EventArgs e)
{
DataTable table = new DataTable();
table.Columns.Add("ProductId");
table.Columns.Add("ProductName");
table.Columns.Add("ExpiryDate");
table.Columns.Add("Price");
table.Columns.Add("LotNumber");
DataRow dr = table.NewRow();
dr["ProductId"] = ProductId.Text;
dr["ProductName"] = ProductName.Text;
dr["ExpiryDate"] = ExpiryDate.Text;
dr["Price"] = Price.Text;
dr["LotNumber"] = LotNumber.Text;
table.Rows.Add(dr);
GridView2.DataSource = table;
GridView2.DataBind();
}
According the code, you have two GridView. Verify you update the right one.

How to check CheckBoxList checked values exist in GridView asp.net C#

Hi I want to display asp CheckBoxList checked items text in gridview row by row.This is my code , It adding list items text to gridview row by row, but when I checked items it duplicate same Item text again and again in gridview . How I checked Is exist same Item text in Gridview please help me .
This is my checked event
protected void CheckBoxList1_SelectedIndexChanged(object sender, EventArgs e)
{
// check view state is not null
if (ViewState["MailTracking"] != null)
{
//get datatable from view state
dt = (DataTable)ViewState["MailTracking"];
// DataRow oItem = null;
if (dt.Rows.Count > 0)
{
foreach (ListItem li1 in CheckBoxListBranch.Items)
{
if (li1.Selected)
{
dt.Rows.Add(li1.Text);
}
}
//Remove initial blank row
if (dt.Rows[0][0].ToString() == "")
{
dt.Rows[0].Delete();
dt.AcceptChanges();
}
// dt.Rows.Add(oItem);
ViewState["MailTracking"] = dt;
GVDisplay.DataSource = dt;
GVDisplay.DataBind();
}
}
}
You seem to be appending to the already existing list every time an item is checked. I would create a new DataTable every time (especially if it is a small list).
Example:
protected void CheckBoxList1_SelectedIndexChanged(object sender, EventArgs e)
{
dt = new DataTable(); // Assuming that dt is a local variable
foreach (ListItem li1 in CheckBoxListBranch.Items)
{
if (li1.Selected)
dt.Rows.Add(li1.Text);
}
GVDisplay.DataSource = dt;
GVDisplay.DataBind();
}

Dynamically add rows to DataTable

I have an asp.net form with a textbox and a button. Each time the button is clicked I need the text from the textbox to be added as a new row in a table, which will then be presented on a gridview.
I have managed to add the text from the textbox as a new row, but every time I click the button it seems the table is not saved (meaning - I end up with only one row).
public partial class buildTable : System.Web.UI.Page
{
DataTable dt = new DataTable();
public int namesCounter;
protected void Page_Load(object sender, EventArgs e)
{
dt.Columns.Add("ID", typeof(Int16));
dt.Columns.Add("name", typeof(string));
namesCounter = 0;
names_GV.DataSource = dt;
}
protected void addName_Click(object sender, EventArgs e)
{
namesCounter += 1;
DataRow dtrow = dt.NewRow();
dtrow["ID"] = namesCounter;
dtrow["name"] = newName_TXT.Text;
dt.Rows.Add(dtrow);
names_GV.DataBind();
}
}
I'm guessing this has something to do with postback...
The problem here lies in the "statelessness" of asp.net. In short, each round trip to the page (first visit, post-backs) creates a new instance of buildTable, thus re-instantiating your dt variable and setting it as data source to your grid.
Consider sending the user input to some sort of persistence layer that enables you to hold the data per-user and rebinding said data with each post back. The strategy which could be used here really depends on the size and context of your application.
Please refer to:
Microsoft's ASP.NET State Management Overview (http://msdn.microsoft.com/en-us/library/75x4ha6s(v=vs.100).aspx) for state management strategies
Microsoft's State Management Recommendations (http://msdn.microsoft.com/en-us/library/z1hkazw7(v=vs.100).aspx) for state management recommendations
Introduction to ASP.NET Web Pages (http://msdn.microsoft.com/en-us/library/ms178125(v=vs.100).aspx) for further details about the page lifetime
You need to Add the ID and Table to Viewstate so that the State is retained because, here we are not saving the Data in the Database. So every time the Page Loads, the Data is Null unless we save it in a viewstate.
Check with the Code below:-
It will run perfectly :-
DataTable dt = new DataTable();
public int namesCounter;
protected void Page_Load(object sender, EventArgs e)
{
dt.Columns.Add("ID", typeof(Int32));
dt.Columns.Add("name", typeof(string));
//namesCounter = 0;
if (!IsPostBack)
{
ViewState["Number"] = 0;
ViewState["table"] = dt;
}
names_GV.DataSource = dt;
names_GV.DataBind();
}
protected void addName_Click(object sender, EventArgs e)
{
dt = (DataTable)ViewState["table"];
namesCounter = Convert.ToInt32(ViewState["Number"]) + 1;
ViewState["Number"] = namesCounter;
DataRow dtrow = dt.NewRow();
dtrow[0] = namesCounter;
// dtrow["ID"] = namesCounter;
dtrow["name"] = newName_TXT.Text;
dt.Rows.Add(dtrow);
ViewState["table"] = dt;
names_GV.DataSource = dt;
names_GV.DataBind();
}
This code is working properly with me,
add them in button click event
:
DataTable dt_items = new DataTable();
dt_items.Columns.Add("Item");
dt_items.Columns.Add("Quantity");
if (grid_items.Rows.Count > 0)
{
foreach (GridViewRow row in grid_items.Rows)
{
dt_items.Rows.Add(row.Cells[0].Text,row.Cells[1].Text);
}
}
dt_items.Rows.Add(ddl_item.SelectedItem.Text, txt_itemAmount.Text);
grid_items.DataSource = dt_items;
grid_items.DataBind();

How to Update values of dataGridView row in Winform

I have a dataGridview whose first column is Checkbox.Now as per my requirement i want to update the values of the dataGridView row on the selection of checkbox.I want it like as checkbox is clicked for a specific row ,that row should become editable and anything entered there should be updated on update button click.
Here is the code that i have for the gridview and Checkbox..
private void btn_load_Click(object sender, EventArgs e)
{
DataTable dt = new DataTable();
dt.Columns.Add("Select", System.Type.GetType("System.Boolean"));
dt.Columns.Add("UserName");
dt.Columns.Add("EmpID");
DataRow dr;
//Connection lines
connection.Open();
using (MySqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
dr = dt.NewRow();
dr["Select"] = false;
dr["UserName"] = reader["UserName"].ToString();
dr["EmpID"] = reader["EmpID"].ToString();
dt.Rows.Add(dr);
}
}
}
dataGridView1.AllowUserToAddRows = true;
dataGridView1.AllowUserToDeleteRows = true;
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
dataGridView1.DataSource = dt;
}
Please help me .Thanks in advance..
First thing to do is make sure that the only editable column in your GridView is the one with the checkbox.
So, right after you are done with loading the data into the grid, this needs to be added:
foreach (DataGridViewColumn dc in dataGridView1.Columns)
{
if (dc.Index.Equals(0))
{
dc.ReadOnly = false;
}
else
{
dc.ReadOnly = true;
}
}
This just sets all the columns except for the first one to be read only.
Now that you have your columns and the checkbox can be clicked, we need to somehow handle the changing of the checkbox state. Now, believe it or not, in order for this to work properly, we need to handle two events. There is a good reason for this. You see, if we handle the CellValueChanged event for the cells that contain the checkbox, it won't fire until the user leaves the cell after clicking it. This is what is considered to be the official end of editing the cell. That, of course won't do when checkboxes are in question, because we need to handle the event as soon as it's clicked. In order to do that, we will handle a second event - CellMouseUp, and in that handler force the editing to be finishe. It should all look something like this:
private void dataGridView1_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex == 0 && e.RowIndex != -1)
{
dataGridView1.EndEdit();
}
}
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0 && e.RowIndex != -1)
{
foreach (DataGridViewColumn dc in dataGridView1.Columns)
{
if (!dc.Index.Equals(0))
{
dc.ReadOnly =
!(bool)dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
}
}
}
}

Retrieving all GridViewRow objects from a GridView control with paging enabled

I currently have a GridView control on my aspx page with paging enabled and I need to loop through the entire row collection/count to process the selected records. With my current code, it will only loop through the current page of GridView row.
What is the best way to accomplish this task?
Here is my current code:
ASPX page:
<asp:GridView ID="MyGridView" runat="server" AllowPaging="true" PageSize="20">
<Columns>
<!-- My Column list -->
</Columns>
</asp:GridView>
<asp:Button id="MyButton" runat="server" Text="Add" OnClick="MyButton_Click" />
code behind:
protected void MyButton_Click(object sender, EventArgs e)
{
for (int Count = 0; Count < MyGridView.Rows.Count; Count++)
{
//The row count is 20 and only contains the GridViewRow object in the current page view
//I want to retrieve the all GridViews rows so I can add them to a ReorderList control
}
}
Yes because your gridview UI is only aware of the current page.
Get the datasource and determine the row count from there...
int count = ((DataTable)MyGridView.DataSource).Rows.Count;
//or
int count = ((ICollection<SomeRecord>)MyGridView.DataSource).Count;
Simply use the following code:
//Change gridview to
GridView1.AllowPaging = false;
GridView1.DataBind();
//Transfer rows from GridView to table
for (int i = 0; i < GridView1.Rows.Count; i++)
{
if (GridView1.Rows[i].RowType == DataControlRowType.DataRow)
{
for (int j = 0; j < GridView1.Rows[0].Cells.Count; j++)
{
//Add your code here..
}
}
}
//After filling your datatable change gridview paging style back to first, ie.
GridView1.AllowPaging = true;
GridView1.DataBind();
This may help you, let me know if this was helpful for you...
I think you should get the row count from your data source's row count.
If you need to filter rows, you can use DataTable's / DataView's Select method.
EDIT : You can not get actual row count by gridview.Rows.Count if gridview is paged. Depending on your comment, I assume that you're using listDataSource generic list to bind your gridview, you can get your row count as :
List<DataSourceItem> selectedRows =
listDataSource.FindAll(delegate(DataSourceItem item)
{
// Assuming you have a IsSelected bool property
// that refers your row is selected :
return item.IsSelected;
});
int rowCount = selectedRows.Count;
use session or state to store:
protected void Set_CheckboxStatus()
{
CheckBox selectall = (CheckBox)EmployeeGrid.HeaderRow.FindControl("gcb_selectall");
ArrayList cbstatuslist = new ArrayList();
if (Session["childcbstatus"] != null)
{
cbstatuslist = (ArrayList)Session["childcbstatus"];
}
foreach (GridViewRow row in EmployeeGrid.Rows)
{
int cb_index = (int)row.DataItemIndex; //For Getting DataItemIndex of EmployeeGrid
//int cb_index = (int)row.RowIndex;
CheckBox cb_selemp = (CheckBox)row.FindControl("gcb_selemp");
CheckBox cb_active = (CheckBox)row.FindControl("gcb_active");
if (cb_selemp.Checked == true)
{
if (!cbstatuslist.Contains(cb_index))
cbstatuslist.Add(cb_index);
}
else
{
cbstatuslist.Remove(cb_index);
}
}
Session["childcbstatus"] = cbstatuslist;
}
from the arraylist you can get all row index to loop and get the value from the gridview with paging.
#CRice's answer should have been the official answer.
Here is my solution. You need to presave the gridview's data, via its DataSource, into ViewState or Session.
GridView.Rows only refers to the "visible" rows, or the page currently shown on the screen.
protected void GridView_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView gv = (GridView)sender;
DataSourceSelectArguments dss = new DataSourceSelectArguments();
//get the datasource related to the gridview
string wsDataSourceID = (gv.DataSourceID == string.Empty) ? ViewState["DataSourceID"].ToString() : gv.DataSourceID;
SqlDataSource sds = (SqlDataSource)pnlMAIN.FindControl(wsDataSourceID);
if (sds != null)
{
//load the data again but this time into a dataview object
DataView dv = (DataView)sds.Select(DataSourceSelectArguments.Empty);
if (dv != null)
{
//convert the dataview to a datatable so we can see the row(s)
DataTable dt = (DataTable)dv.ToTable();
if (dt != null)
{
//Save your data before changing pages
ViewState["AllTheData"] = dt;
gv.DataSource = dt;
gv.DataSourceID = null;
}
}
}
//now change pages!
gv.PageIndex = e.NewPageIndex;
gv.DataBind();
}
Next, when changing pages, here we save the data
protected void GridView_PageIndexChanged(object sender, EventArgs e)
{
GridView gv = (GridView)sender;
DataSourceSelectArguments dss = new DataSourceSelectArguments();
//reload the datatable back to the gridview
gv.DataSource = ViewState["AllTheData"];
gv.DataSourceID = null;
gv.DataBind();
I hope the code speaks for itself.
Thanks

Categories