Skip to main content Skip to footer

Display and Edit HTML Content in FlexGrid

This blog article details how you can use ComponentOne Studio for WinForms to display and edit HTML content inside a bound datagrid. To achieve this functionality we will use 3 controls: C1FlexGrid, C1Editor and C1SuperLabel. The C1FlexGridcontrol is a flexible datagrid which will allow us to easily embed custom editors inside any cell, as well as provide custom drawing of cells. The C1Editor will be used as the Xhtml cell editor, and C1SuperLabelwill be used to simply display our Xhtml content and paint to graphics. First, we need to have our FlexGrid bound to a field containing Html content. The code below can be used to quickly create some test data.


private void Form1_Load(objectsender, EventArgs e)  
{  
c1FlexGrid1.Rows.DefaultSize = 50;  
    c1FlexGrid1.Rows[0].Height = 22;  

    // create a data table with an HTML field  
DataTable dt = newDataTable();  
    dt.Columns.Add("HTML", typeof(string));  
dt.Columns.Add("Plain Text", typeof(string));  
    for (int i = 0; i < 100; i++)  
    {  
dt.Rows.Add(GetHtml(8, "Lorem <em>ipsum</em> dolor sit amet, <u>consectetur</u> adipisicing elit, sed do eiusmod <strong>tempor incididunt</strong> ut labore et dolore magna aliqua."), "Plain text...");  
    }  

    // bind grid  
c1FlexGrid1.DataSource = dt;  

    // format Html column  
Column colHtml = c1FlexGrid1.Cols["HTML"];  
colHtml.Width = 400;  
colHtml.StyleNew.WordWrap = true;  
}  

stringGetHtml(floatfontSize, string html)  
{  
    stringbgColor = ColorTranslator.ToHtml(Color.LightGoldenrodYellow);  
    return string.Format(  
        "<html><body style='margin:0pt;padding:0pt;font-family:{0};font-size:{1}pt;background-color:{2}'><p>{3}</p></body></html>",  
        Font.Name,  
fontSize,  
bgColor,  
        html);  
}  

Next, we want to interpret the HTML and display it using C1SuperLabel. We will use the FlexGrid's OwnerDrawCell event to draw the C1SuperLabelas a graphic. To use this event we must first set the FlexGrid's DrawModeproperty to OwnerDraw.


c1FlexGrid1.DrawMode = DrawModeEnum.OwnerDraw;  
c1FlexGrid1.OwnerDrawCell += newOwnerDrawCellEventHandler(c1FlexGrid1_OwnerDrawCell);  

Then inside theOwnerDrawCell event, we grab the HTML cell value, feed it to C1SuperLabel and finally draw the label to the cell.


// use this C1SuperLabel control to render Html cells  
C1.Win.C1SuperTooltip.C1SuperLabel _html = new C1.Win.C1SuperTooltip.C1SuperLabel();  
private voidc1FlexGrid1_OwnerDrawCell(objectsender, OwnerDrawCellEventArgs e)  
{  
    if (c1FlexGrid1.Cols[e.Col].Name == "HTML" && e.Row > 0)  
    {  
        // draw background  
e.DrawCell(DrawCellFlags.Background);  

        // use the C1SuperLabel to draw the html text  
        if (e.Bounds.Width > 0 && e.Bounds.Height > 0)  
        {  
_html.Text = c1FlexGrid1.GetDataDisplay(e.Row, e.Col);  
            _html.BackColor = Color.Transparent;  
_html.DrawToGraphics(e.Graphics, e.Bounds);  
        }  
        // and draw border last  
e.DrawCell(DrawCellFlags.Border);  

        // we're done with this cell  
        e.Handled = true;  
    }  
}  

So far we can just display HTML content, but we can't edit (or if we try it will just look like the first screenshot above). The next step involves using C1Editoras the cell editor for our HTML column. If we just simply set c1FlexGrid.Cols["HTML"].Editor = new C1Editor(), it will not work as desired. This will, by default, bind our cell values to the Text property of C1Editor, which is the actual plain text you see and read, not the underlying HTML. To load in HTML content to C1Editor we should call its LoadXml method. So the easiest way around this is to create our own HtmlEditor control that implements C1Editor. This will enable us to load the HTML content as well as provide further functionality. Add a reference to C1.Win.C1Editor and then add a new User Control (.cs) to your project replacing the code with the following:


using System;  
using System.Drawing;  
using System.Collections;  
using System.Collections.Generic;  
using System.Text;  
using System.Windows.Forms;  
usingSystem.Runtime.InteropServices;  
using System.IO;  
using C1.Win.C1Editor;  

namespace FlexGridHtmlEdit  
{  
    /// <summary>  
    /// Class used to edit and render Html in C1FlexGrid cells.  
    /// </summary>  
    public classHtmlEditor : C1Editor  
    {  
        //--------------------------------------------------------------------------------  
        #region** ctor  

        publicHtmlEditor()  
        {  
        }  

        #endregion  

        //--------------------------------------------------------------------------------  
        #region ** Editing  

        public voidC1EditorInitialize(object value, IDictionary editorAttributes)  
        {  
            // assign HTML content when editing starts  
            this.LoadXml((string)value, null);  
        }  

        public object C1EditorGetValue()  
        {  
            // save HTML content when done editing  
MemoryStream ms = newMemoryStream();  
            this.SaveXml(ms);  
            List<byte> byteArray = new List<byte>(ms.ToArray());  
byteArray.RemoveRange(0, 3); //remove BOM characters  
            returnEncoding.UTF8.GetString(byteArray.ToArray());  
        }  

        public bool C1EditorValueIsValid()  
        {  
            return Enabled;  
        }  

        // support ctrl-B, I, U to implement bold/italic/underline  
        protected override voidOnKeyDown(KeyEventArgs e)  
        {  
            if (this.SelectedText != null)  
            {  
                if (e.Modifiers == Keys.Control)  
                {  
                    switch(e.KeyCode)  
                    {  
                        case Keys.B:  
ToggleStyle(FontStyle.Bold);  
                            e.Handled = true;  
e.SuppressKeyPress = true;  
                            return;  
                        case Keys.I:  
ToggleStyle(FontStyle.Italic);  
                            e.Handled = true;  
e.SuppressKeyPress = true;  
                            return;  
                        case Keys.U:  
ToggleStyle(FontStyle.Underline);  
                            e.Handled = true;  
e.SuppressKeyPress = true;  
                            return;  
                    }  
                }  
            }  
           base.OnKeyDown(e);  
        }  
        voidToggleStyle(FontStyle fs)  
        {  
            switch(fs)  
            {  
                caseFontStyle.Bold:  
                    if(Selection.IsTagApplied("strong"))  
                    {  
Selection.RemoveTag("strong");  
                    }  
                    else  
                    {  
Selection.ApplyTag("strong");  
                    }  
                    break;  
                caseFontStyle.Italic:  
                    if(Selection.IsTagApplied("em"))  
                    {  
Selection.RemoveTag("em");  
                    }  
                    else  
                    {  
Selection.ApplyTag("em");  
                    }  
                    break;  
                caseFontStyle.Underline:  
                    if(Selection.IsStyleApplied("text-decoration") &&  
                        string.Compare(Selection.GetStyleValue("text-decoration", C1StyleType.Character), "underline", true) == 0)  
                    {  
Selection.RemoveStyle("text-decoration", null);  
                    }  
                    else  
                    {  
Selection.ApplyStyle("text-decoration", "underline", C1StyleType.Character);  
                    }  
                    break;  
            }  
        }  

        #endregion  

        private voidInitializeComponent()  
        {  
((System.ComponentModel.ISupportInitialize)(this)).BeginInit();  
            this.SuspendLayout();  
            //  
            // HtmlEditor  
            //  
            this.AutoScaleDimensions = newSystem.Drawing.SizeF(6F, 13F);  
            this.Name = "HtmlEditor";  
            this.Size = new System.Drawing.Size(200, 50);  
((System.ComponentModel.ISupportInitialize)(this)).EndInit();  
            this.ResumeLayout(false);  

        }  
    }  
}  

This HtmlEditor class contains a lot of code but it's really quite simple. First, in the C1EditorInitialize event we take the incoming value and assign it as the underlying Html to the editor control. The rest of the code we've customized to give some added functionality. When the user presses CTRL B, CTRL I or CTRL U the text will become bold, italic or underlined respectively. We accomplish this by intercepting the keys and then toggling the style. C1Editor makes it easy to apply/remove a tag to a selection of text. We simply call RemoveTag or ApplyTag passing in the name of the tag (such as "em", "strong", etc). The same approach can be used for styles in HTML using the RemoveStyle and ApplyStyle methods. So that's our custom html editor. To attach this to FlexGrid, we simply assign an instance of it to the column's Editor property.


// use HtmlEditor class to edit values in the "C1Editor" column  
var editor = newHtmlEditor();  
editor.BorderStyle = BorderStyle.None;  
colHtml.Editor = editor;  

For the full sample, download Studio for WinFormsand look for the FlexGrid/HtmlGrid sample. Or you can download it from here. If you want to provide even richer HTML editing support, you could add the C1Editor toolbars. For example, the code below attaches a style toolbar (C1EditorToolbarStyle) to the editor at runtime using the FlexGrid SetupEditor event. Using the toolbars we can unlock so much more functionality, such as inserting images, tables, formatting colors, font sizes, text alignment and everything else supported by C1Editor.


private void c1FlexGrid1_SetupEditor(object sender, RowColEventArgs e)  
{  
    if (e.Col == 1)  
    {  
c1EditorToolStripStyle1.Editor = (HtmlEditor)c1FlexGrid1.Cols[e.Col].Editor;  
    }  
}  

private void c1FlexGrid1_AfterEdit(object sender, RowColEventArgs e)  
{  
    c1EditorToolStripStyle1.Editor = null;  
}  

Conclusion

ComponentOne Studio for WinForms provides a wide selection of tools to get the job done. It's amazing how much more power you can unleash into your apps when you combine multiple controls together as demonstrated with this sample. Download sample

ComponentOne Product Manager Greg Lutz

Greg Lutz

comments powered by Disqus