Με το δίκιο σου δεν κατάλαβες το “out-of-the-box”, δικό μου λάθος, μπερδεύτικα με το computed column του DataTable όπου μπορείς να ορίσεις formula.
Λοιπόν, αν και επιμένω στο ότι σωστότερο είναι το extra column να μπει εκ των προτέρων ως computed column στο DataTable ή ως property σε DataSource object, τελικά βρήκα μια λύση για να παίξεις πάνω στο DataGridView. Το κόλπο είναι να βάλεις τον DataGridView σε Virtual Mode.
To Virtual Mode σε υποχρεώνει να χειρίζεται εσύ το πότε θα περάσεις data από το source στο DGV και πίσω. Στην περίπτωσή, μιας και έχεις data binding δεν χρειάζεται να ασχοληθείς με τα data που έχεις ήδη αλλά μόνο με τα data που δεν έχεις, ήτοι το computed column.
Αν και τα λέει όλα αρκετά αναλυτικά στο MSDN, σου παραθέτω τον κώδικα που δοκίμασα ότι παίζει το concept. Χρειάζεσαι μια φόρμα και ένα data source που στην συγκεκριμένη περίπτωση είναι ο πίνακας Products . Κάνεις το κλασικό data binding και κατόπιν προσθέτεις ένα unbound column. Εδώ, έχω ένα computed column που είναι το γινόμενο UnitPrice * UnitsInStoc. To unbound column έχει index 7.
Οι τιμές που θέλεις να εμφανίζονται στο unbound column αποθηκεύονται σε ένα Generic Dictionary και μέσα από τα τρία παρακάτω events τις διαβάζεις και τις γράφεις όταν χρειάζεται.
Private computedValuesStore As System.Collections.Generic.Dictionary(Of Integer, Decimal)
Private Sub ProductsDataGridView_CellValueChanged(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles ProductsDataGridView.CellValueChanged
If e.RowIndex <> -1 AndAlso e.ColumnIndex = 7 Then
Dim productID As Integer = CType(ProductsDataGridView.Rows(e.RowIndex).Cells("ProductID").Value, Integer)
Dim unitPrice As Decimal = CType(ProductsDataGridView.Rows(e.RowIndex).Cells("DataGridViewTextBoxColumn6").Value, Decimal)
Dim unitsInStoc As Decimal = CType(ProductsDataGridView.Rows(e.RowIndex).Cells("DataGridViewTextBoxColumn7").Value, Decimal)
computedValuesStore(productID) = unitPrice * unitsInStoc
End If
End Sub
Private Sub ProductsDataGridView_CellValueNeeded(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles ProductsDataGridView.CellValueNeeded
If e.ColumnIndex = 7 Then
Dim productID As Integer = CType(ProductsDataGridView.Rows(e.RowIndex).Cells("ProductID").Value, Integer)
If computedValuesStore.ContainsKey(productID) Then
e.Value = computedValuesStore(productID)
Else
Dim unitPrice As Decimal = CType(ProductsDataGridView.Rows(e.RowIndex).Cells("DataGridViewTextBoxColumn6").Value, Decimal)
Dim unitsInStoc As Decimal = CType(ProductsDataGridView.Rows(e.RowIndex).Cells("DataGridViewTextBoxColumn7").Value, Decimal)
e.Value = unitPrice * unitsInStoc
End If
End If
End Sub
Private Sub ProductsDataGridView_CellValuePushed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles ProductsDataGridView.CellValuePushed
If e.ColumnIndex = 7 Then
Dim productID As Integer = CType(ProductsDataGridView.Rows(e.RowIndex).Cells("ProductID").Value, Integer)
If Not computedValuesStore.ContainsKey(productID) Then
computedValuesStore.Add(productID, CType(e.Value, Decimal))
Else
computedValuesStore(productID) = CType(e.Value, Decimal)
End If
End If
End Sub
Vir prudens non contra ventum mingit