setting datagrid columns' width dynamically

thundergod989

Member
Joined
Jan 2, 2006
Messages
6
Programming Experience
1-3
Ok here's the situation:

datatable is created dynamically, it is set to a datagrid later in the code, when the datagrid shows the data, all the columns have the same width. I've played around with datagridtablestyle and columnstyles and such and haven't found anything that works. Anybody have any suggestions?
 
I think what he wants is to autosize the column width. The following code is working and can be used. I found it in one of these forums.

Public Sub AutoSizeDataGridColumns(ByVal dgData As DataGrid, ByVal strMappingName As String, ByVal intPadding As Integer)
Dim ex1 As New Exception("DataGrid must be databound")
Dim ex2 As New Exception("DataSource must be DataSet or DataTable")
Dim ex3 As New Exception("Invalid tablename in the DataSet")
Dim dt As DataTable
Dim dr As DataRow
Dim dset As New DataSet
Dim dcCol As DataColumn
Dim gr As Graphics
Dim sngGridNameWidth, sngDataWidth As Single
Dim i As Integer, sngPadding As Single
Dim ts As New DataGridTableStyle ' Create a new table style
ts.MappingName = strMappingName ' Address the TableGrid Style
If dgData.TableStyles.Contains(ts.MappingName) = False Then dgData.TableStyles.Add(ts) ' Attach the new style if the table does not have this style
If dgData.DataSource Is Nothing Then
Throw ex1
Exit Sub
End If
If TypeOf dgData.DataSource Is DataSet Then
dset = dgData.DataSource
dt = dset.Tables(dgData.DataMember)
ElseIf TypeOf dgData.DataSource Is DataTable Then
dt = dgData.DataSource
Else
Throw ex2
Exit Sub
End If
If dt.Rows.Count > 0 Then ' Don't change size if there are no rows.
Try
dgData.BeginInit()
dr = dt.Rows(0)
Dim sz As SizeF 'Stores an ordered pair of floating-point numbers, typically the width and height of a rectangle.
gr = dgData.CreateGraphics
sz = gr.MeasureString(
New String("M", intPadding), dgData.Font) ' Pad "n" M-width characters
sngPadding = sz.Width
For Each dcCol In dt.Columns ' Loop through the column header
' Measure the "width" of the text in each grid column header
Try
sz = gr.MeasureString(dgData.TableStyles(ts.MappingName).GridColumnStyles(dcCol.Ordinal).HeaderText, dgData.Font)
dgData.TableStyles(ts.MappingName).GridColumnStyles(dcCol.Ordinal).Width = sz.Width + sngPadding
Catch ex As ArgumentOutOfRangeException
Throw ex3
End Try
Next ' dcCol loop through each column in the bound DataTable
For i = 0 To dgData.VisibleRowCount - 2 ' Calculate width on all visible rows (header row counted)
For Each dcCol In dt.Columns ' Loop through each column
dr = dt.Rows(i) ' Navigate to visible rows
' Measure the "width" of the txt in the first row of each bound DataTable column
sz = gr.MeasureString(dr(dcCol.Ordinal).ToString, dgData.Font) ' Measure "width" of data value
dgData.TableStyles(0).GridColumnStyles(dcCol.Ordinal).Width = _
Math.Max(sz.Width + sngPadding, _
dgData.TableStyles(0).GridColumnStyles(dcCol.Ordinal).Width)
' Use larger width
Next ' Next DataGrid Column
Next i ' Next DataRow
Catch ex As Exception
MsgBox(ex.ToString)
Finally
dgData.EndInit() ' complete graphics edit
gr.Dispose() ' Release graphic object
End Try
End If ' Test for DataTable Rows
End Sub

Varadarajan R

 
Thanks

well its for an invoice to display items on it, so I need to define fixed column widths every time and do not need to automatically resize every time something is added, ex: sku is 8 characters, so no need for it to be larger, but i also want larger columns such as the short description to be a fixed width so if the description is longer, it will simply not display the rest of it until the mouse is hovered over. Eitehr way, i think the first method should work, i'll give it a shot eitehr way. I'll let you guys know what i did and what worked ( or didnt' work *knock on wood* )
 
i keep getting "Invalid tablename in the DataSet" error when i run the resize sub with this command:

VB.NET:
'dim column
        Dim ugs As DataColumn = New DataColumn("ugs")
        Dim sku As DataColumn = New DataColumn("sku")
        Dim brand As DataColumn = New DataColumn("brand")
        Dim shortdesc As DataColumn = New DataColumn("description")
        Dim qty As DataColumn = New DataColumn("qty")
        Dim price As DataColumn = New DataColumn("price")
        Dim total As DataColumn = New DataColumn("total")
        Dim type As DataColumn = New DataColumn("type")

        'define column
        ugs.DataType = System.Type.GetType("System.String")
        sku.DataType = System.Type.GetType("System.String")
        brand.DataType = System.Type.GetType("System.String")
        shortdesc.DataType = System.Type.GetType("System.String")
        price.DataType = System.Type.GetType("System.Double")
        qty.DataType = System.Type.GetType("System.Int32")
        total.DataType = System.Type.GetType("System.Double")
        type.DataType = System.Type.GetType("System.String")

        'adding the column to table
        With invoicetable.Columns
            .Add(ugs)
            .Add(sku)
            .Add(brand)
            .Add(shortdesc)
            .Add(type)
            .Add(qty)
            .Add(price)
            .Add(total)
        End With

        Dim temprow As DataRow

        temprow = invoicetable.NewRow

        temprow.Item("ugs") = "002993939"
        temprow.Item("sku") = "tcr01010"
        temprow.Item("brand") = "infinity"
        temprow.Item("type") = "SA"
        temprow.Item("description") = "kappa 4.1"
        temprow.Item("qty") = 4
        temprow.Item("price") = 45.99
        temprow.Item("total") = 183.96

        invoicetable.Rows.Add(temprow)

        ds.Tables.Add(invoicetable)

        dgInvoice.DataSource = ds

        dgInvoice.DataMember = "invoicetable"

        AutoSizeDataGridColumns(dgInvoice, "trialname", 3)

so anyways, i tried to manually create a tablestyle and add it to the grid with this:
VB.NET:
    Dim tsProducts As New DataGridTableStyle
    tsProducts.MappingName = "Products"

    Dim cstbProdName As New DataGridTextBoxColumn
    cstbProdName.MappingName = "ProductName"
    cstbProdName.HeaderText = "Product Name"

    tsProducts.GridColumnStyles.Add(cstbProdName)
    Dginvoice.TableStyles.Add(tsProducts)
which does nothing, all the column headers report the same name that they have in the table...

maybe i'm missing something with the custom datagrid styles, can somebody help me out a bit?


edit: tried this too, to no avail:

VB.NET:
        ds.Tables.Add(invoicetable)

        ' Create a Grid Table Style. Map it to the table.

        Dim aGridTableStyle As New DataGridTableStyle
        aGridTableStyle.MappingName = "invoicetable"

        ' Create GridColumnStyle objects for the grid columns 

        Dim aCol1 As New DataGridTextBoxColumn
        Dim aCol2 As New DataGridTextBoxColumn
        Dim aCol3 As New DataGridTextBoxColumn
        Dim aCol4 As New DataGridTextBoxColumn
        Dim aCol5 As New DataGridTextBoxColumn
        Dim aCol6 As New DataGridTextBoxColumn
        Dim aCol7 As New DataGridTextBoxColumn
        Dim aCol8 As New DataGridTextBoxColumn

        ' configure columns

        With aCol1
            .MappingName = "ugs"
            .HeaderText = "UGS"
            .Width = 85
            .TextBox.Enabled = False
            .Alignment = HorizontalAlignment.Left
        End With

        With aCol2
            .MappingName = "sku"
            .HeaderText = "SKU"
            .Width = 60
            .Alignment = HorizontalAlignment.Left
            .TextBox.Enabled = False
        End With

        With aCol3
            .MappingName = "brand"
            .HeaderText = "Brand"
            .Width = 70
            .Alignment = HorizontalAlignment.Left
            .TextBox.Enabled = False
        End With

        With aCol4
            .MappingName = "description"
            .HeaderText = "Desc."
            .Width = 120
            .Alignment = HorizontalAlignment.Left
            .TextBox.Enabled = False
        End With

        With aCol5
            .MappingName = "qty"
            .HeaderText = "QTY"
            .Width = 25
            .Alignment = HorizontalAlignment.Left
            .TextBox.Enabled = True
            .Format = "#"
        End With

        With aCol6
            .MappingName = "price"
            .HeaderText = "Price"
            .Width = 80
            .Alignment = HorizontalAlignment.Left
            .TextBox.Enabled = True
            .Format = "c"
        End With

        With aCol7
            .MappingName = "total"
            .HeaderText = "Item Total"
            .Width = 80
            .Alignment = HorizontalAlignment.Left
            .TextBox.Enabled = False
            .Format = "c"
        End With

        With aCol8
            .MappingName = "type"
            .HeaderText = "Type"
            .Width = 50
            .Alignment = HorizontalAlignment.Left
            .TextBox.Enabled = True
        End With

        ' Add the GridColumnStyles to the DataGrid's Column Styles collection.
        ' If invisible columns exist, add to end

        With aGridTableStyle.GridColumnStyles
            .Add(aCol1)
            .Add(aCol2)
            .Add(aCol3)
            .Add(aCol4)
            .Add(aCol5)
            .Add(aCol6)
            .Add(aCol7)
            .Add(aCol8)
        End With

        ' Add the GridColumnStyles to the aGridTableStyle.

        dgInvoice.TableStyles.Clear()

        dgInvoice.TableStyles.Add(aGridTableStyle)

        ' Bind the DataGrid to the DataSet.

        If ds.Tables(0).Rows.Count > 0 Then
            With dgInvoice
                .DataSource = ds.Tables(0)
            End With
        End If

here's what i get, no matter what i try:
dgscreen.jpg
 
Last edited:
First addressing the problem regarding invalid table name in dataset.Since I am using this function quite successfully I tested the code and found that you have to do the following:While defining the datatable, give it a name. For your example I gave it asDim InvoiceTable as New DataTable("InvoiceTable")While giving the datamember for the grid give it as follows :DataGrid1.DataMember = ds.Tables(0).ToString ( Please put your dg name )With this there was no problem, the grid columns are autosizing also.No other change is required in your codeAs regards your second approach, I could not find any apparent fault. However I will test and let you know why it does not workHope this helps.Varadarajan R
 
i changed the invoicetable dim so it gives it a table name, however when i put the dginvoice.datamember = ds.tables(0).tostring(dginvoice) i get an error:

Invoice.vb(1452): 'Public Overrides Function ToString() As String' has no parameters and its return type cannot be indexed.


edit: nvm got it to work using only datamember = "invoicetable"

however, this only arranges the header width depending on header text, i need something that will resize depending on the values in the table ;0 it appears that the code has this feature, but it doesn't appear to work properly, it only uses the header text for measuring.

edit: figured out why, it assumes you ahve a header, which i don't, so it was just skipping the measure row values part, I had to change the

VB.NET:
For i = 0 To dgData.VisibleRowCount - 2 ' Calculate width on all visible rows (header row counted)
to

VB.NET:
For i = 0 To dgData.VisibleRowCount - 1 ' Calculate width on all visible rows (header row counted)

but now i get an index error "index was out of range. Must be non-negative and less than the size of the collection" ;0 i walked through the loops with the quickwatch and all the indexes seemed fine ;0


this is exactly the sub that i have (the copy you posted didn't work too well i had to respace everything):

VB.NET:
Public Sub AutoSizeDataGridColumns(ByVal dgData As DataGrid, ByVal strMappingName As String, ByVal intPadding As Integer)
        Dim ex1 As New Exception("DataGrid must be databound")
        Dim ex2 As New Exception("DataSource must be DataSet or DataTable")
        Dim ex3 As New Exception("Invalid tablename in the DataSet")
        Dim dt As DataTable
        Dim dr As DataRow
        Dim dset As New DataSet
        Dim dcCol As DataColumn
        Dim gr As Graphics
        Dim sngGridNameWidth, sngDataWidth As Single
        Dim i As Integer, sngPadding As Single
        Dim ts As New DataGridTableStyle ' Create a new table style
        ts.MappingName = strMappingName ' Address the TableGrid Style
        If dgData.TableStyles.Contains(ts.MappingName) = False Then dgData.TableStyles.Add(ts) ' Attach the new style if the table does not have this style
        If dgData.DataSource Is Nothing Then
            Throw ex1
            Exit Sub
        End If
        If TypeOf dgData.DataSource Is DataSet Then
            dset = dgData.DataSource
            dt = dset.Tables(dgData.DataMember)
        ElseIf TypeOf dgData.DataSource Is DataTable Then
            dt = dgData.DataSource
        Else
            Throw ex2
            Exit Sub
        End If
        If dt.Rows.Count > 0 Then ' Don't change size if there are no rows.
            Try
                dgData.BeginInit()
                dr = dt.Rows(0)
                Dim sz As SizeF 'Stores an ordered pair of floating-point numbers, typically the width and height of a rectangle.
                gr = dgData.CreateGraphics
                sz = gr.MeasureString(New String("M", intPadding), dgData.Font) ' Pad "n" M-width characters
                sngPadding = sz.Width
                For Each dcCol In dt.Columns ' Loop through the column header
                    ' Measure the "width" of the text in each grid column header
                    Try
                        sz = gr.MeasureString(dgData.TableStyles(ts.MappingName).GridColumnStyles(dcCol.Ordinal).HeaderText, dgData.Font)
                        dgData.TableStyles(ts.MappingName).GridColumnStyles(dcCol.Ordinal).Width = sz.Width + sngPadding
                    Catch ex As ArgumentOutOfRangeException
                        Throw ex3
                    End Try
                Next ' dcCol loop through each column in the bound DataTable
                For i = 0 To dgData.VisibleRowCount - 2 ' Calculate width on all visible rows (header row counted)
                    For Each dcCol In dt.Columns ' Loop through each column
                        dr = dt.Rows(i) ' Navigate to visible rows
                        ' Measure the "width" of the txt in the first row of each bound DataTable column
                        sz = gr.MeasureString(dr(dcCol.Ordinal).ToString, dgData.Font) ' Measure "width" of data value
                        dgData.TableStyles(0).GridColumnStyles(dcCol.Ordinal).Width = _
                        Math.Max(sz.Width + sngPadding, _
                        dgData.TableStyles(0).GridColumnStyles(dcCol.Ordinal).Width) ' Use larger width
                    Next ' Next DataGrid Column
                Next i ' Next DataRow
            Catch ex As Exception
                MsgBox(ex.ToString)
            Finally
                dgData.EndInit() ' complete graphics edit
                gr.Dispose() ' Release graphic object
            End Try
            ts.AllowSorting = False
            ts.ReadOnly = True
        End If ' Test for DataTable Rows
    End Sub
 
Last edited:
I would recommend that we post the solution here without being asked. That is the spirit of a forum. We seek help from the forum. We should also post back to the forum the solution. That way everyone can benefit.Varadarajan R
 
well its kindof half-assed and it doesnt' incorporate padding lol but nonetheless, it works like a charm:

VB.NET:
Public Sub AutoSizeDataGridColumns(ByVal dgData As DataGrid, ByVal strMappingName As String, ByVal intPadding As Integer)
        Dim ex1 As New Exception("DataGrid must be databound")
        Dim ex2 As New Exception("DataSource must be DataSet or DataTable")
        Dim ex3 As New Exception("Invalid tablename in the DataSet")
        Dim dt As DataTable
        Dim dr As DataRow
        Dim dset As New DataSet
        Dim dcCol As DataColumn
        Dim gr As Graphics
        Dim sngGridNameWidth, sngDataWidth As Single
        Dim i As Integer, sngPadding As Single
        Dim ts As New DataGridTableStyle ' Create a new table style
        ts.MappingName = strMappingName ' Address the TableGrid Style
        If dgData.TableStyles.Contains(ts.MappingName) = False Then dgData.TableStyles.Add(ts) ' Attach the new style if the table does not have this style
        If dgData.DataSource Is Nothing Then
            Throw ex1
            Exit Sub
        End If
        If TypeOf dgData.DataSource Is DataSet Then
            dset = dgData.DataSource
            dt = dset.Tables(dgData.DataMember)
        ElseIf TypeOf dgData.DataSource Is DataTable Then
            dt = dgData.DataSource
        Else
            Throw ex2
            Exit Sub
        End If
        If dt.Rows.Count > 0 Then ' Don't change size if there are no rows.
            Try
                dgData.BeginInit()
                dr = dt.Rows(0)
                Dim sz As SizeF 'Stores an ordered pair of floating-point numbers, typically the width and height of a rectangle.
                gr = dgData.CreateGraphics
                sz = gr.MeasureString(New String("M", intPadding), dgData.Font) ' Pad "n" M-width characters
                sngPadding = sz.Width
                'sz = gr.MeasureString(dgData.TableStyles(ts.MappingName).GridColumnStyles(dcCol.Ordinal).HeaderText, dgData.Font)

                dgData.TableStyles(ts.MappingName).GridColumnStyles(0).Width = 122
                dgData.TableStyles(ts.MappingName).GridColumnStyles(1).Width = 83
                dgData.TableStyles(ts.MappingName).GridColumnStyles(2).Width = 70
                dgData.TableStyles(ts.MappingName).GridColumnStyles(3).Width = 145
                dgData.TableStyles(ts.MappingName).GridColumnStyles(4).Width = 62
                dgData.TableStyles(ts.MappingName).GridColumnStyles(5).Width = 55
                dgData.TableStyles(ts.MappingName).GridColumnStyles(6).Width = 67
                dgData.TableStyles(ts.MappingName).GridColumnStyles(7).Width = 77


            Catch ex As Exception
                MsgBox(ex.ToString)
            Finally
                dgData.EndInit() ' complete graphics edit
                gr.Dispose() ' Release graphic object
            End Try
            ts.AllowSorting = False
            ts.ReadOnly = True
        End If ' Test for DataTable Rows
    End Sub
 
Back
Top