6

Edit 2019-01-31: Latest solution

I've followed examples here and here to create a generic sort with memberexpressions, but I can't figure out how I'm supposed to add a "ThenBy" clause, or combine multiple columns for sorting in the methodcallexpression. Ideally, the ThenBy should go before skip, but it can't because it can't see the orderby clause that I made with the methodcallexpression. GridSortExpression is a Telerik class - it just describes which column and direction the query should be sorted.

Can anyone shed some light? Here is what I have right now:

Dim exp As Expressions.Expression(Of Func(Of Product_Catalog, Boolean)) = PredicateBuilder.True(Of Product_Catalog)()
exp = exp.And(Function(e) e.Chapter_Price > 30)
Dim sortExpression As New List(Of GridSortExpression)({New GridSortExpression() With {.SortOrder = GridSortOrder.Descending, .FieldName = "Id"}})
If sortExpression.Count = 0 Then
     catalogList = con.Product_Catalogs.AsExpandable.Where(exp).OrderBy(Function(o) o.Item_Type).ThenBy(Function(o) o.Item_Description).Skip(startRowIndex).Take(maximumRows).ToList
Else
     Dim param As ParameterExpression = Expression.Parameter(GetType(Product_Catalog), String.Empty)
     Dim prop As MemberExpression = Expression.PropertyOrField(param, sortExpression(0).FieldName)
     Dim sort As LambdaExpression = Expression.Lambda(prop, param)
     Dim source = con.Product_Catalogs.AsExpandable.Where(exp)
     Dim resultExp As MethodCallExpression
     resultExp = Expression.[Call](GetType(Queryable), "OrderBy" & If(sortExpression(0).SortOrder = GridSortOrder.Descending, "Descending", ""), _
         New Type() {GetType(Product_Catalog), prop.Type}, con.Product_Catalogs.AsExpandable.Where(exp).Expression, Expression.Quote(sort))

     catalogList = source.Provider.CreateQuery(Of Product_Catalog)(resultExp).Skip(startRowIndex).Take(maximumRows).ToList
End If
dtryan
  • 527
  • 3
  • 14
  • Although, not exactly what I was looking for back in '11, this article might help someone with a similar problem: http://www.codeproject.com/Articles/280952/Multiple-Column-Sorting-by-Field-Names-Using-Linq – dtryan Oct 09 '13 at 19:14
  • My [latest implementation](https://pastebin.com/PH5v1NRs) of this problem – dtryan Feb 01 '19 at 00:28

2 Answers2

1

Here is a very generic way to do property sorting without having to implement multiple sort comparers for each slightly different sort.

it will allow any number of sort "Columns" (though you would need to enhance slightly to support different sort directions)

The drawback is it's obviously not the most efficient, though the use of invoking delegates is far more efficient then using reflection. You also need to define a general function of the properties of the objects that you may want to sort by. By making it more object specific you may be able to fix that aspect...

Public Class PropertySortComparer
Implements IComparer

Public Delegate Function GetProp(ByVal obj As Object) As Object
Public SortProps As New List(Of GetProp)

Public Sub New(ParamArray SortMethods() As GetProp)
    Me.SortProps.AddRange(SortMethods)
End Sub

Public Function Compare(x As Object, y As Object) As Integer Implements System.Collections.IComparer.Compare
    For Each gp As GetProp In SortProps
        Dim xVal As Object = gp.Invoke(x)
        Dim yVal As Object = gp.Invoke(y)
        If xVal > yVal Then
            Return 1
        ElseIf xVal < yVal Then
            Return -1
        Else
            'next loop does next property
        End If
    Next
    Return 0
End Function
End Class

Public Module module1
Sub test()
    Dim buffer As New List(Of Rectangle)
    buffer.Add(New Rectangle(34, 55, 40, 30))
    buffer.Add(New Rectangle(34, 55, 45, 38))
    buffer.Add(New Rectangle(34, 56, 46, 30))
    buffer.Add(New Rectangle(34, 70, 45, 30))

    Dim Lst() As Rectangle = buffer.ToArray
    Array.Sort(Lst, New PropertySortComparer(AddressOf Left, AddressOf Top, AddressOf Widht))
    'Lst is now sorted by Left, Top, Width
End Sub

Public Function Left(r As Object) As Object
    Return r.Left
End Function

Public Function Top(r As Object) As Object
    Return r.Top
End Function

Public Function Widht(r As Object) As Object
    Return r.Width
End Function

End Module
DarrenMB
  • 2,342
  • 1
  • 21
  • 26
  • Obviously this was not built to your specific case but the concept could be adapted to your scenario. – DarrenMB Apr 14 '13 at 22:18
  • I prefer the long syntax, in most cases. I find that when you have allot of code it is easier to understand at a quick glance what is going on. Eg. reading "gp(x)" tells me nothing later unless I also review the type of object. I also avoid single line "IF Condition THEN Block" statements preferring the full multiline format which shows a better flow. – DarrenMB Jun 07 '13 at 10:19
  • I'm surprised how many times I have received comments about shorter forms of syntax. especially since the purpose of this site is to assist with understanding the code and sorting out problems. You would think the real objective would be the format that explains more of what is going on as opposed to always trying to make things less keystrokes. – DarrenMB Jun 07 '13 at 10:22
  • I did say it was a "minor" point. I also mentioned it only after confirming it compiles to the same code. (And delegates are for executing :-) ) – Mark Hurd Jun 07 '13 at 18:51
0

Are you trying to do a sort where one day you may sort based on 1 property, then on another day the sort maybe based on 2 or more properties?

If so you may need to use reflection in order to get the number of properties and then sort them based on their TYPE. It is an interesting idea if your aim is to be able to sort based on any number of properties. However what if one of those properties has the TYPE that it another CLASS, what then?

I think you may need to look at

Implements IComparable

in order to build your own routine to do a Sort.

There is an example of using it here:>>

http://msdn.microsoft.com/en-us/library/4d7sx9hd(VS.80).aspx

However this would be specific for each Class that you create.