sven liegeois
sven liegeois

Reputation: 39

Add formatting attributes from XML to text prior to use in a RichTextBox

My XML file stores paragraphs of text and has an attribute which defines what kind of paragraph it is.

For example :

  <Content>
    <Paragraph Type="Period">
      <Text>A long long time ago</Text>
    </Paragraph>
    <Paragraph Type="location">
      <Text>in a galaxy far, far away</Text>
    </Paragraph>
    <Paragraph Type="GeneralText">
      <Text>It is a period of civil war. Rebel spaceships, striking from a hidden base, ... Pursued by the Empire’s sinister agents, Princess Leia races home aboard her starship, custodian of the stolen plans that can save her people and restore freedom to the galaxy….</Text>
    </Paragraph>
    <Paragraph Type="location">
      <Text>And here's another location</Text>
    </Paragraph>
  </Content>

I am looking for a way to add certain attributes to the text when it is shown in a RichTextBox.

For instance, paragraph of type:

I know how to loop through the XML and how to retrieve the XML attributes and how to append each paragraph to a RichTextBox, but how do I add these formatting attributes?

Upvotes: 0

Views: 321

Answers (1)

Jimi
Jimi

Reputation: 32288

Some suggestions that may get you started.

▶ Use a class object to hold all the properties that your XML descriptors may require

▶ Pre-build a list of these objects that are known when the application is first built, with the option of editing their properties at both Design-Time and Run-Time, for customization purposes.

▶ Provide means to add more of these descriptors:

  • dynamically - reading the XML Attributes of a Type when the XML file is loaded
  • interactively - using the PropertyGrid to add elements to the collection of paragraph descriptors
  • programmatically - allowing to add elements with a custom interface when requested at Run-Time.

You could also have code that saves new descriptor objects (serialized to disc, added to User Settings etc.)

In the example, a Custom Control - derived from RichTextBox - contains all the logic required to load XML data from a known schema, assigns a Paragraph Type descriptor (using a class object, XmlDescriptor, for each Paragraph read).
Using this information, sends text to the RichTextBox container, formatting the new Selection with the parameters specified.

Note that the collection of XmlDescriptor objects is exposed through the ParagraphsDescriptors property. This collection can be edited using the PropertyGrid: you can modify existing descriptors or add new ones.
If you change the collection of descriptors, reload the XML to see the changes applied.

Use the custom RichTextBox LoadXml() method (passing an XML string or overload the method to also pass the path of a file) to load the XML and apply the styles.

Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Xml.Linq

<DesignerCategory("Code")>
Public Class RichTextBoxEx
    Inherits RichTextBox

    Private m_xmlContent As String = String.Empty

    Public Sub New()
        Me.ParagraphsDescriptors = New List(Of XmlDescriptor)({
            New XmlDescriptor("Period", HorizontalAlignment.Left, Color.Red, Color.LightYellow, 10, 20),
            New XmlDescriptor("Location", HorizontalAlignment.Center, Color.Brown, Color.Orange, 5, 0),
            New XmlDescriptor("GeneralText", HorizontalAlignment.Left, Color.White, Color.Black, 0, 0)
        })
    End Sub

    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
    Public Property ParagraphsDescriptors As List(Of XmlDescriptor)

    Public ReadOnly Property XmlContent As String
        Get
            Return m_xmlContent
        End Get
    End Property

    Public Function LoadXml(xml As String, Optional append As Boolean = False) As Boolean
        If (String.IsNullOrEmpty(xml)) Then Return False
        Try
            Dim xElm As XElement = XElement.Parse(xml)
            m_xmlContent = xml
            If (Not append) Then Me.Clear()
            For Each node As XElement In xElm.Elements.Where(Function(n) n.Name.LocalName.Equals("Paragraph"))
                Dim txt = node.Elements.FirstOrDefault(Function(elm) elm.Name.LocalName.Equals("Text"))
                If txt IsNot Nothing Then
                    AddParagraph(node.Attributes, txt.Value)
                End If
            Next
            Return True
        Catch ex As Exception
            MessageBox.Show($"LoadXml failed: {ex.Message}")
            Return False
        End Try
    End Function

    Public Sub AddParagraph(attributes As IEnumerable(Of XAttribute), text As String)
        Dim paragraphType = attributes.FirstOrDefault(Function(a) a.Name.LocalName.Equals("Type"))?.Value
        If String.IsNullOrEmpty(paragraphType) Then Throw New ArgumentException("ParagraphType")

        ' Parse the other Attributes, eventually, to map them to XmlDescriptor properties 
        Dim descriptor = ParagraphsDescriptors.FirstOrDefault(Function(d) d.ParagraphType.Equals(paragraphType))
        If descriptor Is Nothing Then descriptor = New XmlDescriptor(paragraphType)

        Dim selStart = Me.TextLength
        Me.AppendText(text + ChrW(10))
        Me.Select(selStart, text.Length)
        Me.SelectionAlignment = descriptor.Alignment
        Me.SelectionIndent = descriptor.LeftIndent
        Me.SelectionRightIndent = descriptor.RightIndent
        Me.SelectionBackColor = descriptor.BackColor
        Me.SelectionColor = descriptor.ForeColor
    End Sub

    <TypeConverter(GetType(ExpandableObjectConverter))>
    Public Class XmlDescriptor
        Public Sub New()
        End Sub

        Public Sub New(parName As String)
            ParagraphType = parName
        End Sub

        Public Sub New(parName As String, textAlign As HorizontalAlignment, bkColor As Color, textColor As Color, indentLeft As Integer, indentRight As Integer)
            ParagraphType = parName
            Alignment = textAlign
            BackColor = bkColor
            ForeColor = textColor
            LeftIndent = indentLeft
            RightIndent = indentRight
        End Sub

        Public Property ParagraphType As String = String.Empty
        Public Property Alignment As HorizontalAlignment = HorizontalAlignment.Left
        Public Property BackColor As Color = SystemColors.Window
        Public Property ForeColor As Color = SystemColors.ControlText
        Public Property LeftIndent As Integer = 0
        Public Property RightIndent As Integer = 0
    End Class
End Class

Upvotes: 1

Related Questions