New to Telerik UI for WinForms? Download free 30-day trial

How to Embed RadRichTextEditor in GridView Cells

Environment

Product Version Product Author
2022.2.622 RadGridView for WinForms Desislava Yordanova

Description

A common requirement is to display and edit HTML text in RadGridView. RadGridView offers rich text formatting mechanism that uses plain HTML tags to display formatted text such as font style, font color, font size, etc. This can be used to display plain HTML in the grid cells. However, it is also necessary to provide a convenient editing mechanism for this HTML. This article demonstrates a sample approach how to embed a RadRichTextEditor in each cell in RadGridView.

Note that RadRichTextEditor is a heavy control due to its diversity of supported features. Since RadRichTextEditor can't work as an element, it should be hosted as a control in a RadHostItem. Thus, it can be used inside the custom cell element. Note that since this approach uses controls (instead of elements), some visual glitches are possible as controls do not support clipping. In addition, if you are having a lot of rows, performance implications may occur for the same reason.

Display and Edit rich text

embed-richtexteditor-in-grid-cells 001

Solution

Add a RichTextEditorRibbonUI and a RadGridView to the form. It is necessary to create a custom column that uses a specific cell element that shows a RadRichTextEditor.

Custom Column


public class GridViewRichTextColumn : GridViewTextBoxColumn
{
    public GridViewRichTextColumn()
    {
    }

    public GridViewRichTextColumn(string fieldName)
        : base(fieldName)
    {
    }


    public GridViewRichTextColumn(string uniqueName, string fieldName)
        : base(uniqueName, fieldName)
    {
    }

    public override System.Type GetCellType(GridViewRowInfo row)
    {
        if (row is GridViewDataRowInfo)
        {
            return typeof(RichTextEditorCellElement);
        }

        return base.GetCellType(row);
    }

    public override System.Type GetDefaultEditorType()
    {
        return typeof(RichTextEditor);
    }

    public override IInputEditor GetDefaultEditor()
    {
        return new RichTextEditor();
    }
}        


Public Class GridViewRichTextColumn
    Inherits GridViewTextBoxColumn

    Public Sub New()
    End Sub

    Public Sub New(ByVal fieldName As String)
        MyBase.New(fieldName)
    End Sub

    Public Sub New(ByVal uniqueName As String, ByVal fieldName As String)
        MyBase.New(uniqueName, fieldName)
    End Sub

    Public Overrides Function GetCellType(ByVal row As GridViewRowInfo) As System.Type
        If TypeOf row Is GridViewDataRowInfo Then
            Return GetType(RichTextEditorCellElement)
        End If

        Return MyBase.GetCellType(row)
    End Function

    Public Overrides Function GetDefaultEditorType() As System.Type
        Return GetType(RichTextEditor)
    End Function

    Public Overrides Function GetDefaultEditor() As IInputEditor
        Return New RichTextEditor()
    End Function
End Class

Custom Cell Element


public class RichTextEditorCellElement : GridDataCellElement
{
    private RichTextEditor editor;

    public RichTextEditorCellElement(GridViewColumn col, GridRowElement row)
        : base(col, row)
    {

    }

    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(GridDataCellElement);
        }
    }

    public override IInputEditor Editor
    {
        get
        {
            return this.editor;
        }
    }

    protected override void CreateChildElements()
    {
        base.CreateChildElements();
        this.editor = new RichTextEditor();

        this.Children.Add(this.editor.EditorElement);
    }

    protected override void SetContentCore(object value)
    {
        try
        {
            this.editor.Value = Convert.ToString(value);

            if (this.Value != null && this.Value != DBNull.Value && this.Value.ToString() != "")
            {
                RichTextEditorElement element = (RichTextEditorElement)this.editor.EditorElement;
                RadRichTextEditor textBox = (RadRichTextEditor)element.HostedControl;
                HtmlFormatProvider provider = new HtmlFormatProvider(); 

                RadDocument document = provider.Import(this.Value.ToString());
                textBox.Document = document;
                document.LayoutMode = DocumentLayoutMode.Flow;
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(null, ex.ToString(), "EXCEPTION", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    public override void Attach(GridViewColumn data, object context)
    {
        base.Attach(data, context);

        if (this.RowElement != null)
        {
            this.GridViewElement.EditorManager.RegisterPermanentEditorType(typeof(RichTextEditor));
        }
    }
}     


Public Class RichTextEditorCellElement
    Inherits GridDataCellElement

    Private _editor As RichTextEditor

    Public Sub New(ByVal col As GridViewColumn, ByVal row As GridRowElement)
        MyBase.New(col, row)
    End Sub

    Protected Overrides ReadOnly Property ThemeEffectiveType As Type
        Get
            Return GetType(GridDataCellElement)
        End Get
    End Property

    Public Overrides ReadOnly Property Editor As IInputEditor
        Get
            Return Me._editor
        End Get
    End Property

    Protected Overrides Sub CreateChildElements()
        MyBase.CreateChildElements()
        Me._editor = New RichTextEditor()
        Me.Children.Add(Me._editor.EditorElement)
    End Sub

    Protected Overrides Sub SetContentCore(ByVal value As Object)
        Try
            Me.editor.Value = Convert.ToString(value)

            If Me.Value IsNot Nothing AndAlso Not Me.Value.Equals(DBNull.Value) AndAlso Not Me.Value.ToString().Equals(String.Empty) Then
                Dim element As RichTextEditorElement = CType(Me._editor.EditorElement, RichTextEditorElement)
                Dim textBox As RadRichTextEditor = CType(element.HostedControl, RadRichTextEditor)
                Dim provider As HtmlFormatProvider = New HtmlFormatProvider()
                Dim document As RadDocument = provider.Import(Me.Value.ToString())
                textBox.Document = document
                document.LayoutMode = DocumentLayoutMode.Flow
            End If

        Catch ex As Exception
            MessageBox.Show(Nothing, ex.ToString(), "EXCEPTION", MessageBoxButtons.OK, MessageBoxIcon.[Error])
        End Try
    End Sub

    Public Overrides Sub Attach(ByVal data As GridViewColumn, ByVal context As Object)
        MyBase.Attach(data, context)

        If Me.RowElement IsNot Nothing Then
            Me.GridViewElement.EditorManager.RegisterPermanentEditorType(GetType(RichTextEditor))
        End If
    End Sub
End Class

Custom BaseGridEditor


public class RichTextEditor : BaseGridEditor
{
    public override object Value
    {
        get
        {
            RichTextEditorElement element = (RichTextEditorElement)EditorElement;
            RadRichTextEditor textBox = (RadRichTextEditor)element.HostedControl;
           HtmlFormatProvider provider = new HtmlFormatProvider();
            return provider.Export(textBox.Document);
        }
        set
        {
            RichTextEditorElement element = (RichTextEditorElement)EditorElement;
            RadRichTextEditor textBox = (RadRichTextEditor)element.HostedControl;
            HtmlFormatProvider provider = new HtmlFormatProvider();
            if (value != null)
            {
                textBox.Document = provider.Import(value.ToString());
            }
            else
            {
                textBox.Document = provider.Import(@"<html><body></body></html>");
            }
        }
    }

    public override void BeginEdit()
    {
        base.BeginEdit();

        RichTextEditorElement element = this.EditorElement as RichTextEditorElement;
        RadRichTextEditor richTextEditor = element.HostedControl as RadRichTextEditor;
        richTextEditor.Document.DocumentContentChanged += this.OnDocumentContentChanged;
    }

    private void OnDocumentContentChanged(object sender, System.EventArgs e)
    {
        this.OnValueChanged();
    }

    public override bool EndEdit()
    {
        RichTextEditorElement element = this.EditorElement as RichTextEditorElement;
        RadRichTextEditor richTextEditor = element.HostedControl as RadRichTextEditor;
        richTextEditor.Document.DocumentContentChanged -= this.OnDocumentContentChanged;

        return base.EndEdit();
    }

    protected override RadElement CreateEditorElement()
    {
        return new RichTextEditorElement();
    } 
}

public class RichTextEditorElement : RadHostItem
{
    public RichTextEditorElement()
        : base(new RadRichTextEditor())
    {
        RouteMessages = false;
        this.HostedControl.GotFocus += new EventHandler(HostedControl_GotFocus);
        this.HostedControl.KeyDown += new KeyEventHandler(HostedControl_KeyDown);
    }

    private void HostedControl_GotFocus(object sender, EventArgs e)
    {
        RichTextEditorCellElement cell = this.Parent as RichTextEditorCellElement;
        if (cell != null)
        {
            cell.ColumnInfo.IsCurrent = true;
            cell.RowInfo.IsCurrent = true;
            cell.GridViewElement.BeginEdit();
        }
    }

    void HostedControl_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.Enter)
        {
            ((RadGridView)this.ElementTree.Control).EndEdit();
        }
    }
}    


Public Class RichTextEditor
    Inherits BaseGridEditor

    Public Overrides Property Value As Object
        Get
            Dim element As RichTextEditorElement = CType(EditorElement, RichTextEditorElement)
            Dim textBox As RadRichTextEditor = CType(element.HostedControl, RadRichTextEditor)
            Dim provider As HtmlFormatProvider = New HtmlFormatProvider()
            Return provider.Export(textBox.Document)
        End Get
        Set(ByVal value As Object)
            Dim element As RichTextEditorElement = CType(EditorElement, RichTextEditorElement)
            Dim textBox As RadRichTextEditor = CType(element.HostedControl, RadRichTextEditor)
            Dim provider As HtmlFormatProvider = New HtmlFormatProvider()

            If value IsNot Nothing Then
                textBox.Document = provider.Import(value.ToString())
            Else
                textBox.Document = provider.Import("<html><body></body></html>")
            End If
        End Set
    End Property

    Public Overrides Sub BeginEdit()
        MyBase.BeginEdit()
        Dim element As RichTextEditorElement = TryCast(Me.EditorElement, RichTextEditorElement)
        Dim richTextEditor As RadRichTextEditor = TryCast(element.HostedControl, RadRichTextEditor)
        AddHandler richTextEditor.Document.DocumentContentChanged, AddressOf Me.OnDocumentContentChanged
    End Sub

    Private Sub OnDocumentContentChanged(ByVal sender As Object, ByVal e As System.EventArgs)
        Me.OnValueChanged()
    End Sub

    Public Overrides Function EndEdit() As Boolean
        Dim element As RichTextEditorElement = TryCast(Me.EditorElement, RichTextEditorElement)
        Dim richTextEditor As RadRichTextEditor = TryCast(element.HostedControl, RadRichTextEditor)
        RemoveHandler richTextEditor.Document.DocumentContentChanged, AddressOf Me.OnDocumentContentChanged
        Return MyBase.EndEdit()
    End Function

    Protected Overrides Function CreateEditorElement() As RadElement
        Return New RichTextEditorElement()
    End Function
End Class

Public Class RichTextEditorElement
    Inherits RadHostItem

    Public Sub New()
        MyBase.New(New RadRichTextEditor())
        RouteMessages = False
        AddHandler Me.HostedControl.GotFocus, New EventHandler(AddressOf HostedControl_GotFocus)
        AddHandler Me.HostedControl.KeyDown, New KeyEventHandler(AddressOf HostedControl_KeyDown)
    End Sub

    Private Sub HostedControl_GotFocus(ByVal sender As Object, ByVal e As EventArgs)
        Dim cell As RichTextEditorCellElement = TryCast(Me.Parent, RichTextEditorCellElement)

        If cell IsNot Nothing Then
            cell.ColumnInfo.IsCurrent = True
            cell.RowInfo.IsCurrent = True
            cell.GridViewElement.BeginEdit()
        End If
    End Sub

    Private Sub HostedControl_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
        If e.Control AndAlso e.KeyCode = Keys.Enter Then
            Dim grid As RadGridView = TryCast(Me.ElementTree.Control, RadGridView)
            grid.EndEdit()
        End If
    End Sub
End Class

Last, but not least, the following code snippet demonstrates how to use it in RadGridView:


public Form1()
{
    InitializeComponent();

    this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
    this.radGridView1.Columns.Add(new GridViewRichTextColumn("Text", "Text"));

    GridViewRowInfo row = radGridView1.Rows.AddNew(); 
    row.Height = 200;
    row.Cells[0].Value = "<html><span style=\"background-color:red\">Highlighted Text</span></html>";

     row = radGridView1.Rows.AddNew(); 
    row.Height = 200;
    row.Cells[0].Value = "<html><span style=\"background-color:red\">Second Text</span></html>";

     row = radGridView1.Rows.AddNew(); 
    row.Height = 200;
    row.Cells[0].Value = "<html><span style=\"background-color:red\">Third Text</span></html>";

    this.radGridView1.CurrentCellChanged += RadGridView1_CurrentCellChanged;
}

private void RadGridView1_CurrentCellChanged(object sender, CurrentCellChangedEventArgs e)
{
    if (e.NewCell != null && e.NewCell.ColumnInfo is GridViewRichTextColumn)
    {
        RichTextEditorCellElement cellElement = this.radGridView1.TableElement.GetCellElement(e.NewCell.RowInfo,
            e.NewCell.ColumnInfo) as RichTextEditorCellElement;
        if (cellElement != null)
        {
            RichTextEditorElement element = (RichTextEditorElement)((RichTextEditor)cellElement.Editor).EditorElement;
            RadRichTextEditor textBox = (RadRichTextEditor)element.HostedControl;
            this.richTextEditorRibbonBar1.AssociatedRichTextEditor = textBox;
            Console.WriteLine(textBox.GetHashCode());
        }
    }
}




Public Class RadForm1
    Public Sub New()
        InitializeComponent()
        Me.RadGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill
        Me.RadGridView1.Columns.Add(New GridViewRichTextColumn("Text", "Text"))
        Dim row As GridViewRowInfo = RadGridView1.Rows.AddNew()
        row.Height = 200
        row.Cells(0).Value = "<html><span style=""background-color:red"">Highlighted Text</span></html>"
        row = RadGridView1.Rows.AddNew()
        row.Height = 200
        row.Cells(0).Value = "<html><span style=""background-color:red"">Second Text</span></html>"
        row = RadGridView1.Rows.AddNew()
        row.Height = 200
        row.Cells(0).Value = "<html><span style=""background-color:red"">Third Text</span></html>"
        AddHandler Me.RadGridView1.CurrentCellChanged, AddressOf RadGridView1_CurrentCellChanged
    End Sub

    Private Sub RadGridView1_CurrentCellChanged(ByVal sender As Object, ByVal e As CurrentCellChangedEventArgs)
        If e.NewCell IsNot Nothing AndAlso TypeOf e.NewCell.ColumnInfo Is GridViewRichTextColumn Then
            Dim cellElement As RichTextEditorCellElement = TryCast(Me.RadGridView1.TableElement.GetCellElement(e.NewCell.RowInfo,
                                                                    e.NewCell.ColumnInfo), RichTextEditorCellElement)

            If cellElement IsNot Nothing Then
                Dim element As RichTextEditorElement = CType((CType(cellElement.Editor, RichTextEditor)).EditorElement, RichTextEditorElement)
                Dim textBox As RadRichTextEditor = CType(element.HostedControl, RadRichTextEditor)
                Me.RichTextEditorRibbonBar1.AssociatedRichTextEditor = textBox
                Console.WriteLine(textBox.GetHashCode())
            End If
        End If
    End Sub
End Class

A complete C# and VB project is available here.

See Also

In this article