Connect Version 13 C# - tag element question

I created a program that uses tags, I have no problem creating the tags and assigning them to elements.  My question is how to update a tag's value when it already exists in the design file.

The following is a section from my code, I know that I am accessing the tag's value because I added a print statement to show me the tag's current value.

MessageBox1.Text = MessageBox1.Text + "current tag value: " + tagEl.GetTagValue().ToString() + "\n";
//First tried changing the value using the following                            
tagEl.SetTagValue(chStr);

//Then tried changing the value using the following
TextQueryOptions textQueryOptions = new TextQueryOptions
{
    ShouldIncludeEmptyParts = false,
    ShouldRequireFieldSupport = false
};

TextPartIdCollection textParts = tagEl.GetTextPartIds(textQueryOptions);
TextPartId textPart = textParts[0];
TextBlock txtBlock = tagEl.GetTextPart(textPart);
Caret startCaret = txtBlock.CreateStartCaret();
Caret endCaret = txtBlock.CreateEndCaret();
txtBlock.ReplaceText(chStr, startCaret, endCaret);
tagEl.ReplaceTextPart(textPart, txtBlock);

Do I have to clone the tag element, make the changes and then replace the current tag with the clone tag that has the changes?

Thank you for any suggestions!

Donna

Parents
  • Do I have to clone the tag element...
    //Then tried changing the value using the following
    TextQueryOptions textQueryOptions = new TextQueryOptions

    A TagElement is not a TextElement. A TextElement contains only text, whereas a TagElement can contain text, a numeric value or a chunk of memory (typically an image).  You should use the tag API to change a tag's value.

    The idiom for modifying an element is to get the element, make a copy, modify the copy, then replace the original.  That way your edit fits nicely with MicroStation's undo logic.  This article discusses tags in the context of the VBA API.  Another article provides a complete VBA project for replacing tags (and text) in a DGN model.

     
    Regards, Jon Summers
    LA Solutions

  • Hi Jon,

    The first method I tried (as shown in my code) was using a tag API.  A tag has text parts.  I am writing in C# and using the API's from Bentley.DgnPlatformNET

    tagEl.SetTagValue(chStr);

    I check the tag's value after the code above is run using a TextBlock and it was updated correctly. I just can't permanently save the change to the tag?  Using the Element.ReplaceInModel API throws an exception error.

    I previously wrote the program in VB.Net and it works, but runs much slower.  This is the only part that I haven't been able to get working in C# rewrite.

    Donna

  • Hi Donna,

    Using the Element.ReplaceInModel API throws an exception error.

    This call is not in the shared code. How exactly do you call the method (with a parameter or with null)?

    With regards,

      Jan

  • Hi Jan,

    I was calling it with the tag element in the (), which gives me an error.  If I call it with (null), it creates a duplicate tag with the new value.  It doesn't replace the value.

    tagEl.SetTagValue(chStr);
    tagEl.ReplaceInModel(tagEl);  // error thrown
    
    
    tagEl.SetTagValue(chStr);
    tagEl.ReplaceInModel(null);   // no error thrown, but get a duplicate tag with incorrect attributes 

    SHEETNO is being updated from 2 to 102, in the properties dialog, you can see how it created a second tag instance.  I just want to replace the value.

    Donna

  • I was calling it with the tag element in the (), which gives me an error. 

    I think this is the right way, but probably there is an internal bug in API when used with TagElement. I am not sure, and I do not recall whether it was confirmed by Bentley or not.

    With regards,

      Jan

  • Hi Jan,

    It is very frustrating working with the new API's and limited documentation.  I think you are right, there must be a bug in the API.  It seems like it should be rather straight forward, in that it should Replace the existing with the new value.  I want it to keep the attributes of the existing value and just update it with the new value.

    Donna

  • Hi Donna,

    It is very frustrating working with the new API's and limited documentation.

    well, that's true unfortunately. On the other hand, my experience is that using C++ API documentation and search this forum (plus blogs in some cases), a solution can be found quickly. Bugs or incomplete implementation comparing to native API is now bigger problem.

    there must be a bug in the API.

    Yes, it is.

    When I tried to catch the exception, I received

    Bentley.DgnPlatformNET.DgnPlatformNETException: 'Bad StatusInt: 32768'

    but without knowing a source code, it's hard to guess what is wrong.

    and just update it with the new value.

    I think the only workaround now is to use Interop API. It's quite simple, just find your tag(s) in new API and using element id, get it in Interop. Not elegant, but it should work (but I did not test it whether the same bug exists also in COM). Still easier than to call native TagElementHandler I guess.

    Unfortunately MStnTag base EC class, used for TagElement EC definition, defines TagValue as read-only, so the value cannot be changed using EC API (which in standard and simple way how to change elements properties).

    , any insight or comment? Thanks :-)

    With regards,

      Jan

  • Hi Jan,

    I appreciate your efforts!!  I looked at the mdl functions thinking that I could use the dll import for it.  I am hoping to get an answer from Bentley.  Why offer the Replace API and Set Value if they don't work?  I am hoping it is user error!

    I included the source code, although it is just a portion of the package.

            /******************************************************************************************************************************
                ProcessTag
            ******************************************************************************************************************************/
            private void ProcessTagElement(int rowIndex, BDPN.Elements.TagElement tagEl, string keyName, Dictionary<string, int> columnList, Dictionary<string, bool> fndTagList)
            {
                if (columnList.ContainsKey(keyName))
                {
                    columnList.TryGetValue(keyName, out int colIndex);
                    Worksheet setTagSheet = (Worksheet)ExcelApp.Worksheets[tagSheetInd];
                    setTagSheet.Activate();
                    Range exCell = setTagSheet.Cells[rowIndex, colIndex];
                    int colorNumber = System.Convert.ToInt32(exCell.Interior.Color);
                    if (!colorNumber.Equals(tagsNoProcessColor) && colIndex >= 3)
                    {
                        if (ExcelTagValuestoMS.Checked)
                        {
                            string chStr = "";
                            if (exCell.Value != null)
                            {
                                chStr = exCell.Value.ToString();
                            }
    
                            //MessageBox1.Text = MessageBox1.Text + "ProcessTagElement keyName: " + keyName + "\n";
                            //MessageBox1.Text = MessageBox1.Text + "ProcessTagElement chStr: " + chStr + "\n";
    
                            int len = 0;
                            if (chStr != "")
                            {
                                chStr = chStr.Trim();
                                len = chStr.Length;
                            }
    
                            if (len == 1 && keyName.Equals("District"))
                                tagEl.SetTagValue("0" + chStr);
                            else if (len > 17 && (keyName.Equals("FUNCAREA") || keyName.Equals("FunctionalArea")))
                            {
                                tagEl.SetTagValue(chStr.ToUpper());
                                tagEl.ReplaceInModel(null);
                            }
                            else if (keyName.Equals("PLNAD") || keyName.Equals("PlansApprovalDate"))
                            {
                                // Date must be spelled out - example: March 3, 2012 (no leading zero for a single digit day)
                                string[] formats = { "M/d/yyyy", "M/dd/yyyy", "MM/d/yyyy", "MM/dd/yyyy" };
    
                                if (chStr.Contains("/") || chStr.Contains("\\"))
                                {
                                    if (DateTime.TryParseExact(chStr, formats, new CultureInfo("en-US"), DateTimeStyles.None, out DateTime dateValue))
                                    {
                                        chStr = dateValue.ToLongDateString();
                                    }
                                }
                                tagEl.SetTagValue(chStr);
                                tagEl.ReplaceInModel(null);
                            }
                            else
                            {
                                //MessageBox1.Text = MessageBox1.Text + "current tag value: " + tagEl.GetTagValue().ToString() + "\n";
                                tagEl.SetTagValue(chStr);
                                //MessageBox1.Text = MessageBox1.Text + "updated tag value: " + tagEl.GetTagValue().ToString() + "\n";
                                tagEl.ReplaceInModel(null);     // Duplicates element in the file, doesn't Replace
                            }
                        }
                        else if (DGNTagValuesToExcel.Checked)
                        {
                            // write dgn tag value to Excel cell
                            exCell.Value = tagEl.GetTagValue().ToString();
                            ExcelApp.ActiveWorkbook.Save();
                        }
                        else if (ClearDGNTagValues.Checked)
                        {
                            //clear tag value
                            tagEl.SetTagValue("");
                        }
                    }
                    if (fndTagList.ContainsKey(keyName))
                    {
                        fndTagList.Remove(keyName);
                        fndTagList.Add(keyName, true);
                    }
                }
            }

    Thank you,

    Donna

Reply
  • Hi Jan,

    I appreciate your efforts!!  I looked at the mdl functions thinking that I could use the dll import for it.  I am hoping to get an answer from Bentley.  Why offer the Replace API and Set Value if they don't work?  I am hoping it is user error!

    I included the source code, although it is just a portion of the package.

            /******************************************************************************************************************************
                ProcessTag
            ******************************************************************************************************************************/
            private void ProcessTagElement(int rowIndex, BDPN.Elements.TagElement tagEl, string keyName, Dictionary<string, int> columnList, Dictionary<string, bool> fndTagList)
            {
                if (columnList.ContainsKey(keyName))
                {
                    columnList.TryGetValue(keyName, out int colIndex);
                    Worksheet setTagSheet = (Worksheet)ExcelApp.Worksheets[tagSheetInd];
                    setTagSheet.Activate();
                    Range exCell = setTagSheet.Cells[rowIndex, colIndex];
                    int colorNumber = System.Convert.ToInt32(exCell.Interior.Color);
                    if (!colorNumber.Equals(tagsNoProcessColor) && colIndex >= 3)
                    {
                        if (ExcelTagValuestoMS.Checked)
                        {
                            string chStr = "";
                            if (exCell.Value != null)
                            {
                                chStr = exCell.Value.ToString();
                            }
    
                            //MessageBox1.Text = MessageBox1.Text + "ProcessTagElement keyName: " + keyName + "\n";
                            //MessageBox1.Text = MessageBox1.Text + "ProcessTagElement chStr: " + chStr + "\n";
    
                            int len = 0;
                            if (chStr != "")
                            {
                                chStr = chStr.Trim();
                                len = chStr.Length;
                            }
    
                            if (len == 1 && keyName.Equals("District"))
                                tagEl.SetTagValue("0" + chStr);
                            else if (len > 17 && (keyName.Equals("FUNCAREA") || keyName.Equals("FunctionalArea")))
                            {
                                tagEl.SetTagValue(chStr.ToUpper());
                                tagEl.ReplaceInModel(null);
                            }
                            else if (keyName.Equals("PLNAD") || keyName.Equals("PlansApprovalDate"))
                            {
                                // Date must be spelled out - example: March 3, 2012 (no leading zero for a single digit day)
                                string[] formats = { "M/d/yyyy", "M/dd/yyyy", "MM/d/yyyy", "MM/dd/yyyy" };
    
                                if (chStr.Contains("/") || chStr.Contains("\\"))
                                {
                                    if (DateTime.TryParseExact(chStr, formats, new CultureInfo("en-US"), DateTimeStyles.None, out DateTime dateValue))
                                    {
                                        chStr = dateValue.ToLongDateString();
                                    }
                                }
                                tagEl.SetTagValue(chStr);
                                tagEl.ReplaceInModel(null);
                            }
                            else
                            {
                                //MessageBox1.Text = MessageBox1.Text + "current tag value: " + tagEl.GetTagValue().ToString() + "\n";
                                tagEl.SetTagValue(chStr);
                                //MessageBox1.Text = MessageBox1.Text + "updated tag value: " + tagEl.GetTagValue().ToString() + "\n";
                                tagEl.ReplaceInModel(null);     // Duplicates element in the file, doesn't Replace
                            }
                        }
                        else if (DGNTagValuesToExcel.Checked)
                        {
                            // write dgn tag value to Excel cell
                            exCell.Value = tagEl.GetTagValue().ToString();
                            ExcelApp.ActiveWorkbook.Save();
                        }
                        else if (ClearDGNTagValues.Checked)
                        {
                            //clear tag value
                            tagEl.SetTagValue("");
                        }
                    }
                    if (fndTagList.ContainsKey(keyName))
                    {
                        fndTagList.Remove(keyName);
                        fndTagList.Add(keyName, true);
                    }
                }
            }

    Thank you,

    Donna

Children