Salve,
secondo me diventa troppo pesante lasciare il calcolo all'evento datagridview_CellFormatting, soluzione possibile ma al mio pensiero molto invasiva...
preferirei recuperare i dati dal db e, prima di caricare la datagridview, aggiungere una colonna non agganciata al db da usare come colonna "calcolata" di appoggio, come gia' indicata anche da @oregon... qui farei i miei bei conticini in base all'ordinamento eventualmente presente nella datagridview... e lo stesso ricalcolo va ri-effettuato ad ogni modifica/inserimento/cancellazione... pesante ma fattibile...
ad esempio, brutalmente,
Public Class Form1
Private m_dataTable As DataTable = Nothing
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' recupero dati dal db
LoadDataTable()
'aggiungo la colonna calcolata "vuota"
Me.m_dataTable.Columns.Add(New DataColumn With {.ColumnName = "Saldo", .DataType = System.Type.GetType("System.Decimal"), .DefaultValue = 0D})
Me.DataGridView1.DataSource = Me.m_dataTable.DefaultView
BalanceRecalc()
End Sub
Private Sub DataGridView1_Sorted(sender As Object, e As EventArgs) Handles DataGridView1.Sorted
Me.Cursor = Cursors.WaitCursor
Me.DataGridView1.SuspendLayout()
BalanceRecalc()
Me.DataGridView1.ResumeLayout()
Me.DataGridView1.Invalidate()
Me.Cursor = Cursors.Default
End Sub
Private Sub BalanceRecalc()
' calcolo del saldo riga per riga con aggiornamento della colonna "calcolata"
Dim bmb As BindingManagerBase = Me.DataGridView1.BindingContext(Me.DataGridView1.DataSource)
bmb.EndCurrentEdit()
Dim balance As Decimal = 0
For Each r As DataRowView In CType(Me.DataGridView1.DataSource, DataView)
balance += r("Valore") * If(r("DareAvere"), 1, -1)
r("Saldo") = balance
Next
End Sub
Private Sub LoadDataTable()
Dim dt As DataTable = New DataTable("Caricato dal db con un datareader")
If 1 = 1 Then
'qui popolo io come si conviene
dt.Columns.Add(New DataColumn With {.ColumnName = "Id", .DataType = System.Type.GetType("System.Int32")})
dt.Columns.Add(New DataColumn With {.ColumnName = "Data", .DataType = System.Type.GetType("System.DateTime")})
dt.Columns.Add(New DataColumn With {.ColumnName = "Descrizione", .DataType = System.Type.GetType("System.String")})
dt.Columns.Add(New DataColumn With {.ColumnName = "Valore", .DataType = System.Type.GetType("System.Decimal")})
' se "DareAvere" = true il valore e Dare, diversamente e' in Avere
' in pratica si puo' anche "visualizzare" il valore in dare/avere popolando la datagridview in maniera NON automatica ma definendo
' il layout delle colonne "a mano" e quindi valorizzando la colonna corrispondente in base a questo booleano
' nell'evento datagridview_CellFormatting, cioe' scrivendo:
' se "DareAvere" = true allora ColonnaDare= riga(Valore) e ColonnaAvere = ""
' se "DareAvere" = false allora ColonnaDare= "" e ColonnaAvere = riga(Valore)
dt.Columns.Add(New DataColumn With {.ColumnName = "DareAvere", .DataType = System.Type.GetType("System.Boolean")})
' carico 100 righe di prova...
For i As Integer = 1 To 100
Dim dr As DataRow = dt.NewRow
dr("Id") = i
dr("Data") = DateTime.Now.AddDays(i \ 4).Date
dr("Descrizione") = String.Format("{0}-{1}", i, DateTime.Now.AddDays(i \ 4))
dr("Valore") = ((i Mod 4) + 1) * 10
dr("DareAvere") = (i Mod 3) <> 2
dt.Rows.Add(dr)
dr = Nothing
Next
End If
Me.m_dataTable = dt
End Sub
End Class
dove, dopo aver popolato la datatable dal db come desiderato, aggiungo appunto una colonna non in binding, e quindi vado ad effettuare il ricalcolo riga per riga del saldo... al cambio dell'ordinamento o dopo le operazioni CUD va rieffettuata l'operazione...
ripeto, dispendiosa se le righe sono tante....
normalmente definisco la griglia sempre in base alle "mie impostazioni", quindi usando .AutoGenerateColumns = False, e gli aggiornamenti sono sempre legati all'utilizzo di stored procedures...
salutoni
--
Andrea