Datagridview optimization VB.Net - vb.net

I just want to ask if there is another alternative for filling up the cells in the datagridview. Currently I'm using this code :
For i = DataGridView1.CurrentCell.RowIndex To x - 1
DataGridView1.Rows(i).Cells("LastName").Value = empcoll.Item(i).LastName
DataGridView1.Rows(i).Cells("FirstName").Value = empcoll.Item(i).FirstName
DataGridView1.Rows(i).Cells("MiddleName").Value = empcoll.Item(i).MiddleName
DataGridView1.Rows(i).Cells("CreatedBy").Value = empcoll.Item(i).CreatedBy
DataGridView1.Rows(i).Cells("CreateDate").Value = empcoll.Item(i).CreateDate
DataGridView1.Rows(i).Cells("Status").Value = empcoll.Item(i).Status
DataGridView1.Rows(i).Cells("DailySalary").Value = empcoll.Item(i).DailySalary
DataGridView1.Rows(i).Cells("BirthDate").Value = empcoll.Item(i).BirthDate
Next i
but when I use it for databases with a large number of records, it tends to load slow and hangs up.

You can use the SQLDataSource control (http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.sqldatasource.aspx) and then bind the DataGridView to the SQLDataSource. It is described here: http://www.vkinfotek.com/gridview/bind-gridview-sqldatasource-control.html.

In general, you should be Data Binding the columns to the properties on the objects instead of the method you're currently using.
It would look something like this
LastNameColumn.DataPropertyname = "LastName"
FirstNameColumn.DataPropertyname = "FirstName"
....
DataGridView1.DataSource = MyListofEmployeeObjects
As far as the load speed, there are two options: pagination, and virtual mode.
With pagination, you can pull X of Y records from the database at a time and display them in the grid.
Virtual mode ( http://msdn.microsoft.com/en-us/library/ms171622.aspx ) enables the DataGridView to handle automatic pulling/pushing of the records from/to the database so that you do not have to load all records at once.

Well, I prefer to use the DatagridView.Rows.Add method for unbounded DataGridViews.
Something like this:
Dim loData(7) as object
DataGridView1.Rows.Clear()
For i = DataGridView1.CurrentCell.RowIndex To x - 1
loData(0) = empcoll.Item(i).LastName
loData(1) = empcoll.Item(i).FirstName
loData(2) = empcoll.Item(i).MiddleName
loData(3) = empcoll.Item(i).CreatedBy
loData(4) = empcoll.Item(i).CreateDate
loData(5) = empcoll.Item(i).Status
loData(6) = empcoll.Item(i).DailySalary
loData(7) = empcoll.Item(i).BirthDate
DataGridView1.Rows.Add(loData)
Next i
I usually declare en enum to give a meaning name to each array element and make the code cleaner:
private enum eCols
LastName
Firstname
MiddleName
CreatedBy
CreateDate
Status
DailySalary
BirthDate
end enum
Dim loData(7) as object
DataGridView1.Rows.Clear()
For i = DataGridView1.CurrentCell.RowIndex To x - 1
loData(eCol.LastName) = empcoll.Item(i).LastName
loData(eCol.FirstName) = empcoll.Item(i).FirstName
loData(eCol.MiddleName) = empcoll.Item(i).MiddleName
loData(eCol.CreatedBy) = empcoll.Item(i).CreatedBy
loData(eCol.CreateDate) = empcoll.Item(i).CreateDate
loData(eCol.Status) = empcoll.Item(i).Status
loData(eCol.DailySalary) = empcoll.Item(i).DailySalary
loData(eCol.BirthDate) = empcoll.Item(i).BirthDate
DataGridView1.Rows.Add(loData)
Next i

Related

Global Class for SQL enumerated objects

I'm working on a tool crib VB.NET project, my first real one, so I'm struggling with a few things. In my SQL database I have a few tables that translate into enumerated fields. For example I have code and code type tables. I have a code type with CodeTypeID = 2 and description = Tool Status. These are used to track the location of a tool; Shop, In Transit, On Site, Out of Service, etc. I've set up enumerations for some of these.
Enum CodeType
User = 1
ToolStatus = 2
Repair = 3
OutOfService = 4
End Enum
ToolStatus
Shop = 5
Reserved = 6
InTransit = 7
OnSite = 9
ReturnTransit = 10
OutOfService = 11
Repair = 12
End Enum
The problem is if I change a code in SQL I then have to edit my enumerations as well. In the SQL tables I am only storing the CodeID and join to the code table to get the description. Other than an enumeration, I haven't found a good way to load these tables when the project opens that will allow me to code as easily, for example ToolStatus.OnSite to return the number 9 to my SQL table. It just seems inefficient to me. I always try to code my SQL procedures so if something changes I don't have to go and edit a bunch of procedures and would like to do the same here, especially as a simple addition of a new code could force a version update. Is there a better way to do this? I have searched the Internet and haven't found anything that really works as well as enumeration.
Example Code:
In the following code both OnSite and ReturnTransit are enumerations.
I'm moving items between two datagridviews, a Source and a Target DGV. Also updating the underlying shared datatable.
Dim cbo As ComboBox = sender
With cbo
Select Case .Name
Case "cboPeeps"
dvgFilter = "N"
Case "cboToolbox"
For i As Integer = 0 To dtTools.Rows.Count - 1
dtTools.Rows(i)("dgvFilter") = dtTools.Rows(i)("dbFilter")
Next
If cbo.Items.Count > 0 Then
filter = "ToolboxID=" & .SelectedValue.ToString & " And ToolStatus=" & OnSite
filter += " And UserID=" & .SelectedItem("UserID").ToString
End If
dvgFilter = "T"
End Select
End With
End If
Dim result() As DataRow = dtTools.Select(filter)
For i As Integer = 0 To result.Count - 1
result(i)("dgvFilter") = dvgFilter
If result(i)("dgvToolStatus") <> OutOfService Then result(i)("dgvToolStatus") = ReturnTransit
Next
I was, of course, trying to make this way too difficult. Simple solution along these lines.
Public Class Crepair
Public repairID As Integer
Public techID As Integer
Public repairCodeID As Integer
Public acceptedDate As Date
Public remarks As String
Public isComplete As Boolean
End Class
With nRepair
.repairID = row.Cells("RepairID").Value
.techID = row.Cells("TechID").Value
.repairCodeID = row.Cells("RepairCodeID").Value
.acceptedDate = row.Cells("AcceptedDate").Value
.remarks = row.Cells("Remarks").Value
.isComplete = row.Cells("IsComplete").Value
End With

Data grid view with combo box , add rows from data table

Search and display data in data grid view
Dim cmd As New OracleCommand("Select JV_CODE,JV_ACC_NAME,DEBIT,CREDIT From VOUCHER_DETAIL where VOUCHERNO =:Vno", sgcnn)
cmd.Parameters.Add("#Vno", OracleDbType.NVarchar2).Value = txtJVNo.Text.ToString.Trim
Dim daVD As New OracleDataAdapter(cmd)
Dim dtVD As New DataTable()
daVD.Fill(dtVD)
dgvAccDetail.AutoGenerateColumns = False
dgvAccDetail.DataSource = dtVD
dgvAccDetail.Rows(0).Cells(0).Value = dtVD.Rows(0).Item("JV_CODE").ToString.Trim
dgvAccDetail.Rows(0).Cells(1).Value = dtVD.Rows(0).Item("JV_ACC_NAME").ToString.Trim
dgvAccDetail.Rows(0).Cells(2).Value = dtVD.Rows(0).Item("DEBIT").ToString.Trim
dgvAccDetail.Rows(0).Cells(3).Value = dtVD.Rows(0).Item("CREDIT").ToString.Trim
Catch ex As Exception
MsgBox(ex.Message)
End Try
There are two rows in dtVD data table but result shows only one I stack with this some can tell what I'm doing wrong ?
The reason for this is that you are only assigning the one row. You have a couple options:
First, this code below here shouldn't really be necessary, of you setup the property binding on the grid. You'll get better performance that way if you use a bind. You don't have your GUI code here, but essentially your DataPropertyName field on the columns should be set.
dgvAccDetail.Rows(0).Cells(0).Value = dtVD.Rows(0).Item("JV_CODE").ToString.Trim
dgvAccDetail.Rows(0).Cells(1).Value = dtVD.Rows(0).Item("JV_ACC_NAME").ToString.Trim
dgvAccDetail.Rows(0).Cells(2).Value = dtVD.Rows(0).Item("DEBIT").ToString.Trim
dgvAccDetail.Rows(0).Cells(3).Value = dtVD.Rows(0).Item("CREDIT").ToString.Trim
If you insist on manually assigning the cell values, you cannot just do row 0 (that's the first row). You need to do all the rows in a loop.
For i as Integer = 0 to dtVD.Rows.Count - 1
dgvAccDetail.Rows(i).Cells(0).Value = dtVD.Rows(i).Item("JV_CODE").ToString.Trim
dgvAccDetail.Rows(i).Cells(1).Value = dtVD.Rows(i).Item("JV_ACC_NAME").ToString.Trim
dgvAccDetail.Rows(i).Cells(2).Value = dtVD.Rows(i).Item("DEBIT").ToString.Trim
dgvAccDetail.Rows(i).Cells(3).Value = dtVD.Rows(i).Item("CREDIT").ToString.Trim
Next

How can you insert invoice lines into Sage 50 automatically?

I'm trying to find a way to automate data entry into the raise invoice screen in Sage 50.
All of our order data is held in a different system and we could easily pull together the line items, customer data, etc. automatically but our accounts team currently have to manually select each row, enter the SKU and quantity which is very time consuming.
It appears that the clipboard isn't functional in the Product Code field either - which is really annoying!
Are there any reasonable ways to inject data like this into Sage 50?
as far as i know there is a Excel2Sage Tool or App which can handle mass-importing. i did not used the commercial software last year, but the year before.
i'm actual not know about a free solution for this without developing it.
As alternative you could use AutoIt or something.
best
Eric
Here is an example using VB.Net:
'Declare objects
Dim oSDO As SageDataObject230.SDOEngine
Dim oWS As SageDataObject230.WorkSpace
Dim oSOPRecord As SageDataObject230.SopRecord
Dim oSOPItem_Read As SageDataObject230.SopItem
Dim oSOPItem_Write As SageDataObject230.SopItem
Dim oSOPPost As SageDataObject230.SopPost
Dim oStockRecord As SageDataObject230.StockRecord
'Declare Variables
Dim szDataPath As String
'Create SDO Engine Object
oSDO = New SageDataObject230.SDOEngine
' Select company. The SelectCompany method takes the program install
' folder as a parameter
szDataPath = oSDO.SelectCompany("C:\Documents and Settings\All Users\Application Data\Sage\Accounts\2017\")
'Create Workspace
oWS = oSDO.Workspaces.Add("Example")
'Try to connect
If oWS.Connect(szDataPath, "manager", "", "Example") Then
'Create objects
oSOPRecord = oWS.CreateObject("SOPRecord")
oSOPPost = oWS.CreateObject("SOPPost")
oSOPItem_Read = oWS.CreateObject("SOPItem")
oStockRecord = oWS.CreateObject("StockRecord")
'Read an existing Sales Order
oSOPRecord.MoveLast()
'Populate the order header, copying fields from oSOPRecord to oSOPPost
oSOPPost.Header("INVOICE_NUMBER").Value = oSOPRecord.Fields.Item("INVOICE_NUMBER").Value
oSOPPost.Header("ACCOUNT_REF").Value = CStr(oSOPRecord.Fields.Item("ACCOUNT_REF").Value)
oSOPPost.Header("NAME").Value = CStr(oSOPRecord.Fields.Item("NAME").Value)
oSOPPost.Header("ADDRESS_1").Value = CStr(oSOPRecord.Fields.Item("ADDRESS_1").Value)
oSOPPost.Header("ADDRESS_2").Value = CStr(oSOPRecord.Fields.Item("ADDRESS_2").Value)
oSOPPost.Header("ADDRESS_3").Value = CStr(oSOPRecord.Fields.Item("ADDRESS_3").Value)
oSOPPost.Header("ADDRESS_4").Value = CStr(oSOPRecord.Fields.Item("ADDRESS_4").Value)
oSOPPost.Header("ADDRESS_5").Value = CStr(oSOPRecord.Fields.Item("ADDRESS_5").Value)
oSOPPost.Header("DEL_ADDRESS_1").Value = CStr(oSOPRecord.Fields.Item("DEL_ADDRESS_1").Value)
oSOPPost.Header("DEL_ADDRESS_2").Value = CStr(oSOPRecord.Fields.Item("DEL_ADDRESS_2").Value)
oSOPPost.Header("DEL_ADDRESS_3").Value = CStr(oSOPRecord.Fields.Item("DEL_ADDRESS_3").Value)
oSOPPost.Header("DEL_ADDRESS_4").Value = CStr(oSOPRecord.Fields.Item("DEL_ADDRESS_4").Value)
oSOPPost.Header("DEL_ADDRESS_5").Value = CStr(oSOPRecord.Fields.Item("DEL_ADDRESS_5").Value)
oSOPPost.Header("CUST_TEL_NUMBER").Value = CStr(oSOPRecord.Fields.Item("CUST_TEL_NUMBER").Value)
oSOPPost.Header("CONTACT_NAME").Value = CStr(oSOPRecord.Fields.Item("CONTACT_NAME").Value)
oSOPPost.Header("GLOBAL_TAX_CODE").Value = CShort(oSOPRecord.Fields.Item("GLOBAL_TAX_CODE").Value)
oSOPPost.Header("ORDER_DATE").Value = CDate(oSOPRecord.Fields.Item("ORDER_DATE").Value)
oSOPPost.Header("NOTES_1").Value = CStr(oSOPRecord.Fields.Item("NOTES_1").Value)
oSOPPost.Header("NOTES_2").Value = CStr(oSOPRecord.Fields.Item("NOTES_1").Value)
oSOPPost.Header("NOTES_3").Value = CStr(oSOPRecord.Fields.Item("NOTES_3").Value)
oSOPPost.Header("TAKEN_BY").Value = CStr(oSOPRecord.Fields.Item("TAKEN_BY").Value)
oSOPPost.Header("ORDER_NUMBER").Value = CStr(oSOPRecord.Fields.Item("ORDER_NUMBER").Value)
oSOPPost.Header("CUST_ORDER_NUMBER").Value = CStr(oSOPRecord.Fields.Item("CUST_ORDER_NUMBER").Value)
oSOPPost.Header("PAYMENT_REF").Value = CStr(oSOPRecord.Fields.Item("PAYMENT_REF").Value)
oSOPPost.Header("GLOBAL_NOM_CODE").Value = CStr(oSOPRecord.Fields.Item("GLOBAL_NOM_CODE").Value)
oSOPPost.Header("GLOBAL_DETAILS").Value = CStr(oSOPRecord.Fields.Item("GLOBAL_DETAILS").Value)
oSOPPost.Header("ORDER_TYPE").Value = oSOPRecord.Fields.Item("ORDER_TYPE").Value
oSOPPost.Header("FOREIGN_RATE").Value = CDbl(oSOPRecord.Fields.Item("FOREIGN_RATE").Value)
oSOPPost.Header("CURRENCY").Value = oSOPRecord.Fields.Item("CURRENCY").Value
oSOPPost.Header("CURRENCY_USED").Value = oSOPRecord.Fields.Item("CURRENCY_USED").Value
' Link header to items
oSOPItem_Read = oSOPRecord.Link
'Find the First Record
oSOPItem_Read.MoveFirst()
Do
'Add the existing items to the order
oSOPItem_Write = oSOPPost.Items.Add
'Populate the Fields, copying the data from the existing records
oSOPItem_Write.Fields.Item("STOCK_CODE").Value = CStr(oSOPItem_Read.Fields.Item("STOCK_CODE").Value)
oSOPItem_Write.Fields.Item("DESCRIPTION").Value = CStr(oSOPItem_Read.Fields.Item("DESCRIPTION").Value)
oSOPItem_Write.Fields.Item("NOMINAL_CODE").Value = CStr(oSOPItem_Read.Fields.Item("NOMINAL_CODE").Value)
oSOPItem_Write.Fields.Item("TAX_CODE").Value = CShort(oSOPItem_Read.Fields.Item("TAX_CODE").Value)
oSOPItem_Write.Fields.Item("QTY_ORDER").Value = CDbl(oSOPItem_Read.Fields.Item("QTY_ORDER").Value)
oSOPItem_Write.Fields.Item("UNIT_PRICE").Value = CDbl(oSOPItem_Read.Fields.Item("UNIT_PRICE").Value)
oSOPItem_Write.Fields.Item("NET_AMOUNT").Value = CDbl(oSOPItem_Read.Fields.Item("NET_AMOUNT").Value)
oSOPItem_Write.Fields.Item("TAX_AMOUNT").Value = CDbl(oSOPItem_Read.Fields.Item("TAX_AMOUNT").Value)
oSOPItem_Write.Fields.Item("COMMENT_1").Value = CStr(oSOPItem_Read.Fields.Item("COMMENT_1").Value)
oSOPItem_Write.Fields.Item("COMMENT_2").Value = CStr(oSOPItem_Read.Fields.Item("COMMENT_2").Value)
oSOPItem_Write.Fields.Item("UNIT_OF_SALE").Value = CStr(oSOPItem_Read.Fields.Item("UNIT_OF_SALE").Value)
oSOPItem_Write.Fields.Item("FULL_NET_AMOUNT").Value = CDbl(oSOPItem_Read.Fields.Item("FULL_NET_AMOUNT").Value)
oSOPItem_Write.Fields.Item("TAX_RATE").Value = CDbl(oSOPItem_Read.Fields.Item("TAX_RATE").Value)
'We now need to ensure that the TAX_FLAG is set the same as the item being read otherwise it will be re calculated
oSOPItem_Write.Fields.Item("TAX_FLAG").Value = CInt(oSOPItem_Read.Fields.Item("TAX_FLAG").Value)
'Loop until there are no more existing items
Loop Until oSOPItem_Read.MoveNext = False
'destroy the oSOPItem_Write object
oSOPItem_Write = Nothing
'write a new item
oStockRecord.MoveLast()
oSOPItem_Write = oSOPPost.Items.Add
' Populate other fields required for Invoice Item
' From 2015 the update method now wraps internal business logic
' that calculates the vat amount if a net amount is given.
' If you wish to calculate your own Tax values you will need
' to ensure that you set the TAX_FLAG to 1 and set the TAX_AMOUNT value on the item line
' ***Note if a NVD is set the item line values will be recalculated
' regardless of the Tax_Flag being set to 1***
oSOPItem_Write.Fields.Item("STOCK_CODE").Value = oStockRecord.Fields.Item("STOCK_CODE").Value
oSOPItem_Write.Fields.Item("DESCRIPTION").Value = CStr(oStockRecord.Fields.Item("DESCRIPTION").Value)
oSOPItem_Write.Fields.Item("NOMINAL_CODE").Value = CStr(oStockRecord.Fields.Item("NOMINAL_CODE").Value)
oSOPItem_Write.Fields.Item("TAX_CODE").Value = CShort(oStockRecord.Fields.Item("TAX_CODE").Value)
oSOPItem_Write.Fields.Item("QTY_ORDER").Value = CDbl(2)
oSOPItem_Write.Fields.Item("UNIT_PRICE").Value = CDbl(50)
oSOPItem_Write.Fields.Item("NET_AMOUNT").Value = CDbl(100)
oSOPItem_Write.Fields.Item("FULL_NET_AMOUNT").Value = CDbl(100)
oSOPItem_Write.Fields.Item("COMMENT_1").Value = CStr("")
oSOPItem_Write.Fields.Item("COMMENT_2").Value = CStr("")
oSOPItem_Write.Fields.Item("UNIT_OF_SALE").Value = CStr("")
oSOPItem_Write.Fields.Item("TAX_RATE").Value = CDbl(20)
'Destroy the oSOPItem_Write object
oSOPItem_Write = Nothing
'Post the order
If oSOPPost.Update() Then
MsgBox("Order Updated Successfully")
Else
MsgBox("Order Update Failed")
End If
'Disconnect and destroy the objects
oWS.Disconnect()
oSDO = Nothing
oWS = Nothing
oSOPRecord = Nothing
oSOPItem_Read = Nothing
oSOPItem_Write = Nothing
oSOPPost = Nothing
oStockRecord = Nothing
End If
Exit Sub
All of the current commercial products will require you to put your data into a specific format (column order and file type) anyway, so if you can do that, then bring everything into Excel, and then adapt the code listed above for VB.Net into VBA. It's fairly straightforward, mainly passing data to an array and then looping through.
If you want specific assistance, show us the structure of your Order data, and then we can do something
Cheers
Paul

Variable that depends on another variable VBA

I have an interesting question about referencing another variable based on another variable in an array.
Below is my code:
Dim company, price, sdev, mean, random
Dim companies
companies = Array("mm", "tgt", "boog")
mm_price = 0
mm_mean = 0
mm_sdev = 0
tgt_price = 0
tgt_mean = 0
tgt_sdev = 0
boog_price = 0
boog_mean = 0
boog_sdev = 0
For i = 1 To 3
company = companies(i)
mean = company & "_mean"
sdev = company & "_sdev"
Next i
Now, the issue occurs when I attempt to define the "mean" and "sdev" variables, as they will not use the "0" value, but instead give it the string name "mm_mean" etc. mm_mean = 0, therefore, I want mean = 0 when i = 1. Clear?
Thanks, and let me know. It is a rather strange question, and the code is cut from many different functions, so if it doesn't make sense as to why I am doing this, my apologies. I tried to make it as simple as possible so it wouldn't confuse the answerer.
This is a good example of when custom data-structures (aka "record types", "structs") should be used to group related data together. In VBA the syntax is Type:
Type Company
Name As String
Price As Currency
Mean As Double
SDev As Double
End Type
Public Sub CalculateCompanyInfo()
Dim companies(3) As Company
companies(0).Name = "mm"
companies(0).Price = 123
companies(1).Name = "tgt"
companies(1).Price = 456
companies(2).Name = "boog"
companies(2).Price = 789
For i As Integer = 0 to UBound(companies)
companies(i).Mean = ...
companies(i).SDev = ...
Next i
End Sub
Where ... means whatever custom calculation you need to do to get that value.

Base data sheet form will not display calculated Field

I have a Data Sheet form which has a calculated field column. However the field will not display even though it has the correct value. The field in question is "numRisk":
Sub Calculate_Risk (Form As Object)
Dim OrderPrice, IfDonePrice, TotBrSymComm, BrComm, Risk As Double
Dim Symbol As String
Dim IntRateMult, noContracts As Integer
If MinTick = 0 OR Rate = 0 Then
Exit Sub
End If
Symbol = RTrim(Form.getByName("txtSymbol").CurrentValue)
If Symbol = "" Then
Exit Sub
End If
OrderPrice = Form.getByName("fmtOrder_Price").CurrentValue
IfDonePrice = Form.getByName("fmtIf_Done_Price").CurrentValue
noContracts = Form.getByName("fmtNo_Contracts").CurrentValue
If NOT USIntRates Then
Risk = ABS(OrderPrice - IfDonePrice) / MinTick
Else
Risk = ABS(OrderPrice\1 - IfDonePrice\1) * MinTick
IntRateMult = IIf(Symbol = "FV" OR Symbol = "TU",400, 200)
Risk = ABS(Risk - IntRateMult * ABS(OrderPrice - OrderPrice\1
IfDonePrice + IfDonePrice\1))
End If
Risk = Risk * MinTickVal / Rate
TotBrSymComm = BrSymComm + BrSymCommAud
BrComm = IIf(TotBrSymComm = 0, BrCommission, BrSymCommAud + BrSymComm/Rate)
Risk = noContracts*(Risk + BrComm * 2)
Form.getByName("numRisk").Value = Risk
End Sub
The subroutine is called from the following routine which is triggered when the form is loaded:
Sub FromListForm(Event as Object)
Dim Form As Object
Dim TodaysDate As New com.sun.star.util.Date
Dim CurrDate As Date
Form=Event.Source.getByName("MainForm_Grid")
Form.RowSet.first()
Do Until Form.RowSet.isAfterLast()
Get_Contract(Form)
Get_Broker_Comm(Form)
Calculate_Risk(Form)
If isEmpty(Form.getByName("OrderDate").Date) Then
CurrDate = Date()
TodaysDate.Day = Day(CurrDate)
TodaysDate.Month = Month(CurrDate)
TodaysDate.Year = Year(CurrDate)
Form.getByName("OrderDate").CurrentValue = TodaysDate
End If
Form.RowSet.next()
Loop
Form.RowSet.last()
End Sub
Also is there a more efficient method to cycle through the rows? As this seems so slow I can see the row pointer moving down the table as each row is processed.
If I understand correctly, you're trying to enter individual values into each cell in a column of a tablegrid control? I don't believe that's possible.
Inside a tablegrid control, all values have to come from the underlying query. I recommend writing a query to do these calculations, and using that query as the basis for the form - that would solve both the problem of displaying the calculated result as well as improving the load speed of the form (since database logic in determining query results is almost always more efficient than a macro going row-by-row).
Alternately, you could have the calculated field be standalone, showing only the calculated result for the currently selected row of the tablegrid control. In this scenario, the "form loaded" event would only do the calculation for the first row, and the calculating macro would be triggered each time the row selection changed.