IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Linq Discussion :

Dynamique OrderBy / ThenBy


Sujet :

Linq

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2009
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Finance

    Informations forums :
    Inscription : Février 2009
    Messages : 317
    Par défaut Dynamique OrderBy / ThenBy
    Bonjour à tous,

    je suis actuellement confronté à un petit problème...

    J'essaye de trier en cascade une Liste d'objets dynamiquement.

    Pour donner une représentation de ce que je souhaites faire, j'ai créé une fenêtre de tri comme dans Excel où on choisit de trier le résultat sur plusieurs colonnes en même temps.

    Il est possible avec linq de combiner des tri, cependant je n'ai vu comment le faire dynamiquement.

    On peut par exemple faire comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    trier = resu.OrderBy(pr => pr.NumTiers).ThenBy(pr => pr.NumPrestataire);
    Cependant,
    - Ce n'est pas dynamique , on ne peut pas choisir les propriétés de tri, on ne contrôle pas le nombre de niveaux de tri...

    Voici ce que j'ai essayé pour l'instant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    AdvancedList<DisplayClass.GridDisplayPrestation> resu = (AdvancedList<CAC.DisplayClass.GridDisplayPrestation>)dataGridViewPrestations.DataSource;
    IOrderedEnumerable<DisplayClass.GridDisplayPrestation> trier = null;
    foreach (Classes.Trier_OrdreColonne tri in TriageColonnes)
    {
     
                 if (tri.Ordre == SortOrder.Ascending)
                 {
                                trier = from pr in resu
                                        orderby orderBy(tri.Colonne.NomColonne, pr) ascending
                                        select pr;
     
                 }
                 else
                 {
                                trier = from pr in resu
                                        orderby orderBy(tri.Colonne.NomColonne, pr) descending
                                        select pr;
                 }
    }
    object orderBy(string sortKey, DisplayClass.GridDisplayPrestation prest)
    {
                if (sortKey == "NumClient")
                    return prest.NumTiers;
                else if (sortKey == "NomClient")
                    return prest.NomTiers;
                else if (sortKey == "NumPrestataire")
                    return prest.NumPrestataire;
                else if (sortKey == "NomPrestataire")
                    return prest.NomPrestataire;
                else if (sortKey == "NumActivite")
                    return prest.NumActivite;
                else if (sortKey == "NomActivite")
                    return prest.NomActivite;
                else return "";
    }
    Evidemment ici ça ne trie que par mon dernier élément de ma liste TriageColonnes.
    Cependant, je me disais qu'il serait possible de faire un orderBy sur le premier élément de tri et de faire ensuite des ThenBy pour tout les autres, cependant, impossible d'utiliser directement l'expression ThenBy.

    Pour acceder à ThenBy, je peux faire comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    trier = trier.ThenBy(pr => pr.NumTiers);
    Cependant ce n'est plus dynamique et ça serait partir sur une multitude de switch en fonction de la colonne à trier ...

    Quelqu'un d'entre vous aurait une idée ?

    Merci d'avance !

  2. #2
    Membre chevronné
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2009
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Finance

    Informations forums :
    Inscription : Février 2009
    Messages : 317
    Par défaut
    J'ai résolu mon problème avec cette library

    Pour ceux que ça intéresserait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    AdvancedList<DisplayClass.GridDisplayPrestation> resu = (AdvancedList<CAC.DisplayClass.GridDisplayPrestation>)dataGridViewPrestations.DataSource;
    var myQueryable = resu.AsQueryable();
    string orderexpression = "";
    foreach (Classes.Trier_OrdreColonne tri in TriageColonnes)
    {
             orderexpression += tri.Colonne.NomColonne;
             if (tri.Ordre == SortOrder.Descending)
                     orderexpression += " DESC";
              orderexpression += ",";
     
    }
    orderexpression = orderexpression.Remove(orderexpression.Length - 1);
    myQueryable = myQueryable.OrderBy(orderexpression);

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Déjà tu peux faire une méthode d'extension AddOrder qui va gérer le choix entre OrderBy et ThenBy :

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static IEnumerable<TSource> AddOrder<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        var ordered = source as IOrderedEnumerable<TSource>;
     
        if (ordered != null) // Il y a déjà un tri, donc ThenBy
            return ordered.ThenBy(keySelector);
        else // Sinon on trie normalement
            return source.OrderBy(keySelector);
    }

    Ensuite tu peux jouer avec les expressions Linq pour générer le delegate de tri. Voilà le code complet :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public static class OrderExtensions
    {
        static MethodInfo _addOrderMethod;
     
        static OrderExtensions()
        {
            Expression<Func<IEnumerable<object>, IEnumerable<object>>> expr = seq => seq.AddOrder(x => default(object));
            _addOrderMethod = ((MethodCallExpression)expr.Body).Method.GetGenericMethodDefinition();
        }
     
        public static IEnumerable<TSource> AddOrder<TSource>(this IEnumerable<TSource> source, string sortPropertyName)
        {
            var param = Expression.Parameter(typeof(TSource), "x");
            var memberExpr = Expression.PropertyOrField(param, sortPropertyName);
            var keySelectorExpr = Expression.Lambda(memberExpr, param);
            var keySelectorFunc = keySelectorExpr.Compile();
            var method = _addOrderMethod.MakeGenericMethod(typeof(TSource), memberExpr.Type);
            return (IEnumerable<TSource>)method.Invoke(null, new object[] { source, keySelectorFunc });
        }
     
        public static IEnumerable<TSource> AddOrder<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            var ordered = source as IOrderedEnumerable<TSource>;
     
            if (ordered != null) // Il y a déjà un tri, donc ThenBy
                return ordered.ThenBy(keySelector);
            else // Sinon on trie normalement
                return source.OrderBy(keySelector);
        }
    }
    Tu peux l'utiliser comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var list = ...
    var sorted = list.AddOrder("X").AddOrder("Y");

    Dans ton cas ça donne quelque chose comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    IEnumerable<DisplayClass.GridDisplayPrestation> resu = (IEnumerable<DisplayClass.GridDisplayPrestation>)dataGridViewPrestations.DataSource;
    IEnumerable<DisplayClass.GridDisplayPrestation> trie = resu;
    foreach (Classes.Trier_OrdreColonne tri in TriageColonnes)
    {
        trie = trie.AddOrder(tri.Colonne.NomColonne);
    }
    (reste à ajouter le Descending, mais c'est pas grand chose à faire à partir du code que je t'ai donné)

  4. #4
    Membre chevronné
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2009
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Finance

    Informations forums :
    Inscription : Février 2009
    Messages : 317
    Par défaut
    Merci Tomlev pour ta réponse, quelle solution préconise tu parmi celle que tu proposé et celle que j'ai trouvé via la librairie pré-cité ?

    Pour ma part, ta solution semble plus propre, mais bon je peux me tromper x)

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Dynamic Linq a l'avantage d'être assez souple, ce n'est pas limité au tri. Et c'est sûrement plus fiable que mon truc, vu que j'ai fait ça en quelques minutes et que je l'ai pas beaucoup testé... Pour les perfs je sais pas trop ce que ça donne, il faudrait tester

  6. #6
    Membre chevronné
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2009
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Finance

    Informations forums :
    Inscription : Février 2009
    Messages : 317
    Par défaut
    D'accord, un tout grand merci en tout cas, je garde ta solution sous le coude !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Orderby et thenby qui marchent à moitié
    Par Pelote2012 dans le forum Linq
    Réponses: 5
    Dernier message: 06/02/2014, 09h58
  2. Réponses: 20
    Dernier message: 11/10/2011, 10h03
  3. comment creer un alias dynamique avec BDE et ODBC
    Par david33 dans le forum C++Builder
    Réponses: 2
    Dernier message: 12/07/2002, 11h50
  4. Réponses: 4
    Dernier message: 13/05/2002, 16h43
  5. repertoire temp dynamique
    Par killpilot dans le forum C
    Réponses: 2
    Dernier message: 26/04/2002, 16h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo