[CONNECT Update 17 C#] Navigating a TextBlock

TextBlock Class

From the DgnPlatformNet help document: In the TextBlock DOM, this is the master object that represents a piece of text as a whole, and is the primary high-level object used to deal with multi-line, formatted text (and is also generally recommended for any text, regardless of complexity). As described in the Text module documentation, TextBlock consists of a DOM (Document Object Model). Elements of the DOM include Paragraph and Run objects. Internally, lines are also computed, but only affect layout, and are not directly exposed.

Where is the Text module documentation?

Navigating the Components of a TextBlock

I'm writing an example AddIn using C# and the DgnPlatformNet API.  I want to pick a text element, then show its text content.  However, I'm having trouble interpreting the TextBlock API and its component classes.  Unfortunately, examples are rare.

From an element that contains text I can get a TextBlock.  I want to enumerate its components to see their content.  What are the navigable components of a TextBlock?  There are carets, runs and paragraphs.  Which of those contains a string obtained from the text element?

Some of the API seems incomplete.  For example, the ParagraphIterator: An STL iterator-like wrapper around Caret, that allows you to easily iterate paragraphs. See notes on Caret as to why this is helpful.  That gives me a Paragraph enumerator: In the TextBlock DOM, a collection of lines and runs.  But Paragraph doesn't provide any method to obtain a line or run, so how is that supposed to work?

Parents
  • Hi ,

    Where is the Text module documentation?

    My modified version of those few words (to clarify) would be: Text (help module) documentation.

    Indicating to look to the "Text" help topic for an Overview of the Text (many forms) leading into the TextBlock API relationship details.

    The following are a few .NET unit tests I found, where you will need to modify any calls to Assert directly or simply ignore or handle each method or result accordingly.

    Code Snip: CreateTextElementTest

    public void CreateTextElementTest()
    {
    
        //Create a text block.
        TextBlock textBlock = new TextBlock(m_tbProps, m_pProps, m_runProps, m_defaultModel);
        textBlock.AppendText("Simple Text");
    
        //CREATE text element.
        TextElement textElement = (TextElement)TextHandlerBase.CreateElement(null, textBlock);
        Assert.AreEqual(StatusInt.Success, textElement.AddToModel());
    }

    Code Snip: CreateTextElementFromTextBlock

    /// <summary>
    /// Helper method for creating text element.
    /// </summary>
    /// <param name="model"></param>
    /// <param name="textBlock"></param>
    protected string CreateTextElementFromTextBlock(ref DgnModel model, ref TextBlock textBlock)
    {
        //CREATE text element.
        TextHandlerBase textElement = TextHandlerBase.CreateElement(null, textBlock);
        Assert.IsNotNull(textElement);
        Assert.AreEqual(true, textElement.IsTextElement);
    
        return (textElement.GetTextPart(textElement.GetTextPartIds (new TextQueryOptions()) [0])).ToString();
    }

    Code Snip: TextElement_CRUD_Test

    public void TextElement_CRUD_Test()
    {
    
        //Create a text block.
        TextBlock textBlock = new TextBlock (m_tbProps, m_pProps, m_runProps, m_defaultModel);
        textBlock.AppendText("Simple Text");
    
        //CREATE text element.
        TextElement textElement = (TextElement)TextHandlerBase.CreateElement(null, textBlock);
        textElement.AddToModel();
        Assert.IsNotNull(textElement);
        Assert.AreEqual(true, textElement.IsTextElement);
        Assert.AreEqual("Text", textElement.TypeName);
    
        //READ: We know this model contains a single text element.
        {
            //Read from current element.
            foreach (TextPartId tId in textElement.GetTextPartIds (new TextQueryOptions()))
            {
                TextBlock tBlock = textElement.GetTextPart(tId);
                Assert.IsNotNull(tBlock);
                Assert.AreEqual ("Simple Text", tBlock.ToString ());
            }
        }
    
        {
            //Read from model.
            foreach (Element element in m_defaultModel.GetGraphicElements())
            {
                if (element.TypeName.Equals("Text"))
                {
                    TextElement textEeh = (TextElement)element;
                    foreach (TextPartId tId in textEeh.GetTextPartIds (new TextQueryOptions()))
                    {
                        TextBlock tBlock = textEeh.GetTextPart(tId);
                        Assert.IsNotNull(tBlock);
                        Assert.AreEqual ("Simple Text", tBlock.ToString ());
                    }
                }
                else
                    Assert.Fail("This model should contain only one text element");
            }
        }
    
        //UPDATE text.
        TextEdit tEdit = textElement.AsTextEdit();
    
        TextPartIdCollection textParts = tEdit.GetTextPartIds (new TextQueryOptions());
        Assert.AreEqual(1, textParts.Count);
        TextPartId partId = textParts[0]; //We have confirmed that it contains one text part id.
        TextBlock textBlock2 = tEdit.GetTextPart(partId);
        Assert.AreEqual(false, textBlock2.IsEmpty);
        textBlock2.Remove(textBlock2.CreateStartCaret(), textBlock2.CreateEndCaret());
        Assert.AreEqual(true, textBlock2.IsEmpty);
        textBlock2.AppendText("This is updated text");
        Assert.AreEqual(false, textBlock2.IsEmpty);
        Assert.AreEqual(TextReplaceStatus.Success, tEdit.ReplaceTextPart(partId, textBlock2));
        tEdit.ReplaceInModel(textElement);
        Assert.AreEqual(StatusInt.Success, m_dgnFile.ProcessChanges(DgnSaveReason.ApplicationInitiated));
    
        //READ again: We know this model contains a single text element.
        {
            //Read from current element.
            foreach (TextPartId tId in tEdit.GetTextPartIds (new TextQueryOptions()))
            {
                TextBlock tBlock = tEdit.GetTextPart(tId);
                Assert.IsNotNull(tBlock);
                Assert.AreEqual ("This is updated text", tBlock.ToString ());
            }
        }
    
        {
            //Read from model.
            foreach (Element element in m_defaultModel.GetGraphicElements())
            {
                if (element.TypeName.Equals("Text"))
                {
                    TextElement textEeh = (TextElement)element;
                    foreach (TextPartId tId in textEeh.GetTextPartIds (new TextQueryOptions()))
                    {
                        TextBlock tBlock = textEeh.GetTextPart(tId);
                        Assert.IsNotNull(tBlock);
                        Assert.AreEqual ("This is updated text", tBlock.ToString ());
                    }
                }
                else
                    Assert.Fail("This model should contain only one text element");
            }
        }
    
        TextElement elemToDelete = null;
    
        //Read from model.
        foreach (Element element in m_defaultModel.GetGraphicElements())
        {
            if (element.TypeName.Equals("Text"))
            {
                elemToDelete = (TextElement)element;
            }
        }
    
        //We are sure that a text element exist in model.
        Assert.IsNotNull(elemToDelete);
    
        //DELETE:
        Assert.AreEqual(StatusInt.Success, textElement.DeleteFromModel());
        Assert.AreEqual(StatusInt.Success, m_dgnFile.ProcessChanges(DgnSaveReason.ApplicationInitiated));
    
    }

    Let me know if you need something more.

    HTH,
    Bob



  • From the DgnPlatformNet help document about TextBlock: In the TextBlock DOM, this is the master object that represents a piece of text as a whole, and is the primary high-level object used to deal with multi-line, formatted text (and is also generally recommended for any text, regardless of complexity).

    Given that the API appears to be incomplete, it is impossible for a developer to fully utilise the TextBlock API for interrogating elements that contain text.

    • Is there a timetable to improve the API? 
    • Who is responsible for the TextBlock API?
    Let me know if you need something more

    Someone needs to extend the TextBlock API so that its implementation matches its specification.

     
    Regards, Jon Summers
    LA Solutions

  • Bump!

    Given that the .NET API appears to be incomplete, it is impossible for a developer to fully utilise the TextBlock API for interrogating elements that contain text

    What plans are there to implement the .NET TextBlock in full?

     
    Regards, Jon Summers
    LA Solutions

  • Hi Jon,

    what exactly do you miss in available API? I did not do any detail comparison, but as far as I remember, I was always able to find solution for any task I implement, regardless to create or query/modify text.

    The only missing API I know are Text Fields.

    Regards,

      Jan

  • I was always able to find solution for any task

    There are examples above.   They show text nodes that contain text elements.  With .NET it's not possible to navigate to each text element using the TextBlock API.  In contrast, C++ lets us find paragraphs and runs.

     
    Regards, Jon Summers
    LA Solutions

  • Hi Jon,

    With .NET it's not possible to navigate to each text element using the TextBlock API.

    I am outside office, so I am not able to check my code archive, but I disagree it's not possible to navigate text elements. As far as I remember, using carets it's possible to analyze complete text and to find required piece of text.

    I see no problem to use carets only, but sometimes it requires to write a bunch of own code. But there are classes like paragraph iterator available, that makes navigating a bit simpler (but in fact the iterator is only a wrapper around, again, using carets).

    In contrast, C++ lets us find paragraphs and runs.

    I am not sure without consulting API and assemblies delivered with MicroStation, but I am pretty sure all important classes are available for a long time in API, including Run, RunIterator, Paragraph or ParagraphIterator (plus related properties classes).

    With regards,

      Jan

    Answer Verified By: Jon Summers 

Reply
  • Hi Jon,

    With .NET it's not possible to navigate to each text element using the TextBlock API.

    I am outside office, so I am not able to check my code archive, but I disagree it's not possible to navigate text elements. As far as I remember, using carets it's possible to analyze complete text and to find required piece of text.

    I see no problem to use carets only, but sometimes it requires to write a bunch of own code. But there are classes like paragraph iterator available, that makes navigating a bit simpler (but in fact the iterator is only a wrapper around, again, using carets).

    In contrast, C++ lets us find paragraphs and runs.

    I am not sure without consulting API and assemblies delivered with MicroStation, but I am pretty sure all important classes are available for a long time in API, including Run, RunIterator, Paragraph or ParagraphIterator (plus related properties classes).

    With regards,

      Jan

    Answer Verified By: Jon Summers 

Children
No Data