• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 4981
  • Last Modified:

Display HTML in RichTextbox or WebBrowser

Hi Guys,

I have a requirement to display text received in HTML format in a Winforms application. I can do this easily with the WebBrowser control, but the length of the text varies, and I need to be able to resize the control to fit the contents. The resizing is easy with a RichTextbox using the ContentsResized event, but I've yet to find a way to resize the WebBrowser effectively. A Richtextbox also makes it easy to get selected text, link clicks, etc.

I'm open to ideas. At this stage, I know of 2 options....

1) Convert HTML to RTF to display in the RichTextbox
2) Find a way to resize the WebBrowser control.

So, how can I convert HTML to RTF? Or, how can the WebBrowser control be resized to fit the contents?

Cheers,

Wayne
0
Wayne Taylor (webtubbs)
Asked:
Wayne Taylor (webtubbs)
  • 6
  • 6
  • 2
3 Solutions
 
Bob LearnedCommented:
Wayne,

You have yourself an interesting situation.  I have seen ways where you can use a RichTextBox to color the text, but it is restrictive to try to push it to what you need.

Proof-of-concept:

Syntax Highlighting in Rich TextBox Control - Part 1
http://www.c-sharpcorner.com/uploadfile/duncanharris/syntaxhighlightinrichtextboxp112012005050840am/syntaxhighlightinrichtextboxp1.aspx
0
 
Wayne Taylor (webtubbs)Author Commented:
Hi Bob,

Yeah, it's been bugging me for a while. I have the below function to convert the html to RTF, but the html can come in different formats, so it doesn't always work. Plus I don't know enough about RTF to be able to convert it effectively.

Do you know of any HTML to RTF converters available, preferably for free? Or, failing that, do you know how I can re-size the WebBrowser control to fit the contents and get rid of the scroll bars?

Wayne
    Public Function HTMLtoRTF(ByVal html As String) As String
 
 
        Const BulletListPatt As String = "<ul>(.*?)</ul>"
        Const NumberListPatt As String = "<ol>(.*?)</ol>"
        Const ListPatt As String = "<li style=""(?:(?:(font-weight: bold;)|(font-style: italic;)|(text-decoration: underline;))\s*)*"">(.*?)</li>"
        Const ListPatt2 As String = "<li>(.*?)</li>"
        Const SpanPatt As String = "<span style=""(?:(?:(font-weight: bold;)|(font-style: italic;)|(text-decoration: underline;))\s*)*"">(.*?)</span>"
        Const SpanPatt2 As String = "<span>(.*?)</span>"
        Const BRPatt As String = "<br style=""(?:(?:(font-weight: bold;)|(font-style: italic;)|(text-decoration: underline;))\s*)*"">"
        Const STRONGpatt As String = "<STRONG>(.*?)</STRONG>"
        Const EMpatt As String = "<EM>(.*?)</EM>"
        Const PARpatt As String = "<P>(.*?)</P>"
        Const Upatt As String = "<U>(.*?)</U>"
        Const RTFHeader As String = "{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fswiss\fcharset0 Arial;}" & _
                                    "{\f1\fnil\fcharset0 Microsoft Sans Serif;}{\f2\fnil\fcharset2 Symbol;}}" & _
                                    "{\colortbl ;\red0\green0\blue255;\red0\green0\blue0;}\viewkind4\uc1\pard\f5\fs20\par "
        Const bStart As String = "\b "
        Const bEnd As String = " \b0"
        Const iStart As String = "\i "
        Const iEnd As String = " \i0"
        Const uStart As String = "\ul "
        Const uEnd As String = " \ulNone"
 
        Dim sb As New StringBuilder(html)
 
        sb.Replace("}", "\}")
        sb.Replace("{", "\{")
 
        sb.Insert(0, RTFHeader)
 
        sb.Replace("<br>", "\par ")
        sb.Replace("<BR>", "\par ")
        sb.Replace(vbCrLf, "\par ")
 
        Dim DIVmch As Match = Regex.Match(sb.ToString, "<div style=.*?>(.*?)</div>", RegexOptions.IgnoreCase)
        Do While DIVmch.Success
            sb.Replace(DIVmch.Value, DIVmch.Groups(1).Value)
            DIVmch = Regex.Match(sb.ToString, "<div style=.*?>(.*?)</div>", RegexOptions.IgnoreCase)
        Loop
 
        For Each m As Match In Regex.Matches(html, SpanPatt)
            Dim tmp As New StringBuilder(m.Groups(4).Value)
            If m.Groups(1).Success Then 'bold
                tmp.Insert(0, bStart)
                tmp.Append(bEnd)
            End If
            If m.Groups(2).Success Then 'italic
                tmp.Insert(0, iStart)
                tmp.Append(iEnd)
            End If
            If m.Groups(3).Success Then 'underline
                tmp.Insert(0, uStart)
                tmp.Append(uEnd)
            End If
            sb.Replace(m.Value, tmp.ToString)
        Next
 
        Dim SPANmch As Match = Regex.Match(sb.ToString, SpanPatt, RegexOptions.IgnoreCase)
        Do While SPANmch.Success
            Dim tmp As New StringBuilder(SPANmch.Groups(4).Value)
            If SPANmch.Groups(1).Success Then 'bold
                tmp.Insert(0, bStart)
                tmp.Append(bEnd)
            End If
            If SPANmch.Groups(2).Success Then 'italic
                tmp.Insert(0, iStart)
                tmp.Append(iEnd)
            End If
            If SPANmch.Groups(3).Success Then 'underline
                tmp.Insert(0, uStart)
                tmp.Append(uEnd)
            End If
            sb.Replace(SPANmch.Value, tmp.ToString)
            SPANmch = Regex.Match(sb.ToString, SpanPatt, RegexOptions.IgnoreCase)
        Loop
 
        SPANmch = Regex.Match(sb.ToString, SpanPatt2, RegexOptions.IgnoreCase)
        Do While SPANmch.Success
            sb.Replace(SPANmch.Value, SPANmch.Groups(1).Value & "\par ")
            SPANmch = Regex.Match(sb.ToString, SpanPatt2, RegexOptions.IgnoreCase)
        Loop
 
        For Each m As Match In Regex.Matches(sb.ToString, STRONGpatt)
            sb.Replace(m.Value, bStart & m.Groups(1).Value & bEnd)
        Next
 
        For Each m As Match In Regex.Matches(sb.ToString, EMpatt)
            sb.Replace(m.Value, iStart & m.Groups(1).Value & iEnd)
        Next
 
        For Each m As Match In Regex.Matches(sb.ToString, PARpatt)
            sb.Replace(m.Value, "\par " & m.Groups(1).Value)
        Next
 
        For Each m As Match In Regex.Matches(sb.ToString, Upatt)
            sb.Replace(m.Value, uStart & m.Groups(1).Value & uEnd)
        Next
 
        '/////////////////////////////////////////////
        '////////////////numbered list////////////////
        '/////////////////////////////////////////////
 
        For Each m As Match In Regex.Matches(sb.ToString, BulletListPatt, RegexOptions.IgnoreCase)
            Dim tmp As New StringBuilder(m.Groups(1).Value)
            Dim i As Integer = 0
            For Each m1 As Match In Regex.Matches(tmp.ToString, ListPatt2, RegexOptions.IgnoreCase)
                Dim tmp1 As New StringBuilder(m1.Groups(1).Value)
                If i > 0 Then
                    tmp1.Insert(0, "{\pntext\f2\'B7\tab}")
                ElseIf i = 0 Then
                    tmp1.Insert(0, "{\*\pn\pnlvlblt\pnf2\pnindent5{\pntext\f2\'B7\tab}}\fi-200\li200 ")
                End If
                tmp1.Append("\par" & vbCrLf)
                tmp.Replace(m1.Value, tmp1.ToString)
                i += 1
            Next
            i = 0
            For Each m1 As Match In Regex.Matches(tmp.ToString, ListPatt, RegexOptions.IgnoreCase)
                Dim tmp1 As New StringBuilder(m1.Groups(4).Value)
                If i > 0 Then
                    tmp1.Insert(0, "{\pntext\f2\'B7\tab}")
                ElseIf i = 0 Then
                    tmp1.Insert(0, "{\*\pn\pnlvlblt\pnf2\pnindent5{\pntxtb\'B7}}\fi-200\li200 ")
                End If
                If m1.Groups(1).Success Then 'bold
                    tmp1.Insert(0, bStart)
                    tmp1.Append(bEnd)
                End If
                If m1.Groups(2).Success Then 'italic
                    tmp1.Insert(0, iStart)
                    tmp1.Append(iEnd)
                End If
                If m1.Groups(3).Success Then 'underline
                    tmp1.Insert(0, uStart)
                    tmp1.Append(uEnd)
                End If
                tmp1.Append("\par" & vbCrLf)
                tmp.Replace(m1.Value, tmp1.ToString)
                i += 1
            Next
            sb.Replace(m.Value, tmp.ToString & "\pard\par ")
        Next
 
        '///////////////////////////////////////////
        '////////////////numbered list//////////////
        '///////////////////////////////////////////
 
        For Each m As Match In Regex.Matches(sb.ToString, NumberListPatt, RegexOptions.IgnoreCase)
            Dim tmp As New StringBuilder(m.Groups(1).Value)
            Dim i As Integer = 0
            For Each m1 As Match In Regex.Matches(tmp.ToString, ListPatt2, RegexOptions.IgnoreCase)
                Dim tmp1 As New StringBuilder(m1.Groups(1).Value)
                If i > 0 Then
                    tmp1.Insert(0, "{\pntext\f1 " & i + 1 & ")\tab}")
                ElseIf i = 0 Then
                    tmp1.Insert(0, "{\pntext\f1 " & i + 1 & ")\tab}{\*\pn\pnlvlbody\pnf1\pnindent0\pnstart1\pndec{\pntxta)}}")
                End If
                tmp1.Append("\par" & vbCrLf)
                tmp.Replace(m1.Value, tmp1.ToString)
                i += 1
            Next
            i = 0
            For Each m1 As Match In Regex.Matches(tmp.ToString, ListPatt, RegexOptions.IgnoreCase)
                Dim tmp1 As New StringBuilder(m1.Groups(4).Value)
                If i > 0 Then
                    tmp1.Insert(0, "{\pntext\f1 " & i + 1 & ")\tab}")
                ElseIf i = 0 Then
                    tmp1.Insert(0, "{\pntext\f1 " & i + 1 & ")\tab}{\*\pn\pnlvlbody\pnf1\pnindent0\pnstart1\pndec{\pntxta)}}")
                End If
                If m1.Groups(1).Success Then 'bold
                    tmp1.Insert(0, bStart)
                    tmp1.Append(bEnd)
                End If
                If m1.Groups(2).Success Then 'italic
                    tmp1.Insert(0, iStart)
                    tmp1.Append(iEnd)
                End If
                If m1.Groups(3).Success Then 'underline
                    tmp1.Insert(0, uStart)
                    tmp1.Append(uEnd)
                End If
                tmp1.Append("\par" & vbCrLf)
                tmp.Replace(m1.Value, tmp1.ToString)
                i += 1
            Next
            sb.Replace(m.Value, tmp.ToString & "\pard\par ")
        Next
 
        '///////////////////////////////////////////
        '////////////////hyperlinks/////////////////
        '///////////////////////////////////////////
 
        Dim HyperlinkPatt As String = "<a (?:(?:style=""font-weight: bold;"")|(?:href=""(.*?)"")|\s*)>(.*?)</a>"
 
        For Each m As Match In Regex.Matches(sb.ToString, HyperlinkPatt, RegexOptions.IgnoreCase)
            sb.Replace(m.Value, "\cf1\ul " & m.Groups(1).Value & "\cf2\ulnone")
        Next
 
        For Each m As Match In Regex.Matches(sb.ToString, BRPatt, RegexOptions.IgnoreCase)
            sb.Replace(m.Value, "\par ")
        Next
 
        sb.Replace("<br>", "\par ")
        sb.Replace("<BR>", "\par ")
        sb.Replace(vbCrLf, "\par ")
        sb.Replace(vbLf, "\par ")
        sb.Replace(vbCr, "\par ")
 
        sb.Append("\f1\fs17}")
 
        Return sb.ToString
 
    End Function

Open in new window

0
 
CodeCruiserCommented:
I am not sure but may be you could use Word DLLs to open an HTML file and then save it as RTF.
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
Wayne Taylor (webtubbs)Author Commented:
Yeah, I thought of that, but it has the disadvantage of being really slow. I need to do this as quickly as possible.

Wayne
0
 
Bob LearnedCommented:
Wayne,

While I haven't had a need for HTML/RTF conversions, I have seen this CodeProject example.  It appears to be pretty thorough, and includes different .NET versions for 2005/2008, RTF to XML, RTF to HTML.

Writing Your Own RTF Converter
http://www.codeproject.com/KB/recipes/RtfConverter.aspx
0
 
Wayne Taylor (webtubbs)Author Commented:
Thanks Bob, but I'd be looking for HTML to RTF, which the CodeProject example doesn't support.

Do you know of a way to resize a WebBrowser control to fit the contents?

Wayne
0
 
Bob LearnedCommented:
Ok, ya got me on that one--I got it backwards (d'oh).

I have seen less on resizing the WebBrowser based on contents, then I have about converting from HTML to RTF.  

Is finding something commercial an option?  There are a few options out there which I have seen, but not used.
0
 
Wayne Taylor (webtubbs)Author Commented:
I'd rather not pay for this, as the application that will be using it is free also.

I just went searching, and came across this -> http://www.planet-source-code.com/vb/scripts/ShowCode.asp?lngWId=1&txtCodeId=27904

Problem is VS2005 is unable to convert it. Trying vs2008 now...
0
 
Wayne Taylor (webtubbs)Author Commented:
2008 converted it OK, but it doesn't seem to work. It seems to strip out all the formatting, returning plain text.
0
 
Bob LearnedCommented:
Wayne,

I probably came across that VB6 code before, and dismissed it, because you can do it differently in .NET, but it certainly looks like a place to start.  Not very elegant, but might get you to where you need to be.

Bob
0
 
Wayne Taylor (webtubbs)Author Commented:
Yeah, although it'll probably be easier for me to re-visit my function (http:#a22892853). For the most part it works, but has problems with bullets and numbered lists.

Wayne
0
 
Bob LearnedCommented:
This is what I found a while ago (that I forgot about)


Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Text
 
' Source:
' http://www.developer.com/net/vb/article.php/10926_1576561_3
 
Public Class RtfHtmlConverter
 
  ''' <summary>
  ''' Takes RichText and returns a simple HTML-formatted version.
  ''' </summary>
  ''' <remarks></remarks>
  Public Shared Function ConvertToHTML(ByVal rtf As String) As String
 
    ' If nothing in the formatter, exit
    If rtf.Length > 0 Then
      Const STYLE As String = "<span style=""font-family: {0}; font-size: {1}pt; color: {2}"">"
 
      Dim formatter As New RichTextBox()
      formatter.Rtf = rtf
 
      ' Store original selections, then select first character
      Dim startIndex As Integer = 0
      Dim length As Integer = formatter.TextLength
 
      formatter.Select(0, 1)
 
      Dim html As New StringBuilder()
 
      ' Add HTML header
      html.Append("<html>")
 
      ' Set up initial parameters
      Dim selectionColor As Color = formatter.SelectionColor
      Dim fontBold As Boolean = formatter.SelectionFont.Bold
      Dim fontItalic As Boolean = formatter.SelectionFont.Italic
      Dim fontName As String = formatter.SelectionFont.FontFamily.Name
      Dim fontSize As Integer = CInt(formatter.SelectionFont.Size)
 
      ' Include first 'style' parameters in the HTML
      html.AppendFormat(STYLE, fontName, fontSize, selectionColor)
 
      ' Include bold tag, if required
      If fontBold Then
        html.Append("<b>")
      End If
 
      ' Include italic tag, if required
      If fontItalic Then
        html.Append("<i>")
      End If
 
      ' Finally, add our first character
      html.Append(formatter.Text.Substring(0, 1))
      ' Loop around all remaining characters
      For index As Integer = 2 To formatter.Text.Length - 1
 
        ' Select current character
        formatter.Select(index - 1, 1)
        ' If this is a line break, add HTML tag
        If formatter.Text.Substring(index - 1, 1) = vbLf Then
          html.Append("<br>")
        End If
        ' Check/implement any changes in style
        If formatter.SelectionColor <> selectionColor Or _
           formatter.SelectionFont.FontFamily.Name <> fontName Or _
           formatter.SelectionFont.Size <> fontSize Then
          html.AppendFormat(STYLE, formatter.SelectionFont.FontFamily.Name, formatter.SelectionFont.Size, formatter.SelectionColor)
        End If
        ' Check for bold changes
        If formatter.SelectionFont.Bold <> fontBold Then
          If Not formatter.SelectionFont.Bold Then
            html.Append("</b>")
          Else
            html.Append("<b>")
          End If
        End If
 
        ' Check for italic changes
        If formatter.SelectionFont.Italic <> fontItalic Then
          If Not formatter.SelectionFont.Italic Then
            html.Append("</i>")
          Else
            html.Append("<i>")
          End If
        End If
 
        ' Add the actual character
        html.Append(formatter.Text.Substring(index, 1))
 
        ' Update variables with current style
        selectionColor = formatter.SelectionColor
        fontBold = formatter.SelectionFont.Bold
        fontItalic = formatter.SelectionFont.Italic
        fontName = formatter.SelectionFont.FontFamily.Name
        fontSize = CInt(formatter.SelectionFont.Size)
      Next index
 
      ' Close off any open bold/italic tags
      If fontBold Then
        html.Append("</b>")
      End If
 
      If fontItalic Then
        html.Append("</i>")
      End If
 
      ' Terminate outstanding HTML tags
      html.Append("</span></html>")
 
      ' Restore original RichTextformatter selection
      formatter.Select(startIndex, length)
 
      ' Return HTML
      Return html.ToString()
    End If
    Return ""
  End Function
 
End Class

Open in new window

0
 
CodeCruiserCommented:
@TheLearnedOne
You keep forgetting that Wayne needs to convert HTML to RTF and not RTF to HTML!!!!
0
 
Bob LearnedCommented:
Ok, I have my Mountain Dew on my desk, and I am going to start slugging it back, cuz I am not completely awake this morning (d'oh).
0

Featured Post

Get your Conversational Ransomware Defense e‑book

This e-book gives you an insight into the ransomware threat and reviews the fundamentals of top-notch ransomware preparedness and recovery. To help you protect yourself and your organization. The initial infection may be inevitable, so the best protection is to be fully prepared.

  • 6
  • 6
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now