none
Somme d'une colonne de datagridview/bindingsource : évènement déclenchant RRS feed

  • Question

  •    Bonjour,

    J'affiche les données d'un bindingsource dans un datagridview et je fais la somme d'une colonne dans une variable afin de travailler avec ensuite et de l'afficher.

    Si je change une valeur dans la colonne (modification d'une valeur, ajout ou suppression d'une ligne) un évènement doit mettre à jour la variable.

    Mais quel évènement choisir ? J'ai testé des évènements sur le bindingsource (listchanged, currentchanged, currentitemchanged) et sur le datagridview (cellvalidated etc...) mais tous ces évènements sont exécutés lors du chargement de chaque ligne voire chaque champ de la source de données => 10000 fois s'il y a 10000 lignes dans la table, en termes de performances ce n'est pas top !

    Quelqu'un a-t-il une idée ?

    Merci.



    • Modifié laumon jeudi 3 novembre 2011 15:40
    jeudi 3 novembre 2011 14:23

Réponses

  • Super!!!

    Voici le code modifié. Je conserve le tout dans l'évènement ListChanged car je m'en ressert ensuite.

    RemoveHandler bsLigneBudget.ListChanged, AddressOf bsLigneBudget_ListChanged
    bsBudget.DataSource = aObjectContext.asaBudget.Include("LigneBudget").Where("it.Annee = @p ", New ObjectParameter("p2", DefaultAnnee))
    AddHandler bsLigneBudget.ListChanged, AddressOf bsLigneBudget_ListChanged

    Private Sub bsLigneBudget_ListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs) 'Mis en commentaire  >>> Handles bsLigneBudget.ListChanged
          CalculerLesTotaux()
    end sub

    Merci beaucoup, débutant je ne connaissais pas cette fonctionnalité.

    • Marqué comme réponse laumon vendredi 4 novembre 2011 10:22
    vendredi 4 novembre 2011 10:21

Toutes les réponses

  • Bonjour,

    Le mieux serait d'avoir la colonne somme dans la data source de votre BindingSource (BindingSource.DataSource) :

    Si la data source est un objet de l'un de vos types ou une collection, il faut ajouter une nouvelle propriété en lecture seule à votre type qui représenta la somme de vos deux colonnes.

    Si votre data source est une source Sql, il faut ajouter la colonne somme à votre requête.

     

    Si ce n'est pas très claire pour vous, vous pouvez toujours nos poster votre code ou une partie de celui ci pour que l'on puisse vous aider avec du code.

     

    Le pattern Binding Source est très puissant si n'est que le plus puissant dans le framework, il faut avoir la bonne aproche pour l'exploiter au maximum

    Bon courage.

    jeudi 3 novembre 2011 21:14
    Auteur de réponse
  • Merci,

    Il s'agit en fait de faire la somme d'une colonne et non pas de sommer plusieurs colonnes. Voici un morceau de mon code (épuré), j'ai choisi de mettre l'appel à la sub de calcul de totaux lors du listchanged de ma bindingsource. Comme je l'ai déjà dit j'ai essayé sur d'autres évènements, ça n'était pas mieux. Rien que lors du chargement de la source de données, le calcul est appelé 19 fois pour une table contenant 13 lignes. Je n'ose pas imaginer la perte de temps machine en phase d'exploitation avec quelques milliers de lignes.

    A présent, je sais qu'il y a une fonction du bindingsource qui permet de faire la somme d'une colonne, mais il faut que je puisse lui passer des critères en paramètre car en fonction des champs "CodeType" et "CodeParamètre" de la ligne je ne fait pas ma somme dans la même variable.

    Donc j'en revient à mon idée de départ, appeler la fonction de somme lorsque l'utilisateur fait une vraie modification de champ et pas lors du chargement de la source de données.

      
    Private Sub bsLigneBudget_ListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs) Handles bsLigneBudget.ListChanged
     ...
                If bsLigneBudget.Count > 0 Then
                    CalculerLesTotaux()
                End If
     ...
    End Sub

     Private Sub CalculerLesTotaux()
     ...

            Dim aLigneBudget As New LigneBudget
            For i = 0 To bsLigneBudget.Count - 1
                aLigneBudget = CType(bsLigneBudget.Item(i), LigneBudget)

                If aLigneBudget.CodeType = "D" And aLigneBudget.CodeNature = "F" Then
                    dTotHTDF += aLigneBudget.MtHT
                    dTotTVADF += aLigneBudget.MtTVA
                    dTotTTCDF += aLigneBudget.MtTTC
                ElseIf aLigneBudget.CodeType = "D" And aLigneBudget.CodeNature = "I" Then
                    dTotHTDI += aLigneBudget.MtHT
                    dTotTVADI += aLigneBudget.MtTVA
                    dTotTTCDI += aLigneBudget.MtTTC
                ElseIf aLigneBudget.CodeType = "R" And aLigneBudget.CodeNature = "F" Then
                    dTotHTRF += aLigneBudget.MtHT
                    dTotTVARF += aLigneBudget.MtTVA
                    dTotTTCRF += aLigneBudget.MtTTC
                ElseIf aLigneBudget.CodeType = "R" And aLigneBudget.CodeNature = "I" Then
                    dTotHTRI += aLigneBudget.MtHT
                    dTotTVARI += aLigneBudget.MtTVA
                    dTotTTCRI += aLigneBudget.MtTTC
                End If
            Next
     ...
        End Sub

    Je continue mes recherches, mais une piste positive serait la bienvenue...

    vendredi 4 novembre 2011 08:29
  • Bonjour,

     

    Autant pour moi, je n'avais pas compris qu'il s'agissait de faire la somme d'une colonne.

     

    Sinon l'événement qui doit être intéressant pour vous est 

     

    BindingSource.CurrentItemChanged

     

    l’évènement CurrentItemChanged de votre BindingSource.

    vendredi 4 novembre 2011 09:03
    Auteur de réponse
  • C'est la même chose.

    Lorsque je charge bon bindingsource : bsBudget.DataSource = aObjectContext.asaBudget.Include("LigneBudget").Where("it.Annee = @p ", New ObjectParameter("p2", DefaultAnnee))
    à chaque ligne un évènement est lancé.
    Donc je vais faire ceci avec un booleen

    dim bBindingSourceIsInLoad as boolean = false

    ...

    bBindingSourceIsInLoad = true
    bsBudget.DataSource = aObjectContext.asaBudget.Include("LigneBudget").Where("it.Annee = @p ", New ObjectParameter("p2", DefaultAnnee))
    bBindingSourceIsInLoad = false

    et dans l'évènement (lischanged ou tout autre évunement je rajoute le test suivant
    if bBindingSourceIsInLoad = false then
      If bsLigneBudget.Count > 0 Then
                    CalculerLesTotaux()
      End If
    endif

    Je ne trouve pas cette solution super mais ça va optimiser le traitement...

    Merci Ould pour t'être penché sur ce problème et s'il quelqu'un a une solution plus simple, je suis preneur...

    • Marqué comme réponse laumon vendredi 4 novembre 2011 09:30
    • Non marqué comme réponse laumon vendredi 4 novembre 2011 10:22
    vendredi 4 novembre 2011 09:29
  • Vous pouvez vous désabonner de l'évènement en question juste avant de charger votre data source puis vous réabonner à nouveau une fois ce ci fait.
    vendredi 4 novembre 2011 09:40
    Auteur de réponse
  • Super!!!

    Voici le code modifié. Je conserve le tout dans l'évènement ListChanged car je m'en ressert ensuite.

    RemoveHandler bsLigneBudget.ListChanged, AddressOf bsLigneBudget_ListChanged
    bsBudget.DataSource = aObjectContext.asaBudget.Include("LigneBudget").Where("it.Annee = @p ", New ObjectParameter("p2", DefaultAnnee))
    AddHandler bsLigneBudget.ListChanged, AddressOf bsLigneBudget_ListChanged

    Private Sub bsLigneBudget_ListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs) 'Mis en commentaire  >>> Handles bsLigneBudget.ListChanged
          CalculerLesTotaux()
    end sub

    Merci beaucoup, débutant je ne connaissais pas cette fonctionnalité.

    • Marqué comme réponse laumon vendredi 4 novembre 2011 10:22
    vendredi 4 novembre 2011 10:21