Click here to Skip to main content
15,881,455 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Following this article

RichTextBox Cell in a DataGridView[^]

i built a typed datagridview with richtextbox cells.
But when i try to bind a DataTable to the DataGridView, the DataTable exhibit the DataColumn.DataType property as normal string, and it pass a normal string.
The DataGridView show it as normal string and lost the rtf formatting.
Does someone know some ways to bind correctly the rtf datas to a typed DataGridView?


Form code
VB
 Private dt As DataTable
    Private dgv As DataGridView
    Private b_Rtb_Dgv, b_Dt_Dgv As Button
    Private rbRtb, rbDt As RadioButton
    Private rtb As RichTextBox

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Size = New Size(350, 380)
        Me.Location = New Point(0, 0)
        Me.Text = "Form1"

        rbRtb = New RadioButton
        With rbRtb
            .Size = New Size(100, 30)
            .Location = New Point(10, 10)
            .Text = "RichTextBox"
            .Checked = True
            AddHandler .Click, AddressOf rb_Click
        End With
        Me.Controls.Add(rbRtb)
        rbDt = New RadioButton
        With rbDt
            .Size = New Size(100, 30)
            .Location = New Point(10, 40)
            .Text = "DataTable"
            .Checked = False
            AddHandler .Click, AddressOf rb_Click
        End With
        Me.Controls.Add(rbDt)

        dt = New DataTable
        With dt
            .Columns.Add("col1", GetType(String))
            .Rows.Add()
        End With

        dgv = New DataGridView
        With dgv
            .AllowUserToAddRows = False
            .AllowUserToDeleteRows = False
            .AllowUserToResizeColumns = False
            .AllowUserToResizeRows = False
            .ColumnHeadersVisible = False
            .RowHeadersVisible = False
            .RowsDefaultCellStyle.WrapMode = DataGridViewTriState.True
            .Size = New Size(300, 100)
            .Location = New Point(10, 80)
            .RowTemplate.Height = .Size.Height

            loadDgv()
        End With
        Me.Controls.Add(dgv)


        b_Rtb_Dgv = New Button
        With b_Rtb_Dgv
            .Size = New Size(200, 23)
            .Location = New Point(110, 10)
            .Text = "RichTextBox --> DataGridView"
            AddHandler .Click, AddressOf b_Rtb_Dgv_Click
            .Enabled = True
        End With
        Me.Controls.Add(b_Rtb_Dgv)

        b_Dt_Dgv = New Button
        With b_Dt_Dgv
            .Size = New Size(200, 23)
            .Location = New Point(110, 40)
            .Text = "DataTable --> DataGridView"
            AddHandler .Click, AddressOf b_Dt_Dgv_Click
            .Enabled = False
        End With
        Me.Controls.Add(b_Dt_Dgv)

        rtb = New RichTextBox
        With rtb
            .Size = New Size(300, 120)
            .Location = New Point(10, 200)
            .Rtf = "{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 Calibri;}}  \viewkind4\uc1\pard\sa200\sl276\slmult1\lang16\b\f0\fs36 Donald\b0\fs22\par  \i Duck\i0\par  }  "
        End With
        Me.Controls.Add(rtb)

    End Sub
    Private Sub loadDgv()
        With dgv
            Select Case rbRtb.Checked
                Case True
                    .DataSource = Nothing
                    .AutoGenerateColumns = False
                    .Rows.Clear()
                    .Columns.Clear()
                    .Columns.Add(New DataGridViewRichTextBoxColumn)
                    .Rows.Add(New DataGridViewRichTextBoxCell)
                Case False
                    If .AutoGenerateColumns = False Then
                        .Rows.Clear()
                        .Columns.Clear()
                        .AutoGenerateColumns = True
                        .DataSource = dt
                    End If
            End Select
            .Columns.Item(0).Width = .Size.Width - 3
        End With

    End Sub
    Private Sub rb_Click()
        Select Case rbRtb.Checked
            Case True
                If b_Rtb_Dgv.Enabled = False Then b_Rtb_Dgv.Enabled = True : b_Dt_Dgv.Enabled = False
            Case False
                If b_Dt_Dgv.Enabled = False Then b_Dt_Dgv.Enabled = True : b_Rtb_Dgv.Enabled = False
        End Select
        loadDgv()
    End Sub

    Public Shared Function TextToRTF(ByVal RTFtext As String) As String
        Dim data_object As New DataObject
        data_object.SetData(DataFormats.Rtf, RTFtext)
        Return data_object.GetData(DataFormats.Rtf)
    End Function

    Private Sub b_Rtb_Dgv_Click(sender As Object, e As EventArgs)
        Me.dgv.Rows(0).Cells(0).Value = Me.rtb.Rtf
    End Sub

    Private Sub b_Dt_Dgv_Click(sender As Object, e As EventArgs)
        dt.Rows(0)(0) = Me.rtb.Rtf
        rtb.Rtf = dt.Rows(0)(0)
    End Sub

End Class


DataGridView RichTextFormat class

VB
Imports System.ComponentModel


Public Class DataGridViewRichTextBoxColumn
    Inherits DataGridViewColumn

    Public Sub New()
        MyBase.New(New DataGridViewRichTextBoxCell())
    End Sub

    Public Overrides Property CellTemplate() As DataGridViewCell
        Get
            Return MyBase.CellTemplate
        End Get
        Set(value As DataGridViewCell)
            If Not (TypeOf value Is DataGridViewRichTextBoxCell) Then
                Throw New InvalidCastException("CellTemplate must be a DataGridViewRichTextBoxCell")
            End If

            MyBase.CellTemplate = value
        End Set
    End Property
End Class

Public Class DataGridViewRichTextBoxCell
    Inherits DataGridViewImageCell
    Private Shared ReadOnly _editingControl As New RichTextBox()

    Public Overrides ReadOnly Property EditType() As Type
        Get
            Return GetType(DataGridViewRichTextBoxEditingControl)
        End Get
    End Property

    Public Overrides Property ValueType() As Type
        Get
            Return GetType(String)
        End Get
        Set(value As Type)
            MyBase.ValueType = value
        End Set
    End Property

    Public Overrides ReadOnly Property FormattedValueType() As Type
        Get
            Return GetType(String)
        End Get
    End Property

    Private Shared Sub SetRichTextBoxText(ctl As RichTextBox, text As String)
        Try
            ctl.Rtf = text
        Catch generatedExceptionName As ArgumentException
            'ctl.Text = text
        End Try
    End Sub

    Private Function GetRtfImage(rowIndex As Integer, value As Object, selected As Boolean) As Image
        Dim cellSize As Size = GetSize(rowIndex)

        If cellSize.Width < 1 OrElse cellSize.Height < 1 Then
            Return Nothing
        End If

        Dim ctl As RichTextBox = Nothing

        If ctl Is Nothing Then
            ctl = _editingControl
            ctl.Size = GetSize(rowIndex)
            SetRichTextBoxText(ctl, Convert.ToString(value))
        End If

        If ctl IsNot Nothing Then
            ' Print the content of RichTextBox to an image.
            Dim imgSize As New Size(cellSize.Width - 1, cellSize.Height - 1)
            Dim rtfImg As Image = Nothing

            If selected Then
                ' Selected cell state
                ctl.BackColor = DataGridView.DefaultCellStyle.SelectionBackColor
                ctl.ForeColor = DataGridView.DefaultCellStyle.SelectionForeColor

                ' Print image
                rtfImg = RichTextBoxPrinter.Print(ctl, imgSize.Width, imgSize.Height)

                ' Restore RichTextBox
                ctl.BackColor = DataGridView.DefaultCellStyle.BackColor
                ctl.ForeColor = DataGridView.DefaultCellStyle.ForeColor
            Else
                rtfImg = RichTextBoxPrinter.Print(ctl, imgSize.Width, imgSize.Height)
            End If

            Return rtfImg
        End If

        Return Nothing
    End Function

    Public Overrides Sub InitializeEditingControl(rowIndex As Integer, initialFormattedValue As Object, dataGridViewCellStyle As DataGridViewCellStyle)
        MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle)

        Dim ctl As RichTextBox = TryCast(DataGridView.EditingControl, RichTextBox)

        If ctl IsNot Nothing Then
            SetRichTextBoxText(ctl, Convert.ToString(initialFormattedValue))
        End If
    End Sub

    Protected Overrides Function GetFormattedValue(value As Object, rowIndex As Integer, ByRef cellStyle As DataGridViewCellStyle, valueTypeConverter As TypeConverter, formattedValueTypeConverter As TypeConverter, context As DataGridViewDataErrorContexts) As Object
        Return value
    End Function

    Protected Overrides Sub Paint(graphics As Graphics, clipBounds As Rectangle, cellBounds As Rectangle, rowIndex As Integer, cellState As DataGridViewElementStates, value As Object, _
        formattedValue As Object, errorText As String, cellStyle As DataGridViewCellStyle, advancedBorderStyle As DataGridViewAdvancedBorderStyle, paintParts As DataGridViewPaintParts)
        MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, Nothing, _
            Nothing, errorText, cellStyle, advancedBorderStyle, paintParts)

        Dim img As Image = GetRtfImage(rowIndex, value, MyBase.Selected)

        If img IsNot Nothing Then
            graphics.DrawImage(img, cellBounds.Left, cellBounds.Top)
        End If
    End Sub

#Region "Handlers of edit events, copyied from DataGridViewTextBoxCell"
     Private flagsState As Byte

    Protected Overrides Sub OnEnter(rowIndex As Integer, throughMouseClick As Boolean)
        MyBase.OnEnter(rowIndex, throughMouseClick)

        If (MyBase.DataGridView IsNot Nothing) AndAlso throughMouseClick Then
            Me.flagsState = CByte(Me.flagsState Or 1)
        End If
    End Sub

    Protected Overrides Sub OnLeave(rowIndex As Integer, throughMouseClick As Boolean)
        MyBase.OnLeave(rowIndex, throughMouseClick)

        If MyBase.DataGridView IsNot Nothing Then
            Me.flagsState = CByte(Me.flagsState And -2)
        End If
    End Sub

    Protected Overrides Sub OnMouseClick(e As DataGridViewCellMouseEventArgs)
        MyBase.OnMouseClick(e)
        If MyBase.DataGridView IsNot Nothing Then
            Dim currentCellAddress As Point = MyBase.DataGridView.CurrentCellAddress

            If ((currentCellAddress.X = e.ColumnIndex) AndAlso (currentCellAddress.Y = e.RowIndex)) AndAlso (e.Button = MouseButtons.Left) Then
                If (Me.flagsState And 1) <> 0 Then
                    Me.flagsState = CByte(Me.flagsState And -2)
                ElseIf MyBase.DataGridView.EditMode <> DataGridViewEditMode.EditProgrammatically Then
                    MyBase.DataGridView.BeginEdit(False)
                End If
            End If
        End If
    End Sub

    Public Overrides Function KeyEntersEditMode(e As KeyEventArgs) As Boolean
        Return (((((Char.IsLetterOrDigit(CChar(ChrW(CUShort(e.KeyCode)))) AndAlso ((e.KeyCode < Keys.F1) OrElse (e.KeyCode > Keys.F24))) OrElse ((e.KeyCode >= Keys.NumPad0) AndAlso (e.KeyCode <= Keys.Divide))) OrElse (((e.KeyCode >= Keys.OemSemicolon) AndAlso (e.KeyCode <= Keys.OemBackslash)) OrElse ((e.KeyCode = Keys.Space) AndAlso Not e.Shift))) AndAlso (Not e.Alt AndAlso Not e.Control)) OrElse MyBase.KeyEntersEditMode(e))
    End Function

#End Region
End Class

Public Class DataGridViewRichTextBoxEditingControl
    Inherits RichTextBox
    Implements IDataGridViewEditingControl

    Private _dataGridView As DataGridView
    Private _rowIndex As Integer
    Private _valueChanged As Boolean

    Public Sub New()
        Me.BorderStyle = BorderStyle.None
    End Sub

    Protected Overrides Sub OnTextChanged(e As EventArgs)
        MyBase.OnTextChanged(e)

        _valueChanged = True
        EditingControlDataGridView.NotifyCurrentCellDirty(True)
    End Sub

    Protected Overrides Function IsInputKey(keyData As Keys) As Boolean
        Dim keys__1 As Keys = keyData And Keys.KeyCode
        If keys__1 = Keys.[Return] Then
            Return Me.Multiline
        End If

        Return MyBase.IsInputKey(keyData)
    End Function

    Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
        MyBase.OnKeyDown(e)

        If e.Control Then
            Select Case e.KeyCode
                ' Control + B = Bold
                Case Keys.B
                    If Me.SelectionFont.Bold Then
                        Me.SelectionFont = New Font(Me.Font.FontFamily, Me.Font.Size, Not FontStyle.Bold And Me.Font.Style)
                    Else
                        Me.SelectionFont = New Font(Me.Font.FontFamily, Me.Font.Size, FontStyle.Bold Or Me.Font.Style)
                    End If
                    Exit Select
                    ' Control + U = Underline
                Case Keys.U
                    If Me.SelectionFont.Underline Then
                        Me.SelectionFont = New Font(Me.Font.FontFamily, Me.Font.Size, Not FontStyle.Underline And Me.Font.Style)
                    Else
                        Me.SelectionFont = New Font(Me.Font.FontFamily, Me.Font.Size, FontStyle.Underline Or Me.Font.Style)
                    End If
                    Exit Select
                Case Else
                    ' Control + I = Italic
                    ' Conflicts with the default shortcut
                    'case Keys.I:
                    '    if (this.SelectionFont.Italic)
                    '    {
                    '        this.SelectionFont = new Font(this.Font.FontFamily, this.Font.Size, ~FontStyle.Italic & this.Font.Style);
                    '    }
                    '    else
                    '        this.SelectionFont = new Font(this.Font.FontFamily, this.Font.Size, FontStyle.Italic | this.Font.Style);
                    '    break;
                    Exit Select
            End Select
        End If
    End Sub

#Region "IDataGridViewEditingControl Members"
     Public Sub ApplyCellStyleToEditingControl(dataGridViewCellStyle As DataGridViewCellStyle)
        Me.Font = dataGridViewCellStyle.Font
    End Sub

    Public Property EditingControlDataGridView() As DataGridView
        Get
            Return _dataGridView
        End Get
        Set(value As DataGridView)
            _dataGridView = value
        End Set
    End Property

    Public Property EditingControlFormattedValue() As Object
        Get
            Return Me.Rtf
        End Get
        Set(value As Object)
            If TypeOf value Is String Then
                Me.Text = TryCast(value, String)
            End If
        End Set
    End Property

    Public Property EditingControlRowIndex() As Integer
        Get
            Return _rowIndex
        End Get
        Set(value As Integer)
            _rowIndex = value
        End Set
    End Property

    Public Property EditingControlValueChanged() As Boolean
        Get
            Return _valueChanged
        End Get
        Set(value As Boolean)
            _valueChanged = value
        End Set
    End Property

    Public Function EditingControlWantsInputKey(keyData As Keys, dataGridViewWantsInputKey As Boolean) As Boolean
        Select Case (keyData And Keys.KeyCode)
            Case Keys.[Return]
                If (((keyData And (Keys.Alt Or Keys.Control Or Keys.Shift)) = Keys.Shift) AndAlso Me.Multiline) Then
                    Return True
                End If
                Exit Select
            Case Keys.Left, Keys.Right, Keys.Up, Keys.Down
                Return True
        End Select

        Return Not dataGridViewWantsInputKey
    End Function

    Public ReadOnly Property EditingPanelCursor() As Cursor
        Get
            Return Me.Cursor
        End Get
    End Property

    Public Function GetEditingControlFormattedValue(context As DataGridViewDataErrorContexts) As Object
        Return Me.Rtf
    End Function

    Public Sub PrepareEditingControlForEdit(selectAll As Boolean)
    End Sub

    Public ReadOnly Property RepositionEditingControlOnValueChange() As Boolean
        Get
            Return False
        End Get
    End Property

#End Region

    Public Sub ApplyCellStyleToEditingControl1(dataGridViewCellStyle As DataGridViewCellStyle) Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl

    End Sub

    Public Property EditingControlDataGridView1 As DataGridView Implements IDataGridViewEditingControl.EditingControlDataGridView

    Public Property EditingControlFormattedValue1 As Object Implements IDataGridViewEditingControl.EditingControlFormattedValue

    Public Property EditingControlRowIndex1 As Integer Implements IDataGridViewEditingControl.EditingControlRowIndex

    Public Property EditingControlValueChanged1 As Boolean Implements IDataGridViewEditingControl.EditingControlValueChanged

    Public Function EditingControlWantsInputKey1(keyData As Keys, dataGridViewWantsInputKey As Boolean) As Boolean Implements IDataGridViewEditingControl.EditingControlWantsInputKey

    End Function

    Public ReadOnly Property EditingPanelCursor1 As Cursor Implements IDataGridViewEditingControl.EditingPanelCursor
        Get

        End Get
    End Property

    Public Function GetEditingControlFormattedValue1(context As DataGridViewDataErrorContexts) As Object Implements IDataGridViewEditingControl.GetEditingControlFormattedValue

    End Function

    Public Sub PrepareEditingControlForEdit1(selectAll As Boolean) Implements IDataGridViewEditingControl.PrepareEditingControlForEdit

    End Sub

    Public ReadOnly Property RepositionEditingControlOnValueChange1 As Boolean Implements IDataGridViewEditingControl.RepositionEditingControlOnValueChange
        Get

        End Get
    End Property
End Class


RichTextBoxPrinter code

VB
Imports System.Drawing.Printing
Imports System.Runtime.InteropServices

''' <summary>
''' http://support.microsoft.com/default.aspx?scid=kb;en-us;812425
''' The RichTextBox control does not provide any method to print the content of the RichTextBox. 
''' You can extend the RichTextBox class to use EM_FORMATRANGE message 
''' to send the content of a RichTextBox control to an output device such as printer.
''' </summary>
Public Class RichTextBoxPrinter
    'Convert the unit used by the .NET framework (1/100 inch) 
    'and the unit used by Win32 API calls (twips 1/1440 inch)
    Private Const anInch As Double = 14.4

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure RECT
        Public Left As Integer
        Public Top As Integer
        Public Right As Integer
        Public Bottom As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure CHARRANGE
        Public cpMin As Integer
        'First character of range (0 for start of doc)
        Public cpMax As Integer
        'Last character of range (-1 for end of doc)
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure FORMATRANGE
        Public hdc As IntPtr
        'Actual DC to draw on
        Public hdcTarget As IntPtr
        'Target DC for determining text formatting
        Public rc As RECT
        'Region of the DC to draw to (in twips)
        Public rcPage As RECT
        'Region of the whole DC (page size) (in twips)
        Public chrg As CHARRANGE
        'Range of text to draw (see earlier declaration)
    End Structure

    Private Const WM_USER As Integer = &H400
    Private Const EM_FORMATRANGE As Integer = WM_USER + 57

    <DllImport("USER32.dll")> _
    Private Shared Function SendMessage(hWnd As IntPtr, msg As Integer, wp As IntPtr, lp As IntPtr) As IntPtr
    End Function

    ' Render the contents of the RichTextBox for printing
    '	Return the last character printed + 1 (printing start from this point for next page)
    Public Shared Function Print(richTextBoxHandle As IntPtr, charFrom As Integer, charTo As Integer, e As PrintPageEventArgs) As Integer
        'Calculate the area to render and print
        Dim rectToPrint As RECT
        rectToPrint.Top = CInt(e.MarginBounds.Top * anInch)
        rectToPrint.Bottom = CInt(e.MarginBounds.Bottom * anInch)
        rectToPrint.Left = CInt(e.MarginBounds.Left * anInch)
        rectToPrint.Right = CInt(e.MarginBounds.Right * anInch)

        'Calculate the size of the page
        Dim rectPage As RECT
        rectPage.Top = CInt(e.PageBounds.Top * anInch)
        rectPage.Bottom = CInt(e.PageBounds.Bottom * anInch)
        rectPage.Left = CInt(e.PageBounds.Left * anInch)
        rectPage.Right = CInt(e.PageBounds.Right * anInch)

        Dim hdc As IntPtr = e.Graphics.GetHdc()

        Dim fmtRange As FORMATRANGE
        fmtRange.chrg.cpMax = charTo
        'Indicate character from to character to 
        fmtRange.chrg.cpMin = charFrom
        fmtRange.hdc = hdc
        'Use the same DC for measuring and rendering
        fmtRange.hdcTarget = hdc
        'Point at printer hDC
        fmtRange.rc = rectToPrint
        'Indicate the area on page to print
        fmtRange.rcPage = rectPage
        'Indicate size of page
        Dim res As IntPtr = IntPtr.Zero

        Dim wparam As IntPtr = IntPtr.Zero
        wparam = New IntPtr(1)

        'Get the pointer to the FORMATRANGE structure in memory
        Dim lparam As IntPtr = IntPtr.Zero
        lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange))
        Marshal.StructureToPtr(fmtRange, lparam, False)

        'Send the rendered data for printing 
        res = SendMessage(richTextBoxHandle, EM_FORMATRANGE, wparam, lparam)

        'Free the block of memory allocated
        Marshal.FreeCoTaskMem(lparam)

        'Release the device context handle obtained by a previous call
        e.Graphics.ReleaseHdc(hdc)

        ' Release and cached info
        'SendMessage(richTextBoxHandle, EM_FORMATRANGE, DirectCast(0, IntPtr), DirectCast(0, IntPtr))

        'Return last + 1 character printer
        Return res.ToInt32()
    End Function

    Public Shared Function Print(ctl As RichTextBox, width As Integer, height As Integer) As Image
        Dim img As Image = New Bitmap(width, height)
        Dim scale As Single

        Using g As Graphics = Graphics.FromImage(img)
            ' --- Begin code addition D_Kondrad

            ' HorizontalResolution is measured in pix/inch         
            scale = CSng(width * 100) / img.HorizontalResolution
            width = CInt(scale)

            ' VerticalResolution is measured in pix/inch
            scale = CSng(height * 100) / img.VerticalResolution
            height = CInt(scale)

            ' --- End code addition D_Kondrad

            Dim marginBounds As New Rectangle(0, 0, width, height)
            Dim pageBounds As New Rectangle(0, 0, width, height)
            Dim args As New PrintPageEventArgs(g, marginBounds, pageBounds, Nothing)

            Print(ctl.Handle, 0, ctl.Text.Length, args)
        End Using

        Return img
    End Function

End Class


I translated the dataGridViewRichTexBox and RichTextBoxPrinter from c# by this article
RichTextBox Cell in a DataGridView[^]
I have not checked all the classes, then probably if someone tries to edit the cells, some errors may arise.
For me it's also difficult to understand all, i'm beginner, i just translated, but don't understand most of the code.

I notice that when i give a richtTextBox.Rtf value to the typed DataGridView cell, is correctly displayed, but if i bind the richTextBox.Rtf value through a DataTable, seems that the dataTable is not able to properly manage the value.
I think it depend from the dataTable.columns.DataType property.

From my (beginner) point of view the easiest way to solve is to override the DataTable.Columns.DataType property, but it's not overridable.
Other way is to check if there is an event when the DataTable pass the data to the DataGridView, or when the dataGridView obtain the data from the dataTable, but seems to be there is no such type of events.
These are 2 articles that can give an help

How to Manually Create a Typed DataTable[^]
Converting Text to RichTextFormat[^]
But i need an help.

I try to understand something.
I notice that if the DataGridView is bind from the DataTable, the DataGridViewImageCell.Paint method is not called.
I don't know which is the called method for paint the cells.
I added some code at the form:
VB
Imports System.ComponentModel
Public Class Form1
    Private dt As DataTable
    Private dgv As DataGridView
    Private b_Rtb_Dgv, b_Dt_Dgv As Button
    Private rbRtb, rbDt As RadioButton
    Private rtb As RichTextBox
    Private iB As PictureBox
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Size = New Size(650, 380)
        Me.Location = New Point(0, 0)
        Me.Text = "Form1"

        rbRtb = New RadioButton
        With rbRtb
            .Size = New Size(100, 30)
            .Location = New Point(10, 10)
            .Text = "RichTextBox"
            .Checked = True
            AddHandler .Click, AddressOf rb_Click
        End With
        Me.Controls.Add(rbRtb)
        rbDt = New RadioButton
        With rbDt
            .Size = New Size(100, 30)
            .Location = New Point(10, 40)
            .Text = "DataTable"
            .Checked = False
            AddHandler .Click, AddressOf rb_Click
        End With
        Me.Controls.Add(rbDt)

        dt = New DataTable
        With dt
            .Columns.Add("col1", GetType(String))
            .Rows.Add()
        End With

        dgv = New DataGridView
        With dgv
            .AllowUserToAddRows = False
            .AllowUserToDeleteRows = False
            .AllowUserToResizeColumns = False
            .AllowUserToResizeRows = False
            .ColumnHeadersVisible = False
            .RowHeadersVisible = False
            .RowsDefaultCellStyle.WrapMode = DataGridViewTriState.True
            .Size = New Size(300, 100)
            .Location = New Point(10, 80)
            .RowTemplate.Height = .Size.Height

            loadDgv()
            AddHandler .CellPainting, AddressOf dgv_CellPainting
        End With
        Me.Controls.Add(dgv)


        b_Rtb_Dgv = New Button
        With b_Rtb_Dgv
            .Size = New Size(200, 23)
            .Location = New Point(110, 10)
            .Text = "RichTextBox --> DataGridView"
            AddHandler .Click, AddressOf b_Rtb_Dgv_Click
            .Enabled = True
        End With
        Me.Controls.Add(b_Rtb_Dgv)

        b_Dt_Dgv = New Button
        With b_Dt_Dgv
            .Size = New Size(200, 23)
            .Location = New Point(110, 40)
            .Text = "DataTable --> DataGridView"
            AddHandler .Click, AddressOf b_Dt_Dgv_Click
            .Enabled = False
        End With
        Me.Controls.Add(b_Dt_Dgv)

        rtb = New RichTextBox
        With rtb
            .Size = New Size(300, 120)
            .Location = New Point(10, 200)
            .Rtf = "{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 Calibri;}}  \viewkind4\uc1\pard\sa200\sl276\slmult1\lang16\b\f0\fs36 Donald\b0\fs22\par  \i Duck\i0\par  }  "
        End With
        Me.Controls.Add(rtb)

        iB = New PictureBox
        With iB
            .Size = New Size(150, 150)
            .Location = New Point(350, 10)
            .BackColor = Color.Snow
        End With
        Me.Controls.Add(iB)

    End Sub
    Private Sub loadDgv()
        With dgv
            Select Case rbRtb.Checked
                Case True
                    .DataSource = Nothing
                    .AutoGenerateColumns = False
                    .Rows.Clear()
                    .Columns.Clear()
                    .Columns.Add(New DataGridViewRichTextBoxColumn)
                    .Rows.Add(New DataGridViewRichTextBoxCell)
                Case False
                    If .AutoGenerateColumns = False Then
                        .Rows.Clear()
                        .Columns.Clear()
                        .AutoGenerateColumns = True
                        .DataSource = dt
                    End If
                    .Refresh()
            End Select
            .Columns.Item(0).Width = .Size.Width - 3
        End With

    End Sub
    Private Sub rb_Click()
        Select Case rbRtb.Checked
            Case True
                If b_Rtb_Dgv.Enabled = False Then b_Rtb_Dgv.Enabled = True : b_Dt_Dgv.Enabled = False
            Case False
                If b_Dt_Dgv.Enabled = False Then b_Dt_Dgv.Enabled = True : b_Rtb_Dgv.Enabled = False
        End Select
        loadDgv()
    End Sub

    Public Shared Function TextToRTF(ByVal RTFtext As String) As String
        Dim data_object As New DataObject
        data_object.SetData(DataFormats.Rtf, RTFtext)
        Return data_object.GetData(DataFormats.Rtf)
    End Function

    Private Sub b_Rtb_Dgv_Click(sender As Object, e As EventArgs)
        Me.dgv.Rows(0).Cells(0).Value = Me.rtb.Rtf
    End Sub

    Private Sub b_Dt_Dgv_Click(sender As Object, e As EventArgs)
        dt.Rows(0)(0) = Me.rtb.Rtf
        rtb.Rtf = dt.Rows(0)(0)
    End Sub

    Private Sub dgv_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs)
        With dgv
            'If .Columns.Item(e.ColumnIndex).Name = "" Then
            With .Rows(e.RowIndex).Cells(e.ColumnIndex)
                Dim img As Image = GetRtfImage(e.RowIndex, .Value, True)
                If img IsNot Nothing Then
                    iB.Image = img
                    e.Graphics.DrawImage(img, dgv.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, False))
                End If
            End With
            'End If
        End With
    End Sub
    Public Function GetRtfImage(rowIndex As Integer, value As Object, selected As Boolean) As Image
        Dim cellSize As Size = dgv.Rows(0).Cells(0).Size
        Dim _editingControl As New RichTextBox()
        If cellSize.Width < 1 OrElse cellSize.Height < 1 Then
            Return Nothing
        End If

        Dim ctl As RichTextBox = Nothing

        If ctl Is Nothing Then
            ctl = _editingControl
            ctl.Size = cellSize
            Try
                ctl.Rtf = Convert.ToString(value)

            Catch ex As Exception

            End Try
            'SetRichTextBoxText(ctl, Convert.ToString(value))
        End If

        If ctl IsNot Nothing Then
            ' Print the content of RichTextBox to an image.
            Dim imgSize As New Size(cellSize.Width - 1, cellSize.Height - 1)
            Dim rtfImg As Image = Nothing

            If selected Then
                ' Selected cell state
                ctl.BackColor = dgv.DefaultCellStyle.SelectionBackColor
                ctl.ForeColor = dgv.DefaultCellStyle.SelectionForeColor

                ' Print image
                rtfImg = RichTextBoxPrinter.Print(ctl, imgSize.Width, imgSize.Height)

                ' Restore RichTextBox
                ctl.BackColor = dgv.DefaultCellStyle.BackColor
                ctl.ForeColor = dgv.DefaultCellStyle.ForeColor
            Else
                rtfImg = RichTextBoxPrinter.Print(ctl, imgSize.Width, imgSize.Height)
            End If

            Return rtfImg
        End If
        Return Nothing
    End Function
End Class

Added a PictureBox for see what happen to the image of the cell at the DataGridViewCellPainting Event.
Seems that the image is correctly stored in the dataGridView Cell, but something goes wrong with the painting method.
Posted
Updated 11-Nov-15 7:48am
v11
Comments
BillWoodruff 7-Nov-15 16:07pm    
Show the code.
Marci_xxx 10-Nov-15 11:21am    
Posted
Dave Kreskowiak 9-Nov-15 13:19pm    
First, you bind the DataGridView to the data, not the other way around.

Second, in a RichTextBox there are two representations of the data in the box. One is the Text property, which is the unformatted plain text in the RTB. The other is Rtf property, which has the data with all of the formatting codes in it. You'll have to save BOTH values in your database. One for display in the DGV as it doesn't support rendering rich text and the other to bind to the RichTextBox with all the formatting.
Marci_xxx 10-Nov-15 11:22am    
i posted the code, can you help me?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900