Format Datagridview question

bones

Well-known member
Joined
Aug 23, 2014
Messages
143
Programming Experience
Beginner
I use this code elsewhere and it works fine.... Difference is the situation I'm working with here is the DGV is populated by an in memory datatable.

VB.NET:
'format DGV1 formulated colums for proper number type
        DataGridView1.DataSource = SourceTable


        'format datagridview1 columns
        Me.DataGridView1.Columns.Item(4).DefaultCellStyle.Format = "n1"
        Me.DataGridView1.Columns.Item(5).DefaultCellStyle.Format = "n3"
        Me.DataGridView1.Columns.Item(6).DefaultCellStyle.Format = "n3"
        Me.DataGridView1.Columns.Item(7).DefaultCellStyle.Format = "n3"
        Me.DataGridView1.Columns.Item(8).DefaultCellStyle.Format = "n1"
        Me.DataGridView1.Columns.Item(9).DefaultCellStyle.Format = "n1"

The grid columns don't format. Do I need to format the sourcetable columns instead? Or is it the sourcetable is displaying string values?
 
Or is it the sourcetable is displaying string values?

The source table isn't displaying anything. The source table contains the data and the grid displays it. If the source table does indeed contain Strings then yes, that is the reason that you're not seeing the data formatted as you want. Those are numeric format specifiers so they only work for numeric data. This is just one example of why data should always be the correct type. Strings should never be used for data that is not logically text if it can possibly be avoided.
 
The source table isn't displaying anything. The source table contains the data and the grid displays it. If the source table does indeed contain Strings then yes, that is the reason that you're not seeing the data formatted as you want. Those are numeric format specifiers so they only work for numeric data. This is just one example of why data should always be the correct type. Strings should never be used for data that is not logically text if it can possibly be avoided.

The code I use to create the table may hold the answer. Would you be willing to have a look if I post it?
 
The code I use to create the table may hold the answer. Would you be willing to have a look if I post it?

That doesn't really matter. Post it anyway and, even if I'm not prepared to look at it for some reason, there may well be someone else who is.
 
It occurs to me that the calculated values that I'm controlling the number of decimal places in the DGV, are only masked by the formatting code. Otherwise the data in my datatable would be coming through with the same number of decimal places. That said the solution is to either format the datatable columns or handle the entire affair from the beginning with the proper code to obtain the desired number of decimal places..... the latter seems the logical choice.

So... if someone could explain to me how to handle that in this code I can correct it at the source.... problem would be solved. Do I handle this in the dim statements or is it possible to handle it in the code for "r.cells(5).value = "

VB.NET:
Dim  vdiam = Val(Me.TextBox1.Text) 
Dim factor = vdiam * 3.14 
Dim count = Val(Me.TextBox7.Text) 


        For Each r As DataGridViewRow In Me.DGV1.Rows
            '[B]Cell 5 Desired  number of decimal places is  3 [0.000][/B]
            r.Cells(5).Value = r.Cells(2).Value / ((factor * r.Cells(0).Value) * 146) / count
 
Also notice that default data type for a DataColumn in a DataTable is type String, unless you specify otherwise (in code or in database). Then if you assign a numeric expression to cell in DataGridView for a String column in datasource, then it will be implicitly converted to String also.
 
Well let's explore this a bit for my future reference and understanding then...

Here are 3 subs that made this work. What's not clear to me in the code is if the data in sourcetable is string or integer. I'm leaning toward it being integer based on how I solved the formatting issue with out modifying any of this code. Seems to me the formatting wouldn't have worked if the data in sourcetable [in memory datatable] was string... Or am I wrong about that?

Here's the code I used to format the datagridview who's source is the table created in the second posted block of code.
VB.NET:
Private Sub DataAnalysis_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'format DGV1 formulated colums for proper number type
        Me.DGV1.Columns.Item(0).DefaultCellStyle.Format = "n3" ' Valve Lift
        Me.DGV1.Columns.Item(4).DefaultCellStyle.Format = "n1" ' Valve CFM Per Square Inch
        Me.DGV1.Columns.Item(5).DefaultCellStyle.Format = "n3" ' Valve Coefficient Column
        Me.DGV1.Columns.Item(6).DefaultCellStyle.Format = "n3" ' Effective Flow Area Column
        Me.DGV1.Columns.Item(7).DefaultCellStyle.Format = "n3" ' Actual Flow Area Column
        Me.DGV1.Columns.Item(8).DefaultCellStyle.Format = "n1" ' Calculated Throat Velocity
        Me.DGV1.Columns.Item(9).DefaultCellStyle.Format = "n1" ' Average Port Velocity In Feet Per Second


        'Get the port name information from the currently checked portname button on the main form
        'and display it in label17
        Select Case True
            Case frmMain.RBtnPort1.Checked
                Me.Label17.Text = frmMain.RBtnPort1.Text
            Case frmMain.RBtnPort2.Checked
                Me.Label17.Text = frmMain.RBtnPort2.Text
            Case frmMain.RBtnPort3.Checked
                Me.Label17.Text = frmMain.RBtnPort3.Text
            Case frmMain.RBtnPort4.Checked
                Me.Label17.Text = frmMain.RBtnPort4.Text
            Case frmMain.RBtnPort5.Checked
                Me.Label17.Text = frmMain.RBtnPort5.Text
            Case frmMain.RBtnPort6.Checked
                Me.Label17.Text = frmMain.RBtnPort6.Text


        End Select


        DGV1.Columns(0).ValueType = GetType(Double)
        DGV1.Columns(4).ValueType = GetType(Double)
        DGV1.Columns(5).ValueType = GetType(Double)
        DGV1.Columns(6).ValueType = GetType(Double)
        DGV1.Columns(7).ValueType = GetType(Double)
        DGV1.Columns(8).ValueType = GetType(Double)
        DGV1.Columns(9).ValueType = GetType(Double)
    End Sub


The code that creates sourcetable
VB.NET:
 Public Shared Function IfNullObj(ByVal o As Object, Optional ByVal DefaultValue As String = "") As String
        Dim ret As String = ""
        Try
            If o Is DBNull.Value Then
                ret = DefaultValue
            Else
                ret = o.ToString
            End If
            Return ret
        Catch ex As Exception
            Return ret
        End Try
    End Function
    Public Shared Function DataGridViewToDataTable(ByVal dtg As DataGridView,
        Optional ByVal DataTableName As String = "myDataTable") As DataTable
        Try
            
            Dim dt As New DataTable(DataTableName) 'create the new datatable
            'begin testing code section B to try to add the created table to "andata"
            'dt = analisys.Tables.Add(DataTableName)
            Dim row As DataRow
            Dim TotalDatagridviewColumns As Integer = dtg.ColumnCount - 1
            'Add Datacolumn
            For Each c As DataGridViewColumn In dtg.Columns
                Dim idColumn As DataColumn = New DataColumn()
                idColumn.ColumnName = c.HeaderText
                idColumn.DataType = If(c.ValueType, GetType(String)) ' if type is nothing use String
                dt.Columns.Add(idColumn)
            Next
            'Now Iterate thru Datagrid and create the data row
            For Each dr As DataGridViewRow In dtg.Rows
                If dr.Index = dtg.NewRowIndex Then Continue For
                'Iterate thru datagrid
                row = dt.NewRow 'Create new row
                'Iterate thru Column 1 up to the total number of columns
                For cn As Integer = 0 To TotalDatagridviewColumns
                    If dr.Cells(cn).Value Is Nothing OrElse IsDBNull(dr.Cells(cn).Value) Then
                        row.Item(cn) = GetDefaultValue(dtg.Columns(cn).ValueType)
                    Else
                        row.Item(cn) = dr.Cells(cn).Value
                    End If
                Next
                'Now add the row to Datarow Collection
                dt.Rows.Add(row)
            Next
            'Now return the data table
            Return dt
        Catch ex As Exception
            Return Nothing
        End Try
    End Function


    Public Shared Function GetDefaultValue(ByVal type As Type) As Object
        Return If(type.IsValueType, System.Activator.CreateInstance(type), Nothing)
    End Function
 
Last edited:
What is the flow here? You say your DGV table is generated from data in DGV? (chicken-egg)

Anyway I would advise again such approach. It's kind of backwards to create a DataTable from data in DGV. Create the DataTable first, then bind it to DGV. Add data to source table, instead of control.

You can add an untyped DataSet from Toolbox to form in designer, and there configure its table(s) and columns, then bind it directly to DGV in designer (or better yet, via a BindingSource also configured in designer). DGV column formatting can also be configured in designer. None of this requires coding, nor a backend database when that is not intended.
 
What is the flow here? You say your DGV table is generated from data in DGV? (chicken-egg)

Anyway I would advise again such approach. It's kind of backwards to create a DataTable from data in DGV. Create the DataTable first, then bind it to DGV. Add data to source table, instead of control.

You can add an untyped DataSet from Toolbox to form in designer, and there configure its table(s) and columns, then bind it directly to DGV in designer (or better yet, via a BindingSource also configured in designer). DGV column formatting can also be configured in designer. None of this requires coding, nor a backend database when that is not intended.

Yes, I realize it seems backward but there's a reason for things being done this way.

Data from an externally connected device is being captured with the application. That data is combined with user entered data in the application, formulas are applied for analysis purposes & some initial charting is performed. There are times when it's desirable to save that data and times when it's not. Regardless two conditions always exist.

1] The initially captured data is always desired.
2] Beyond the initial captured data and the formulas applied to it, there on the Main Form, it needs to be available for analysis, further charting and if desired, archived to a permanent table that will be in an Access back end db that already exists and is used for other purposes in the app.

The data on the mainform is captured to a DGV. If analysis is desired the user sends each round of captured data to a DGV on the Data Analysis form. That DGV applies formulas for the analysis process & creates a temporary table via the code I posted. And...NO all the analysis cannot be done in the Main Forms DGV...

So on the Analysis form, the user can view the analyzed data and also open an advanced charting form for the visual references everyone is so fond of. Think of this as a temporary work area with the potential to archive the data if desired.

At this point it's possible that the user may want to archive the test data. Hence "Sourcetable" is available to handle that process. If they do not desire to archive... no big deal...the table is emptied either manually or by exiting the application..

Regardless... it is functioning exactly as I want it to and that is not the question at hand. The question I asked was about the state of the date in the code created temporary table being string or integer data. I would say it must be integer because my formatting method worked. What I do not know / see / understand is if there are specific statements in the code that creates the temporary datatable that specify the data type... I don't see anything that refers to that. Then again... I am very new to VB and without question I do not understand every single line of code that's in this, my first VB application.... The desire is to understand, learn, comprehend.

From the good graces of the seasoned programmers on this forum, I hope to grasp more with each answered question...just that simple :tears_of_joy:
 
Last edited:
None of that prevent you from using a DataTable as starting point, and get rid of redundant code. DataGridView and other controls exist to display data to user and allow user to input/edit data. It is a common mistake by new developers to think of controls as the means to hold and manage data, and that leads to all kinds of problems when they need to pass data around in application or have the data processed by other threads. Raw data has no dependency on user interface controls.
What I do not know / see / understand is if there are specific statements in the code that creates the temporary datatable that specify the data type...
DataColumn.DataType is set:
idColumn.DataType = If(c.ValueType, GetType(String)) ' if type is nothing use String
 
None of that prevent you from using a DataTable as starting point, and get rid of redundant code. DataGridView and other controls exist to display data to user and allow user to input/edit data. It is a common mistake by new developers to think of controls as the means to hold and manage data, and that leads to all kinds of problems when they need to pass data around in application or have the data processed by other threads. Raw data has no dependency on user interface controls.

DataColumn.DataType is set:

Hmmm... I wasn't sure how to proceed with creating a datatable with the formulas I needed. The initial data that gets captured to the DGV on the mainform gets a bunch of formulas applied to it in the DGV on the second form. That I was able to figure out. I had no idea how to do that in a data table.

But that's all rather irrelevant at this point because the datatable is created and the next step from there is the archiving of the data. I see no need to redo all the work again only to arrive at the exact same place with the exact same datatable.... However, in future I will take the other route.. Thanks for the assistance.
 
Back
Top