I have a page that allows both sorting columns as well as a search option that filters the GridView data. The problem I am running into is the GridView's ViewState SortExpression gets lost when filtering the datatable through the Search option.
My question is how do I retain the ViewState after a DataBind to ensure the SortExpression is kept on the newly binded dataTable?
protected void Page_Load(object sender, EventArgs e)
{
try{
if (IsPostBack)
{
Control control = null;
string controlName = Request.Params["__EVENTTARGET"];
if (!String.IsNullOrEmpty(controlName))
{
control = FindControl(controlName);
GridViewRow gvRow1 = (GridViewRow)control.Parent.Parent;
string controlID = control.ID.ToString();
}
}
if(!IsPostBack)
{
DataGrid_Load(DAL.reg(HeadText.Text, OrgText.Text), "reg");
}
}
catch{}
}
private void DataGrid_Load(DataTable command, string type)
{
DataTable dataTable = new DataTable();
dataTable = command;
string sortDir = ViewState["SortDirection"] as string;
string sortExp = ViewState["SortExpression"] as string;
if(ViewState["SortExpression"] != null)
{
dataTable = resort(dataTable, sortExp, sortDir);
}
string myStatus = HeadText.Text;
DataRow[] dr = dataTable.Select("status = '" + myStatus + "'");
DataTable filteredDataTable = dataTable.Clone();
foreach (DataRow sourceRow in dr)
{
filteredDataTable.ImportRow(sourceRow);
}
GridView1.DataSource = filteredDataTable;
GridView1.DataBind();
}
public class dal
{
public DataTable reg(string head, string org = null)
{
if (head == "all")
return Data_Load(String.Format("SELECT * from reg"), "reg");
}
}
I resolved this and it was simply a problem with my Load Data procedure which did not take into account if there was something already filtered in the GridView and the filter was being lost on the new Load.
To fix this I made a static searchFilter variable and added a check for this in each of the methods that called for loading data into the GridView:
after column sorting
after the "Rows Per Page" is changed
Any other functions within that page that require Loading Data on that page.
The code looked this this in each of the functions that load data:
if(searchFilter != "")
loadDataWithFilter();
else
loadDataWithoutFilter();
I did not have to do anything with the Page_Load PostBack.
Related
For example I have a datagridview1 with data imported from a excel file and there are 12 columns: date, Name, Activity, Project,time, comment,ect. and 1000 row.
What I want to do is to filter only all with the Project name in project column.
for example I have support as a (Projectname) I want to show all columns filtyring by support rows.
I have combobox to select which column I need to filter it( e.g Project) here,
I tried with this code but it dose not work.
private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string projektItem = comboBox1.Items[comboBox1.SelectedIndex].ToString();
if (projektItem == "Project") {
foreach (DataRow dataRow in dataGridView1.Rows)
{
StringBuilder filter = new StringBuilder();
for (int i = 0; i < dataGridView1.Columns.Count - 1; i++)
{
filter.Append(dataRow[i].ToString());
filter.Append("\t");
}
dataGridView1.DataSource = filter.ToString();
}
if (projektItem == "Name") {
}
if (projektItem == "Aktivity") {
}
}
This is how I do it. convert datagridview to datatable
And this is func for filter purpose:
Hold the origin table to go back if you turn your filter off
//datagrid to datatable
DataTable datatable = new DataTable();
datatable = (DataTable)dataGridView1.DataSource;
//datatableOrigin to hold your origin table
DataTable originTable = null;
// find Function
Public void Find(string column, string st)
{
DataRow[] dtResult;
DataTable holder = New DataTable;
//get datatable Schema
DataTable holder = datatable.Clone();
holder.Rows.Clear();
If (originTable != null)
datatable = originTable;
Else
originTable = datatable;
//select return datarow array
dtResult = datatable.Select("[" + column + "] LIKE '%" + st + "%'");
//import all your result into holder
foreach(DataRow dr In dtResult){holder.ImportRow(dr);}
//pass from holder to datatable
datatable = holder.Copy();
holder.Clear();
}
public void showDT()
{
dataGridView1.DataSource = datatable;
}
private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
// choose your column here
}
private void btn_Clicked(object sender, EventArgs e)
{
Find('YourColumn, 'your search string);
showDT();
}
I have a gridview that I'd like to sort. I've read a few tutorials and copied most of my code directly from the MSDN page, but I can't get it to work. It compiles, but nothing happens when I click the grid column headers.
My HTML:
<asp:DataGrid runat="server" id="dgrMainGrid" CssClass="c_mainGrid"
AutoGenerateColumns="true" AllowSorting="true"
OnSorting="TaskGridView_Sorting" />
My Codebehind:
protected void TaskGridView_Sorting(object sender, GridViewSortEventArgs e)
{
//Retrieve the table from the session object.
DataTable dt = Session["Grid"] as DataTable;
if (dt != null)
{
dt.DefaultView.Sort = e.SortExpression + " " + GetSortDirection(e.SortExpression);
dgrMainGrid.DataSource = dt;
dgrMainGrid.DataBind();
}
}
private string GetSortDirection(string column)
{
// By default, set the sort direction to ascending.
string sortDirection = "ASC";
// Retrieve the last column that was sorted.
string sortExpression = ViewState["SortExpression"] as string;
if (sortExpression != null)
{
// Check if the same column is being sorted.
// Otherwise, the default value can be returned.
if (sortExpression == column)
{
string lastDirection = ViewState["SortDirection"] as string;
if ((lastDirection != null) && (lastDirection == "ASC"))
{
sortDirection = "DESC";
}
}
}
return sortDirection;
}
I know the data table in my session variable works, because it's the source for my grid on page load, which works fine. One other thing, if it's important, this gridview resides in an update panel.
As I said, most of this is copied from the MSDN page, and I've been through it until I'm going code-blind. Can someone see my mistake? Thanks.
You are using a DataGrid, not a GridView. According to Microsoft, DataGrid does not have a OnSorting event, but an OnSortCommand. Either use that or switch to GridView (recommended)
<asp:DataGrid runat="server" OnSortCommand="dgrMainGrid_SortCommand" id="dgrMainGrid" CssClass="c_mainGrid" AutoGenerateColumns="true" AllowSorting="true" />
And in code behind
protected void dgrMainGrid_SortCommand(object source, DataGridSortCommandEventArgs e)
{
DataTable dt = Session["Grid"] as DataTable;
if (dt != null)
{
dt.DefaultView.Sort = e.SortExpression + " " + GetSortDirection(e.SortExpression);
dgrMainGrid.DataSource = dt;
dgrMainGrid.DataBind();
}
}
And your GetSortDirection does not work as it should. See this example.
I have a datatable that I am populating with data, however if I want to edit the row I am getting an error
Unable to cast object of type 'System.Web.UI.WebControls.DataControlLinkButton' to type 'System.Web.UI.WebControls.TextBox'.
The code that populates the gridview is
public void addTochkout(string type, string no)
{
DataTable dt = (DataTable)Session["table_chkout"];
DataRow dr = dt.NewRow();
dr[0] = type;
dr[1] = no;
dt.Rows.Add(dr);
Session["table_detail"] = dt; //save dt to new session
gridbind();
}
public void gridbind()
{
//gridview
if (Session["table_detail"] != null)
{
DataTable dt = (DataTable)Session["table_detail"];
if (dt.Rows.Count > 0)
{
chkoutDetail.DataSource = dt;
chkoutDetail.DataBind();
string countitems = dt.Rows.Count.ToString();
Session["cart_counter"] = countitems;
}
}
else
{
chkoutDetail.DataSource = null;
chkoutDetail.DataBind();
}
}
Now, when I try and update the gridview I am getting the error above from the line
dt.Rows[row.DataItemIndex]["TicketType"] = ((TextBox)(row.Cells[1].Controls[0])).Text;
The entire code block where is erroring is
protected void TaskGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
//Retrieve the table from the session object.
DataTable dt = (DataTable)Session["table_detail"];
//Update the values.
GridViewRow row = chkoutDetail.Rows[e.RowIndex];
dt.Rows[row.DataItemIndex]["TicketType"] = ((TextBox)(row.Cells[1].Controls[0])).Text;
dt.Rows[row.DataItemIndex]["Price"] = ((TextBox)(row.Cells[2].Controls[0])).Text;
//Reset the edit index.
chkoutDetail.EditIndex = -1;
//Bind data to the GridView control.
gridbind();
}
I would be very grateful if you could help me solve this issue.
Simon
Note that when you have the Edit option enabled, the first and second cells of the edit mode of the row in the grid view are linkbuttons(Update and Cancel). So probably you have to change the index while getting the textbox in the row
//Cell number 2 for the first textbox. 0 for update link and 1 for cancel link
dt.Rows[row.DataItemIndex]["TicketType"] = ((TextBox)(row.Cells[2].Controls[0])).Text;
I had figured out my issue just after posting the, but it wouldn't allow me to answer the question.
heres my solutions
protected void TaskGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
try
{
// //Update the values.
string type = e.NewValues[0].ToString();
string qty = e.NewValues[1].ToString();
//Retrieve the table from the session object.
DataTable dt = (DataTable)Session["table_detail"];
dt.Rows[e.RowIndex]["TicketType"] = type;
dt.Rows[e.RowIndex]["TicketNo"] = qty;
dt.AcceptChanges();
chkoutDetail.EditIndex = -1;
//Bind data to the GridView control.
gridbind();
int value1 = Convert.ToInt32(ddtickettype.SelectedItem.Value);
int value2 = Convert.ToInt32(ddTicketno.SelectedItem.Value);
string tType = ddtickettype.SelectedItem.Text;
string tNo = ddTicketno.SelectedItem.Text;
int prevTotal = Convert.ToInt32(lblAmount.Text);
int total = (value1 * value2) + prevTotal;
Session["TotalAmount"] = total.ToString();
if (Session["TotalAmount"] != null)
{
lblAmount.Text = Session["TotalAmount"].ToString();
}
}
catch(Exception ex)
{
Response.Write(ex.Message);
}
}
I have a gridview and its data source comes from linq to sql statements:
var query = from user in dataContext.tbl_files
select new { user.File_Name, user.Upload_Time, user.Uploaded_By };
GridView1.DataSource = query.ToList();
GridView1.DataBind();
I am trying to implement sorting feature of gridview :
public void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
string previousSortExpression = (string)ViewState["SortDirection"];
string sortExpression = e.SortExpression;
SortDirection sortDirection = e.SortDirection;
if (sortExpression.Equals(previousSortExpression))
{
sortDirection = SortDirection.Descending;
ViewState["SortDirection"] = string.Empty;
}
else
ViewState["SortDirection"] = sortExpression;
string direction = sortDirection == SortDirection.Ascending ? "ASC" : "DESC";
e.SortExpression = string.Format("it.{0} {1}", e.SortExpression, direction);
DataTable dataTable = (DataTable)GridView1.DataSource; // here returns null!
if (dataTable != null)
{
DataView dataView = new DataView(dataTable);
dataView.Sort = e.SortExpression ;
GridView1.DataSource = dataView;
GridView1.DataBind();
}
}
But " DataTable dataTable = (DataTable)GridView1.DataSource; " line returns null however count of datasource is 4. I got this error :
{"Unable to cast object of type 'System.Collections.Generic.List1[<>f__AnonymousType03[System.String,System.Nullable`1[System.DateTime],System.String]]' to type 'System.Data.DataTable'."}
How can I sort my gridview and correct my mistake? Thanks..
You can't use the DataSource property of the grid to fetch the data source. It is only available after it is set and to the end of that postback. You'll need the fetch the data from the database again.
Something like this:
public void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
var users = (from user in dataContext.tbl_files
select new { user.File_Name, user.Upload_Time, user.Uploaded_By }).ToList().AsEnumerable();
switch(e.SortExpression)
{
case "File_Name":
users = users.OrderBy(x => x.File_Name);
break;
case "Upload_Time":
users = users.OrderBy(x => x.Upload_Time);
break;
case "Uploaded_By":
users = users.OrderBy(x => x.Uploaded_By);
break;
}
if(e.SortDirection == SortDirection.Descending)
users = users.Reverse();
GridView1.DataSource = users;
GridView1.DataBind();
}
Above answer is correct first you need to assign datasource to gridview again as sorting event is called.
So have to store the data somewhere.
For retrieving the datasource from grid you can follow below steps
The problem lies as you are assigning linq result as datasource of gridview and then taking datatable from the gridview datasource.
Try this code
BindingSource bs = (BindingSource )Gv.DataSource;
DataTable Dt = (DataTable ) bs.DataSource;
Contact if you have any doubt
I set GridView's source to be result from stored procedure, which is basically datatable.
ASPxGridView1.DataSource = dt1;
ASPxGridView1.DataBind();
This is happening on button click. On first step it is OK, but when I try to sort, filter or go to next page of results, gridview is empty, and I must click button (to call DataBind obviously) to see results.
So, my question is, how to somehow cache datatable from stored procedure, so I don't need to bind data on every sort or page change.
Thanks.
Generally, when you updating the ASPxGridView or WebChartControl data at runtime, this information isn't cached automatically.
So, you must provide it to the control at every request to the server, using the Page_Init event handler.
To improve performance, you can save data into a Session/Cache
variable.
For reference check following DevExpress KB regarding your question and KB:
rebinding gridview at each postback
Bind a grid to a DataTable via code.
Why might paging (sorting, grouping, filtering) not work in the ASPxGridView?
//Cache DataTable in Session to avoid multiple database hit on every postback
DataTable GetTable() {
//You can store a DataTable in the session state
DataTable table = Session["Table"] as DataTable;
if (table == null) {
table = new DataTable();
table.Columns.Add("id", typeof(int));
table.Columns.Add("data", typeof(String));
for (int n = 0; n < 100; n++) {
table.Rows.Add(n, "row" + n.ToString());
}
Session["Table"] = table;
}
//Otherwise you have to create a DataTable instance on every request:
//DataTable table = new DataTable();
//table.Columns.Add("id", typeof(int));
//table.Columns.Add("data", typeof(String));
//for(int n = 0; n < 100; n++) {
// table.Rows.Add(n, "row" + n.ToString());
//}
return table;
}
Reference links to improve the performance of DevExpress GridView controls:
Default grid data binding behavior is unworkable for large data sets
ASPxGridView.DataSourceForceStandardPaging Property
ASPxGridView - How to implement caching using the SqlCacheDependency or SqlDependency classes
Best Solution for ASPxGridView with Custom DataTable objects
Data caching on the client side
How To Cache Rows In DevExpress ASP.NET GridView
Performance issue in GridView when using paging & master detail view
Speed up your page loads with a lighter ViewState
Data Loading times and custom record loading
You can use AfterPerformCallback:
protected void gridSchedule_AfterPerformCallback(object sender,
DevExpress.Web.ASPxGridView.ASPxGridViewAfterPerformCallbackEventArgs e)
{
LoadGrid(gridSchedule);
}
Use ViewState
Step 1:
GridView1.DataSource = ds;
ViewState["itemsetPending"] = ds;
GridView1.DataBind();
Step 2:
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
DataSet m_DataTable = (DataSet)ViewState["itemsetPending"];
if (m_DataTable != null)
{
DataView m_dataview = new DataView(m_DataTable.Tables[0]);
if (Convert.ToInt32(ViewState["m_sort"]) == 0)
{
m_dataview.Sort = e.SortExpression + " " + ConvertSortDirectionToSql(SortDirection.Descending);
ViewState["m_sort"] = 1;
}
else
{
m_dataview.Sort = e.SortExpression + " " + ConvertSortDirectionToSql(e.SortDirection);
ViewState["m_sort"] = 0;
}
GridView1.DataSource = m_dataview;
GridView1.DataBind();
}
}
Here I m Fill the data from Store Procedure into Dataset and assigning into ViewState.Just try it.
private string ConvertSortDirectionToSql(SortDirection sortDirection)
{
string newSortDirection = String.Empty;
switch (sortDirection)
{
case SortDirection.Ascending:
newSortDirection = "ASC";
break;
case SortDirection.Descending:
newSortDirection = "DESC";
break;
}
return newSortDirection;
}