All,
I have a grid view that has the following columns. The paging work great, but not sorting. Everytime I click on the Category column to sort by category I would get this error:
Instance property 'Category.CategoryName' is not defined for type 'ESA.Data.Models.Entity.Project'
This error statement is not true because the gridview was able to display the column correctly.
Here is the select method
public IQueryable<Project> getProjects()
{
ApplicationServices objServices = new ApplicationServices();
IQueryable<Project> lstProject;
lstProject = objServices.getProjects();
return lstProject;
}
Any suggestion?
<asp:GridView ID="grdProject" runat="server" ShowHeader="true"
AutoGenerateColumns="false" CellPadding="2" CellSpacing="2"
ItemType="ESA.Data.Models.Entity.Project"
SelectMethod="getProjects"
DataKeyNames="ProjectID"
AllowSorting="true"
AllowPaging="true"
PageSize="5">
<Columns>
<asp:BoundField DataField="ProjectID" HeaderText="ID " ItemStyle-Width="10" />
<asp:BoundField DataField="Category.CategoryName" HeaderText="Category" SortExpression="Category.CategoryName" />
<asp:BoundField DataField="ProjectName" HeaderText="Project Name" ItemStyle-Width="300" />
<asp:BoundField DataField="Status.StatusName" HeaderText="Status" SortExpression="Status.StatusName" />
<asp:BoundField DataField="AddedByUser.UserName" HeaderText="Added By" ItemStyle-Width="120" />
<asp:BoundField DataField="AddedDate" HeaderText="Added Date" ItemStyle-Width="90" DataFormatString="{0:d}" />
</Columns>
</asp:GridView>
I was having a similar issue with a Listview control. I solved it like this.
firstly I'm using the code from this post by Marc Gravell Dynamic LINQ OrderBy on IEnumerable<T>
in my Listview's 'OnSorting' event I added the following code.
protected void lv_Sorting(object sender, ListViewSortEventArgs e)
{
e.Cancel = true;
ViewState["OrderBy"] = e.SortExpression;
lvList.DataBind();
}
I added a fairly standard way to capture the sortdirection list this
public SortDirection sortDirection
{
get
{
if (ViewState["sortdirection"] == null)
{
ViewState["sortdirection"] = SortDirection.Ascending;
return SortDirection.Ascending;
}
else if ((SortDirection)ViewState["sortdirection"] == SortDirection.Ascending)
{
ViewState["sortdirection"] = SortDirection.Descending;
return SortDirection.Descending;
}
else
{
ViewState["sortdirection"] = SortDirection.Ascending;
return SortDirection.Ascending;
}
}
set
{
ViewState["sortdirection"] = value;
}
}
In my Listview the Selectmethod looks like this (using the extension method from Marc)
public IQueryable<SomeObject> GetObjects([ViewState("OrderBy")]String OrderBy = null)
{
var list = GETSOMEOBJECTS();
if (OrderBy != null)
{
switch (sortDirection)
{
case SortDirection.Ascending:
list = list.OrderByDescending(OrderBy);
break;
case SortDirection.Descending:
list = list.OrderBy(OrderBy);
break;
default:
list = list.OrderByDescending(OrderBy);
break;
}
}
return list;
}
I Haven't tried it with a GridView but I'm fairly certain it would work just the same.
EDIT Here is an example of the linq extension class that should work
public static class LinqExtensions
{
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderBy");
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderByDescending");
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenBy");
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenByDescending");
}
static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
{
string[] props = property.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (string prop in props)
{
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
object result = typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { source, lambda });
return (IOrderedQueryable<T>)result;
}
}
Simply add a using 'whatevernamespaceyouused' to the page and you should be good to go.
Add a string parameter named sortByExpression
to your getProjects()
method.
If the gridView find this parameter in your method signature, it won't try to "auto order" your result and it will let you do the job.
To do the job yourself, you can use DynamicLinq (you can add the nuget package, or use the LinqExtensions
class posted by Drauka).
So your method will look like this :
// using System.Linq.Dynamic;
public IQueryable<Project> getProjects(string sortByExpression)
{
ApplicationServices objServices = new ApplicationServices();
IQueryable<Project> lstProject = objServices.getProjects();
if (!String.IsNullOrEmpty(sortByExpression))
lstProject = lstProject.OrderBy(sortByExpression);
return lstProject;
}
This way you don't bypass the gridView sort styles.
Source : decompiled framework code, specially System.Web.UI.WebControls.ModelDataSourceView.IsAutoSortingRequired(...)
Drauka your solution works for me, but I would get an error on this line of code eventhough I already reference System.Linq.Dynamic
The two line that give me syntax error are
lstProject = lstProject.OrderByDescending(OrderBy);
and the error messge is
The type arguments for method 'System.Linq.Enumerable.OrderByDescending(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
public IQueryable<Project> getProjects([ViewState("OrderBy")]String OrderBy = null)
{
ApplicationServices objServices = new ApplicationServices();
var lstProject = objServices.getProjects();
if (OrderBy != null)
{
switch (sortDirection)
{
case SortDirection.Ascending:
lstProject = lstProject.OrderByDescending(OrderBy);
break;
case SortDirection.Descending:
lstProject = lstProject.OrderBy(OrderBy);
break;
default:
lstProject = lstProject.OrderByDescending(OrderBy);
break;
}
}
return lstProject;
}
来源:https://stackoverflow.com/questions/16550231/asp-net-4-5-model-binding-sorting-by-navigation-property