Сортировка привязки модели ASP.Net 4.5 по свойству навигации
Все,
У меня есть вид сетки, который имеет следующие столбцы. Пейджинг отлично работает, но не сортировка. Каждый раз, когда я нажимаю на столбец Категория для сортировки по категории, я получаю эту ошибку:
Свойство экземпляра "Category.CategoryName" не определено для типа "ESA.Data.Models.Entity.Project".
Это утверждение об ошибке неверно, потому что grid view смог правильно отобразить столбец.
Вот метод выбора
public IQueryable<Project> getProjects()
{
ApplicationServices objServices = new ApplicationServices();
IQueryable<Project> lstProject;
lstProject = objServices.getProjects();
return lstProject;
}
Любое предложение?
<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>
3 ответа
У меня была похожая проблема с элементом управления Listview. Я решил это так.
во-первых, я использую код из этого поста Марка Грэвелла, динамический LINQ OrderBy на IEnumerable
в событие OnSorting моего Listview я добавил следующий код.
protected void lv_Sorting(object sender, ListViewSortEventArgs e)
{
e.Cancel = true;
ViewState["OrderBy"] = e.SortExpression;
lvList.DataBind();
}
Я добавил довольно стандартный способ захвата списка сортировки
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;
}
}
В моем ListView метод выбора выглядит следующим образом (с использованием метода расширения от 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;
}
Я не пробовал это с GridView, но я уверен, что он будет работать точно так же.
РЕДАКТИРОВАТЬ Вот пример класса расширения linq, который должен работать
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;
}
}
Просто добавьте на страницу "whatevernamespaceyouused", и все будет хорошо.
Добавьте строковый параметр с именем sortByExpression
на ваш getProjects()
метод.
Если gridView найдет этот параметр в сигнатуре вашего метода, он не будет пытаться автоматически упорядочить ваш результат и позволит вам выполнить эту работу.
Чтобы сделать работу самостоятельно, вы можете использовать DynamicLinq (вы можете добавить пакет nuget или использовать LinqExtensions
класс размещен Драукой).
Итак, ваш метод будет выглядеть так:
// 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;
}
Таким образом, вы не обойдете стили сортировки gridView.
Источник: декомпилированный фреймворк, специально System.Web.UI.WebControls.ModelDataSourceView.IsAutoSortingRequired(...)
Drauka, ваше решение работает для меня, но я получаю сообщение об ошибке в этой строке кода, хотя я уже ссылаюсь на System.Linq.Dynamic
Две строки, которые дают мне синтаксическую ошибку:
lstProject = lstProject.OrderByDescending(OrderBy);
и сообщение об ошибке
Аргументы типа для метода 'System.Linq.Enumerable.OrderByDescending(System.Collections.Generic.IEnumerable, System.Func)' не могут быть выведены из использования. Попробуйте указать аргументы типа явно.
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;
}