2

I'm using a Windows Forms Datagridview to diplay some (long) text. (The code is PowerShell, but the problem is related to the Cell Wrapping mode)

$TestGridView = New-Object System.Windows.Forms.DataGridView -Property @{
    Name="TestDataGridView"
    AllowUserToAddRows = $False
    AllowUserToDeleteRows = $False
    Location = "14,225"
    Size = "1041,328"
    TabIndex = 1
    DefaultCellStyle= @{WrapMode ='True'}
    RowHeadersVisible=$False
    AutoSizeColumnsMode='Fill'
    AutoSizeRowsMode = 'AllCells' 
    Anchor = 'Left, Right, Top, Bottom'
    DefaultCellStyle.Padding =  new-object Windows.Forms.Padding -a 2
}

I'm using Cell Wrapping and AutosizeRowMode, but I have found no way to have a DGV cell display up to a certain point, then truncate by ellipsis when the cell size is exceeded. What I'd want to accomplish is this: (graphic edit)

Desired

but so far, I've been unable to do so:

WrapMode=False,AutoSizeRowsMode=AllCells

truncates by ellipsis, but removes all CRLFs and displays just one line

WrapMode=False,AutoSizeRowsMode=AllCells

WrapMode=False,AutoSizeRowsMode=None

Row height set to desired value, but otherwise truncation same as above

WrapMode=False,AutoSizeRowsMode=None

WrapMode=True,AutoSizeRowsMode=AllCells

No truncation, all the text is displayed and the cell is adapted in height to fit all the text

WrapMode=True,AutoSizeRowsMode=AllCells

WrapMode=True,AutoSizeRowsMode=None

Height stays as it shoulds, but no truncation is performed.

WrapMode=True,AutoSizeRowsMode=None

What I'm trying to accomplish is to have the rows adjust in size up to a maximum, after which text should be truncated by ellipsis [...]

I'have already tried truncating the content, but it has the adverse side effect that when the user COPY the cell content, the cell content is missing all the truncated part (of course) so it is not a viable option..

Many thanks

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
Aldo
  • 303
  • 1
  • 4
  • 14

1 Answers1

1

You need to handle CellPainting event yourself and draw text yourself by applying word-wrapping and ellipsis:

Function dgv_CellPainting{[CmdletBinding()]param( 
    [parameter()] 
    [Object]$sender, 
    [parameter()] 
    [System.Windows.Forms.DataGridViewCellPaintingEventArgs]$e 
) 
    #Don't process if it's not the column which we want or it's a header row
    if (($e.ColumnIndex -ne 0) -or ($e.RowIndex -lt 0)){ return }

    #Paint all parts but text        
    $e.Paint($e.CellBounds, [System.Windows.Forms.DataGridViewPaintParts]::All `
        -band (-bnot([System.Windows.Forms.DataGridViewPaintParts]::ContentForeground)))
    $color = $e.CellStyle.ForeColor
    if ($sender.Rows[$e.RowIndex].Cells[$e.ColumnIndex].Selected -eq $true){
        $color = $e.CellStyle.SelectionForeColor}

    #Paint text
    [System.Windows.Forms.TextRenderer]::DrawText($e.Graphics, $e.FormattedValue, `
        $e.CellStyle.Font, $e.CellBounds, $color, `
                [System.Windows.Forms.TextFormatFlags]::VerticalCenter -bor `
                [System.Windows.Forms.TextFormatFlags]::TextBoxControl -bor `
                [System.Windows.Forms.TextFormatFlags]::WordBreak -bor `
                [System.Windows.Forms.TextFormatFlags]::EndEllipsis)

    #Event handled, stop default processing
    $e.Handled = $true
}

enter image description here

Full Example

Here is a full working PowerShell example. To see the effect, you can try to resize the column or row.

Add-Type -AssemblyName System.Windows.Forms

$form = New-Object System.Windows.Forms.Form
$form.Add_Load({form_Load -sender $form -e $_})

$dgv = New-Object System.Windows.Forms.DataGridView
$dgv.Dock = [System.Windows.Forms.DockStyle]::Fill
$dgv.RowTemplate.Height = 50
$dgv.Add_CellPainting({dgv_CellPainting -sender $dgv -e $_})

$form.Controls.Add($dgv)

Function form_Load {[CmdletBinding()]param( 
    [parameter()] 
    [Object]$sender, 
    [parameter()] 
    [System.EventArgs]$e 
) 
    $dt = New-Object System.Data.DataTable
    $dt.Columns.Add("Column1")
    $dt.Rows.Add("Lorem ipsum dolor sit amet, " + `
        "wisi fierent fabellas pri et, eum aeterno volumus no.")
    $dgv.DataSource = $dt
    #Enable multiline editing
    $dgv.Columns[0].DefaultCellStyle.WrapMode = `
        [System.Windows.Forms.DataGridViewTriState]::True
}

Function dgv_CellPainting{[CmdletBinding()]param( 
    [parameter()] 
    [Object]$sender, 
    [parameter()] 
    [System.Windows.Forms.DataGridViewCellPaintingEventArgs]$e 
) 
    #Don't process if it's not the column which we want or it's a header row
    if (($e.ColumnIndex -ne 0) -or ($e.RowIndex -lt 0)){ return }

    #Paint all parts but text        
    $e.Paint($e.CellBounds, [System.Windows.Forms.DataGridViewPaintParts]::All `
        -band (-bnot([System.Windows.Forms.DataGridViewPaintParts]::ContentForeground)))
    $color = $e.CellStyle.ForeColor
    if ($sender.Rows[$e.RowIndex].Cells[$e.ColumnIndex].Selected -eq $true){
        $color = $e.CellStyle.SelectionForeColor}

    #Paint text
    [System.Windows.Forms.TextRenderer]::DrawText($e.Graphics, $e.FormattedValue, `
        $e.CellStyle.Font, $e.CellBounds, $color, `
                [System.Windows.Forms.TextFormatFlags]::VerticalCenter -bor `
                [System.Windows.Forms.TextFormatFlags]::TextBoxControl -bor `
                [System.Windows.Forms.TextFormatFlags]::WordBreak -bor `
                [System.Windows.Forms.TextFormatFlags]::EndEllipsis)

    #Event handled, stop default processing
    $e.Handled = $true
}

$form.ShowDialog()
$form.Dispose()
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • Working asbsolutely PERFECT!! Many, many thanks I was (wrongly) thinking there was a native way without resorting to alter the cellpainting – Aldo May 30 '18 at 13:36
  • You're welcome :) At least I'm not aware of a builtin way, but using custom painting, it's possible. – Reza Aghaei May 30 '18 at 13:43
  • 1
    I must thank you again because besides solving my problem, you provided excellent powershell code.. again, you have all my gratitude – Aldo May 30 '18 at 14:08