Update TextElements in C# .NET API (Microstation Connect)

I'm trying to get accustomed to the Connect's .net api and I am struggling to understand the TextElement/TextPart/TextBlock concept. Let's say I want to scan the entire drawing for a specific text string, here's my thinking so far:

1. Iterate the model.GetElements

2. Check for MSElementType.Text

3. Iterate cells for the same text object

4. Then on each textelement, I can do textElement.GetTextPartIds, so if this is a textnode with multiple elements, it will return multiple ids?

5. Then using the id I can get do the textElement.GetTextPart which returns a TextBlock.

Now, this is where I'm getting lost, so TextBlock.ToString() returns a string of that specific TextPart, but how do I update that TextPart?

I can see Append, Insert and ReplaceText functions, Replace is asking for caretStart and caretEnd, am I going down the right path? or is there a simpler way of doing this?

Thanks.

Parents
  • I am struggling to understand the TextElement/TextPart/TextBlock concept.

    The TextBlock API is a gateway to a DOM.  The DOM is an abstract description of text — whether that's a single piece of text or a number of pieces of text obtained from, say, a text node.  The API converts text from a DGN element to construct a TextBlock.  From a TextBlock you can construct a suitable DGN element.

    Unfortunately the DOM is invisible.  The only way to navigate it is via the API.

    The DgnPlatformNet help document does not help.  However, always keep in mind Jan's advice: When the .NET documentation lacks detail, turn to the MicroStationAPI help document.  At first sight, the MicroStationAPI help document does not help.  The TextBlock Struct Reference topic is terse.  However, hidden in the section deprecated10_0.fdf File Reference are many examples of TextBlock programming. 

    Replace is asking for caretStart and caretEn

    Imagine you're looking at an XML file that describes multi-part text.  Those carets are a way to point at the start and end of pieces of text within that structure.

     
    Regards, Jon Summers
    LA Solutions

  • Thanks Jon, so I had a little bit of time to look into this again, so far the DOM concept makes sense, but the updating back to model doesn't seem to work. Here's an example method that I'm trying to update existing textelement to have a test phrase in it. I'm using the first text part by default and not iterating anything deeper just for this test purpose.

    private Element UpdateTextElement(TextElement t)
            {
                var tq = new TextQueryOptions() { ShouldIncludeEmptyParts = false, ShouldRequireFieldSupport = false };
    
                TextEdit textEdit = t.AsTextEdit();
                TextBlock tb = t.GetTextPart(t.GetTextPartIds(tq)[0]);
    
                tb.Remove(tb.CreateStartCaret(), tb.CreateEndCaret());
                tb.InsertText(tb.CreateStartCaret(), "This is a long test");
    
                if (TextReplaceStatus.Success == t.ReplaceTextPart(t.GetTextPartIds(tq)[0], tb))
                {
                    textEdit.ReplaceInModel(t);
                }
                return t;
            }

    I get an error "Bad StatusInt: 32768" on line textEdit.ReplaceInModel(t);

    Any help is appreciated.

    Thanks.

  • I get an error "Bad StatusInt: 32768" on line textEdit.ReplaceInModel(t);

    It is what I remember from my previous testing.

  • I get an error "Bad StatusInt: 32768" on line textEdit.ReplaceInModel(t)

    That could be a quite different bug, which you solve like this...

    /// This is a workaround because Element.ReplaceInModel causes MicroStation to abort.
    /// See communities.bentley.com/.../579796
    /// param name="modifiedElement"
    /// param name="original"
    private void ReplaceInModel(ref Element modifiedElement, Element original)
    {
      Element oldElem = Element.GetFromElementRef(original.GetNativeElementRef()); ;
      modifiedElement.ReplaceInModel(oldElem);
    }
    

     
    Regards, Jon Summers
    LA Solutions

  • Ok, so this works, i think the concept makes sense with getting the native element and then doing the replacement on it, but it does make my brain hurt. Am I understanding this right, that iterating through Model.GetElements doesn't give you access to the actual elements (writable), so if you make any changes to them the changes need to be written back to the actual element which you get by Element.GetFromElementRef?

     if (elem.ElementType == MSElementType.Text)
                    {
                       
                        var tq = new TextQueryOptions() { ShouldIncludeEmptyParts = false, ShouldRequireFieldSupport = false };
                        var t = (TextElement)elem;
    
                        TextElement origElem = (TextElement)Element.GetFromElementRef(elem.GetNativeElementRef());
    
                        TextBlock tb = t.GetTextPart(t.GetTextPartIds(tq)[0]);
    
                        tb.Remove(tb.CreateStartCaret(), tb.CreateEndCaret());
                        tb.InsertText(tb.CreateStartCaret(), "This is a long test");
    
                        if (TextReplaceStatus.Success == t.ReplaceTextPart(t.GetTextPartIds(tq)[0], tb))
                        {
                            t.ReplaceInModel(origElem);
    
                        }
                        
                    }

Reply
  • Ok, so this works, i think the concept makes sense with getting the native element and then doing the replacement on it, but it does make my brain hurt. Am I understanding this right, that iterating through Model.GetElements doesn't give you access to the actual elements (writable), so if you make any changes to them the changes need to be written back to the actual element which you get by Element.GetFromElementRef?

     if (elem.ElementType == MSElementType.Text)
                    {
                       
                        var tq = new TextQueryOptions() { ShouldIncludeEmptyParts = false, ShouldRequireFieldSupport = false };
                        var t = (TextElement)elem;
    
                        TextElement origElem = (TextElement)Element.GetFromElementRef(elem.GetNativeElementRef());
    
                        TextBlock tb = t.GetTextPart(t.GetTextPartIds(tq)[0]);
    
                        tb.Remove(tb.CreateStartCaret(), tb.CreateEndCaret());
                        tb.InsertText(tb.CreateStartCaret(), "This is a long test");
    
                        if (TextReplaceStatus.Success == t.ReplaceTextPart(t.GetTextPartIds(tq)[0], tb))
                        {
                            t.ReplaceInModel(origElem);
    
                        }
                        
                    }

Children
No Data