Gridview sorting in ASP.NET - c#

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

Related

GridView loses ViewState "SortExpression" after DataBind

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.

Sort GridView by column name

I am making a GridView and assigning it to the View property of a ListView. The ListView's ItemsSource is bound to an ObservableCollection<Entry>. Entry is a model in my MVVM application, and it contains a List<KeyValuePair<string,string>>. It also has an indexer which fetches the first KeyValurPair<string,string>'s Value property (from the list) which matches the indexer parameter. So it's much like a dictionary.
Now here's how I am making the GridView.
foreach (Column column in category.Columns.Where(c => c.IsVisibleInTable)) {
var gridViewColumn = new GridViewColumn {
Header = column.Name,
DisplayMemberBinding = new Binding($"[{column.Name}].Value")
};
gridView.Columns.Add(gridViewColumn);
}
Column is also a model but that's not really relevant here.
Now I want to tell the GridView to sort based on the first column. But I can't use the DefaultView of the ItemsSource and add a SortDescription to it because SortDescription expects a Property name whereas I am not binding to a property name but instead to an indexer.
So how can I sort based on the second column?
here is sorting algo
iN gridview pass this two parameter aspx
AllowSorting="true"
OnSorting="OnSorting"
private string SortDirection
{
get { return ViewState["SortDirection"] != null ? ViewState["SortDirection"].ToString() : "ASC"; }
set { ViewState["SortDirection"] = value; }
}
protected void OnSorting(object sender, GridViewSortEventArgs e)
{
this.BindGrid(e.SortExpression);
}
here we have to place the code
` private void BindGrid(string sortExpression = null)
{
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * from [test].[dbo].[myform] order by name", conn);
SqlDataAdapter sda = new SqlDataAdapter();
cmd.Connection = conn;
sda.SelectCommand = cmd;
using (DataTable dt = new DataTable())
{
sda.Fill(dt);
if (sortExpression != null)
{
DataView dv = dt.AsDataView();
this.SortDirection = this.SortDirection == "ASC" ? "DESC" : "ASC";
dv.Sort = sortExpression + " " + this.SortDirection;
GridView2.DataSource = dv;
}
else
{
GridView2.DataSource = dt;
}
GridView2.DataBind();
conn.Close();
}
}`

Making a DataGridViewColumn sortable

I work in C-sharp on ASP NET 4.
I need to add a sorting function to a column in a GridView. I've set the AllowSorting-property on the GridView to true and added sort expressions to the column.
Unfortunately, the sorting isn't working in the GridView.
Below is my code-behind-file for the column that should be able to sort, but I get the error
CS1502: The best overloaded method match for 'System.Data.DataView.DataView(System.Data.DataTable)' has some invalid arguments
on this line:
DataView sortedView = new DataView(BindData());
Code behind:
string sortingDirection;
public SortDirection dir
{
get
{
if (ViewState["dirState"] == null)
{
ViewState["dirState"] = SortDirection.Ascending;
}
return (SortDirection)ViewState["dirState"];
}
set
{
ViewState["dirState"] = value;
}
}
public string SortField
{
get
{
return (string)ViewState["SortField"] ?? "Name";
}
set
{
ViewState["SortField"] = value;
}
}
protected void gvProducts_Sorting(object sender, GridViewSortEventArgs e)
{
sortingDirection = string.Empty;
if (dir == SortDirection.Ascending)
{
dir = SortDirection.Descending;
sortingDirection = "Desc";
}
else
{
dir = SortDirection.Ascending;
sortingDirection = "Asc";
}
DataView sortedView = new DataView(RetrieveProducts());
sortedView.Sort = e.SortExpression + " " + sortingDirection;
SortField = e.SortExpression;
gvProducts.DataSource = sortedView;
gvProducts.DataBind();
}
protected void gvProducts_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
if (dir == SortDirection.Ascending)
{
sortingDirection = "Asc";
}
else
{
sortingDirection = "Desc";
}
DataView sortedView = new DataView(RetrieveProducts());
sortedView.Sort = SortField + " " + sortingDirection;
gvProducts.DataSource = sortedView;
gvProducts.PageIndex = e.NewPageIndex;
gvProducts.DataBind();
}
private void BindData()
{
gvProducts.DataSource = RetrieveProducts();
gvProducts.DataBind();
}
private DataSet RetrieveProducts()
{
DataSet dsProducts = new DataSet();
string sql = " ... ";
using (OdbcConnection cn =
new OdbcConnection(ConfigurationManager.ConnectionStrings["ConnMySQL"].ConnectionString))
{
cn.Open();
using (OdbcCommand cmd = new OdbcCommand(sql, cn))
{
........
}
}
return dsProducts;
}
Edit #1
DataView sortedView = new DataView(dsProducts.Tables[0]);
Edit # 2
I have added in aspx page:
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
But If clicked in Column Name I have this new error:
System.IndexOutOfRangeException: Cannot find table 0.
on this line:
Line 100: DataView sortedView = new DataView(dsProducts.Tables[0]);
The DataView class has only three constructors, in which one is default constructor DataView(), second one takes a DataTable as an argument DataView(DataTable), the other one takes four arguments DataView(DataTable, String, String, DataViewRowState).
The DataView constructor expects arguments of any one of these types, but your code has argument of some other type. That's the error.
Your BindData method should return a DataTable object,
//This function should return a Datatable
private void BindData()
{
gvProducts.DataSource = RetrieveProducts();
gvProducts.DataBind();
}
which you can pass into your DataView here.
DataView sortedView = new DataView(BindData());
For your second edit,
System.IndexOutOfRangeException: Cannot find table 0.
on this line:
Line 100: DataView sortedView = new DataView(dsProducts.Tables[0]);
I guess the dataset is empty, the error clearly states that there isn't any table in the dataset at position 0. So check whether your dataset has tables or not. Might be your sql request didn't get any table to fill in the dataset.
Else you might have created a new instance of the dataset.

Sorting a gridview control - The direction never changes

I can't seem to get this right, even after looking at a few examples.
I've got this code, which happily re-sorts my gridview in an Ascending order:
// gridViewSorting and ConvertSortDirectionToSql are both necessary to ensure the gridview can sort when their column headers are
// clicked. You must remember to add (AllowSorting="True" OnSorting="gridViewSorting") to the gridview tag on the ASP side
protected void gridViewSorting(object sender, GridViewSortEventArgs e)
{
DataTable dataTable = GVInactive.DataSource as DataTable;
if (dataTable != null)
{
DataView dataView = new DataView(dataTable);
string SQL = "[" + e.SortExpression + "] " + ConvertSortDirectionToSql(e.SortDirection);
dataView.Sort = SQL;
GVInactive.DataSource = dataView.ToTable();
GVInactive.DataBind();
}
}
private string ConvertSortDirectionToSql(SortDirection sortDirection)
{
string newSortDirection = String.Empty;
switch (sortDirection)
{
case SortDirection.Ascending:
newSortDirection = "DESC";
break;
case SortDirection.Descending:
newSortDirection = "ASC";
break;
}
return newSortDirection;
}
However, the second time I click on the header it's supposed to reverse the previous sorting order. It never does. Every time I click the header of a column, it hits the case SortDirection.Ascending: line and sets newSortDirection = "DESC". The data is sorted in descending order, yet when I click the header again it resolves SortDirection to Ascending.
Any ideas?
We use a ViewState variable to store the latest Sort Direction. When the grid is sorted we compare the Sort Criteria and Sort Direction of the grid with the ViewState variables which stores last sort expression. If the columns are equal then check the direction of the previous sort and sort in the opposite direction.
Example:
private string SortCriteria
{
get
{
if (ViewState["sortCriteria"] == null)
{
ViewState["sortCriteria"] = "";
}
return ViewState["sortCriteria"].ToString();
}
set
{
ViewState["sortCriteria"] = value;
}
}
private string SortDirection
{
get
{
if (ViewState["sortDirection"] == null)
{
ViewState["sortDirection"] = "";
}
return ViewState["sortDirection"].ToString();
}
set
{
ViewState["sortDirection"] = value;
}
}
protected void gvData_Sorting(object sender, GridViewSortEventArgs e)
{
gvData.EditIndex = -1;
if (SortCriteria == e.SortExpression)
{
if (SortDirection == string.Empty || SortDirection == "DESC") { SortDirection = "ASC"; }
else { SortDirection = "DESC"; }
}
else
{
SortCriteria = e.SortExpression;
SortDirection = "ASC";
}
BindGrid();
}
private void BindGrid()
{
DataTable dt = new [However you get dataset from database];
DataView dv = new DataView(dt);
dv.Sort = string.Format("{0} {1}", SortCriteria, SortDirection).Trim();
gvData.DataSource = dv;
gvData.DataBind();
}
For the record, I replaced the code used in my question with this, and it worked perfectly:
// gridViewSorting and ConvertSortDirectionToSql are both necessary to ensure the gridview can sort when their column headers are
// clicked. You must remember to add (AllowSorting="True" OnSorting="gridViewSorting") to the gridview tag on the ASP side
protected void gridViewSorting(object sender, GridViewSortEventArgs e)
{
DataTable dataTable = GVInactive.DataSource as DataTable;
string sortExpression = e.SortExpression;
string direction = string.Empty;
if (dataTable != null)
{
DataView dataView = new DataView(dataTable);
if (SortDirection == SortDirection.Ascending)
{
SortDirection = SortDirection.Descending;
direction = " DESC";
}
else
{
SortDirection = SortDirection.Ascending;
direction = " ASC";
}
DataTable table = GVInactive.DataSource as DataTable;
table.DefaultView.Sort = sortExpression + direction;
GVInactive.DataSource = table;
GVInactive.DataBind();
}
}
public SortDirection SortDirection
{
get
{
if (ViewState["SortDirection"] == null)
{
ViewState["SortDirection"] = SortDirection.Ascending;
}
return (SortDirection)ViewState["SortDirection"];
}
set
{
ViewState["SortDirection"] = value;
}
}
I can probably remove a few lines (not sure I even need the DataView anymore), but it works perfectly as is. Just remember to add these pieces to the ASP side in the GridView tag:
AllowSorting="True" OnSorting="gridViewSorting"
and then change your gridview's name where appropriate.

Dynamic sorting of Gridview

I am working of datagrid sorting. But GridViewStudents.dataSource is returning null in sorting function. I tried using session & viewstate. But doesn't work.
Any help appreciated.
My asp code for datagrid:
<asp:GridView ID="GridViewStudents" runat="server" AllowSorting="True"
onsorting="GridViewStudents_Sorting" ></asp:GridView>
Sorting function:
protected void GridViewStudents_Sorting(object sender, GridViewSortEventArgs e)
{
DataTable dataTable = GridViewStudents.DataSource as DataTable;
if (dataTable != null)
{
DataView dataView = new DataView(dataTable);
GridViewStudents.Sort = e.SortExpression + " " + ConvertSortDirectionToSql(e.SortDirection);
GridViewStudents.DataSource = dataView;
GridViewStudents.DataBind();
}
}
Sorting helper function:
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;
}
Apply automatic sorting mode
dataGridView1.Columns["ColName"].SortMode = DataGridViewColumnSortMode.Automatic;
Try this....
DataGridView control is sorted using a column with a SortMode property value of Automatic, a sorting glyph is automatically displayed in the column header.
Make sure that you rebind your Gridview on each roundtrip. The datasource of a gridview is not automatically stored in gridview or viewstate. If you need to access the datasource, you need to propagate the datasource first.
I found the solution.
Hope it is useful for others.
For anyone who come across DataGridView sorting problem.
Remember 4 steps.
Declare global dataset object
static DataSet ds = null;
Load data to grid
if (!IsPostBack)
{
loadData();
}
Write sorting function
protected void GridViewStudents_Sorting(object sender, GridViewSortEventArgs e)
{
DataTable dataTable = new DataTable();
dataTable = ds.Tables[0];
if (dataTable != null)
{
DataView dataView = new DataView(dataTable);
dataView.Sort = e.SortExpression + " " + ConvertSortDirectionToSql(e.SortDirection);
GridViewStudents.DataSource = dataView;
GridViewStudents.DataBind();
}
}
Sorting helper function
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;
}

Categories

Resources