ASP.Net 4.5 Model Binding Sorting By Navigation Property

我的未来我决定 提交于 2019-11-30 22:02:19
Drauka

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.

JYL

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;

    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!