I'm working in ORD 2021 R1. Wondering if there is any way to remove individual annotation groups from the cross sections? I originally annotated all drawing models with EAV and have ultimately decided I wanted to remove it. We can add individual annotation groups to all drawing models but I don't see a way to remove individual groups, only remove all groups at once. Does anyone have a workaround for this?
Hi Matt,
There is a way to do this via VBA. As every Annotation Group placement instance has a unique Named Group, you can use vba to get the Named Group from a selected element and delete all elements that are part of the same one. You could then get it to iterate through all Drawing models to delete other instances of it.
Unfortunately no native tools for this...yet.
Regards,
Mark
OpenRoads Designer 2022 R3 (10.12) | Microstation 2023 | ProjectWise CE 3.4
The VBA code below should do what you need. To run:
Sub deleteAnnoAll() Dim oScanEnumerator As ElementEnumerator, oScanEnumerator0 As ElementEnumerator, ph As PropertyHandler Dim oGroupName As String, ph0 As PropertyHandler, oElement As Element, oSelected As Element, oModel As ModelReference If ActiveModelReference.Type = msdModelTypeDrawing Then For Each oModel In ActiveDesignFile.Models If oModel.Type = msdModelTypeDrawing Then countDrawings = countDrawings + 1 End If Next If ActiveModelReference.AnyElementsSelected = False Then CadInputQueue.SendCommand "beep" ShowMessage "ERROR - No elements selected", , msdMessageCenterPriorityError, True GoTo finish Else Set oScanEnumerator0 = ActiveModelReference.GetSelectedElements oScanEnumerator0.MoveNext Set oSelected = oScanEnumerator0.Current If oSelected.ModelReference.IsAttachment = False And oSelected.ModelReference.Name = ActiveModelReference.Name Then Set ph0 = CreatePropertyHandler(oSelected) If ph0.SelectByAccessString("Groups[0].Description") = True Then oSearch = InStr(ph0.GetDisplayString, "\") oGroupName = Left(ph0.GetDisplayString, oSearch) If ph0.GetDisplayString = "" Then CadInputQueue.SendCommand "beep" ShowMessage "ERROR - Selected element is not Civil Annotation", , msdMessageCenterPriorityError, True GoTo finish End If Else CadInputQueue.SendCommand "beep" ShowMessage "ERROR - Selected element is not Civil Annotation", , msdMessageCenterPriorityError, True GoTo finish End If Else CadInputQueue.SendCommand "beep" ShowMessage "ERROR - Only elements in active model can be used for this tool", , msdMessageCenterPriorityError, True GoTo finish End If ' Save current model name 'currMod = ActiveModelReference.Name Dim oScanCriteria As New ElementScanCriteria ' Cycle through models and delete matching annotation group elements For Each oModel In ActiveDesignFile.Models If oModel.Type = msdModelTypeDrawing Then totmodels = totmodels + 1 count1 = 0 oScanCriteria.IncludeOnlyVisible oScanCriteria.ExcludeNonGraphical Set oScanEnumerator = oModel.Scan(oScanCriteria) oRun = 1 'oModel.Activate ShowTempMessage msdStatusBarAreaMiddle, "Processing Drawing model " + CStr(totmodels) + " of " + CStr(countDrawings) + "..." Do While oScanEnumerator.MoveNext Set oElement = oScanEnumerator.Current countTot = countTot + 1 If oElement.IsGraphical = True And oElement.ModelReference.Name = oModel.Name And oElement.ModelReference.IsAttachment = False Then Set ph = CreatePropertyHandler(oElement) If ph.SelectByAccessString("Groups[0].Description") = True Then oSearch = "" oSearch = InStr(ph.GetDisplayString, "\") oNew = Left(ph.GetDisplayString, oSearch) If StrComp(oNew, oGroupName, vbBinaryCompare) = 0 Then oModel.RemoveElement oElement count = count + 1 count1 = count + 1 End If End If End If Loop If count1 > 0 Then countMod = countMod + 1 End If End If Set oElement = Nothing Set oModel = Nothing Set oScanEnumerator = Nothing Next ' Return to original model 'ActiveDesignFile.Models(currMod).Activate CadInputQueue.SendCommand "beep" If count > 0 Then ShowMessage CStr(count) + " total annotation element(s) deleted from " + CStr(countMod) + " Drawing models." & vbNewLine & vbNewLine + "Removed Annotation Group: " + vbNewLine + Left(ph0.GetDisplayString, oSearch - 1), , msdMessageCenterPriorityInfo, True Else ShowMessage "No associated Civil Annotation found in any Drawing models", , msdMessageCenterPriorityWarning, True End If End If Else CadInputQueue.SendCommand "beep" ShowMessage "ERROR - Tool can only be run in a Drawing model", , msdMessageCenterPriorityError, True End If GoTo finish skip: finish: CommandState.StartDefaultCommand Exit Sub End Sub
Hi Mark,
First of all, thanks for sharing this solution! I'm looking at making use of this to remove some annotation groups. However, my issue is that all of my drawing models are in separate DGNs, so I'm going to try to run this with a batch process. This means I won't be able to select the annotations to be deleted with a mouse click...
How might I modify the code to target a certain annotation group (e.g. "Design Annotations\XS Edge of Pavement\e6dc4e75-6ea0-4131-91f4-f27c47592154", but replace the last part of the string with wildcard?) so that the process of selecting an element from a group is bypassed? Can this be done?
Thanks very much,
Andrew
Hi Andrew,
No dramas at all, this should be possible by changing the oGroup variable to this value and then have the if statement on line 80 check the left characters of oNew match for the number of characters in oGroup. You'll just need to remove parts of the code that check for data from a selected element.
I'll see if I can post what that would look like first chance tomorrow or so.
Mark,
I'm relatively green at MicroStation VBA (and VBA in general), but after some self-study, I was able to understand most of what's going on here. I made some changes, and it worked great.
For now, I have to hard code the name of the annotation group. As I learn more VBA, I might try to set something up that lets the user pick from a list of annotation groups that exist in the cross-section container DGN. Guessing I would have to nest the batch process inside the procedure somewhere after the user picks the annotation group to remove.
Sub deleteAnnoEOP() Dim oScanEnumerator As ElementEnumerator, oScanEnumerator0 As ElementEnumerator, ph As PropertyHandler Dim oGroupName As String, ph0 As PropertyHandler, oElement As Element, oSelected As Element, oModel As ModelReference If ActiveModelReference.Type = msdModelTypeDrawing Then For Each oModel In ActiveDesignFile.Models If oModel.Type = msdModelTypeDrawing Then countDrawings = countDrawings + 1 End If Next 'Set oScanEnumerator0 = ActiveModelReference.GetSelectedElements 'oScanEnumerator0.MoveNext 'Set oSelected = oScanEnumerator0.Current 'If oSelected.ModelReference.IsAttachment = False And oSelected.ModelReference.Name = ActiveModelReference.Name Then 'Set ph0 = CreatePropertyHandler(oSelected) ' If ph0.SelectByAccessString("Groups[0].Description") = True Then 'oSearch = InStr(ph0.GetDisplayString, "\") oGroupName = "Design Annotations\XS Edge of Pavement\" 'If ph0.GetDisplayString = "" Then ' CadInputQueue.SendCommand "beep" 'ShowMessage "ERROR - Selected element is not Civil Annotation", , msdMessageCenterPriorityError, True ' GoTo finish 'End If 'Else 'CadInputQueue.SendCommand "beep" ' ShowMessage "ERROR - Selected element is not Civil Annotation", , msdMessageCenterPriorityError, True 'GoTo finish ' End If 'Else 'CadInputQueue.SendCommand "beep" 'ShowMessage "ERROR - Only elements in active model can be used for this tool", , msdMessageCenterPriorityError, True 'GoTo finish 'End If ' Save current model name 'currMod = ActiveModelReference.Name Dim oScanCriteria As New ElementScanCriteria ' Cycle through models and delete matching annotation group elements For Each oModel In ActiveDesignFile.Models If oModel.Type = msdModelTypeDrawing Then totmodels = totmodels + 1 count1 = 0 oScanCriteria.IncludeOnlyVisible oScanCriteria.ExcludeNonGraphical Set oScanEnumerator = oModel.Scan(oScanCriteria) oRun = 1 'oModel.Activate ShowTempMessage msdStatusBarAreaMiddle, "Processing Drawing model " + CStr(totmodels) + " of " + CStr(countDrawings) + "..." Do While oScanEnumerator.MoveNext Set oElement = oScanEnumerator.Current countTot = countTot + 1 If oElement.IsGraphical = True And oElement.ModelReference.Name = oModel.Name And oElement.ModelReference.IsAttachment = False Then Set ph = CreatePropertyHandler(oElement) If ph.SelectByAccessString("Groups[0].Description") = True Then oSearch = "" oSearch = InStrRev(ph.GetDisplayString, "\") oNew = Left(ph.GetDisplayString, oSearch) If StrComp(oNew, oGroupName, vbBinaryCompare) = 0 Then oModel.RemoveElement oElement Count = Count + 1 count1 = Count + 1 End If End If End If Loop If count1 > 0 Then countMod = countMod + 1 End If End If Set oElement = Nothing Set oModel = Nothing Set oScanEnumerator = Nothing Next ' Return to original model 'ActiveDesignFile.Models(currMod).Activate Else CadInputQueue.SendCommand "beep" ShowMessage "ERROR - Tool can only be run in a Drawing model", , msdMessageCenterPriorityError, True End If GoTo finish skip: finish: CommandState.StartDefaultCommand Exit Sub End Sub
This is great, Mark. Thanks for this. It saves a huge amount of time, as now it takes just a couple seconds to run through 20 or so models. I made a few changes that I think I'll capture here:
* I revised some variable names to make them more explicit as to their purpose.
* I added declaration lines because I use Option Explicit.
* I changed ShowMessage to MsgBox because VBA was telling me the function wasn't working, but I changed nothing else about those lines.
* I added a loop to cycle through all of the user's initial selection set rather than just the first one. (This is a less important improvement because the alternative is that the user would simply run the script multiple times according to the selection set.)
At the top I mentioned this thread's URL for reference.
Sub deleteAnnoInAllModelsOfSameFile() 'substantially identical to the script that Mark Shamoun offered here: _ https://communities.bentley.com/products/road___site_design/f/geopak-inroads-mx-openroads-forum/228930/remove-individual-annotation-groups/709368 _ but with some variable names changed and a loop introduced to cycle through all of the user's selection set instead of just the first element's group Dim oScanEnumerator As ElementEnumerator, eeInitialSelection As ElementEnumerator, ph As PropertyHandler Dim oGroupName As String, ph0 As PropertyHandler, oElement As Element, oSelected As Element, oModel As ModelReference Dim count_drawing_models As Long Dim oSearch As String, oNew As String Dim totModels As Long Dim count_within_Model As Long, count_total_deleted As Long, count_annotation_elements As Long Dim count_Model_affected As Long Dim oRun As Long If ActiveModelReference.Type = msdModelTypeDrawing Then For Each oModel In ActiveDesignFile.Models If oModel.Type = msdModelTypeDrawing Then count_drawing_models = count_drawing_models + 1 End If Next If ActiveModelReference.AnyElementsSelected = False Then CadInputQueue.SendCommand "beep" ShowMessage "ERROR - No elements selected", , msdMessageCenterPriorityError, True GoTo finish Else Set eeInitialSelection = ActiveModelReference.GetSelectedElements Do While eeInitialSelection.MoveNext Set oSelected = eeInitialSelection.Current If oSelected.ModelReference.IsAttachment = False And oSelected.ModelReference.Name = ActiveModelReference.Name Then Set ph0 = CreatePropertyHandler(oSelected) If ph0.SelectByAccessString("Groups[0].Description") = True Then oSearch = InStr(ph0.GetDisplayString, "\") oGroupName = Left(ph0.GetDisplayString, oSearch) If ph0.GetDisplayString = "" Then CadInputQueue.SendCommand "beep" ShowMessage "ERROR - Selected element is not Civil Annotation", , msdMessageCenterPriorityError, True GoTo finish End If Else CadInputQueue.SendCommand "beep" ShowMessage "ERROR - Selected element is not Civil Annotation", , msdMessageCenterPriorityError, True GoTo finish End If Else CadInputQueue.SendCommand "beep" ShowMessage "ERROR - Only elements in active model can be used for this tool", , msdMessageCenterPriorityError, True GoTo finish End If ' Save current model name 'currMod = ActiveModelReference.Name Dim oScanCriteria As New ElementScanCriteria ' Cycle through models and delete matching annotation group elements For Each oModel In ActiveDesignFile.Models If oModel.Type = msdModelTypeDrawing Then totModels = totModels + 1 count_within_Model = 0 oScanCriteria.IncludeOnlyVisible oScanCriteria.ExcludeNonGraphical Set oScanEnumerator = oModel.Scan(oScanCriteria) oRun = 1 'oModel.Activate ShowTempMessage msdStatusBarAreaMiddle, "Processing Drawing model " + CStr(totModels) + " of " + CStr(count_drawing_models) + "..." Do While oScanEnumerator.MoveNext Set oElement = oScanEnumerator.Current count_total_deleted = count_total_deleted + 1 If oElement.IsGraphical = True And oElement.ModelReference.Name = oModel.Name And oElement.ModelReference.IsAttachment = False Then Set ph = CreatePropertyHandler(oElement) If ph.SelectByAccessString("Groups[0].Description") = True Then oSearch = "" oSearch = InStr(ph.GetDisplayString, "\") oNew = Left(ph.GetDisplayString, oSearch) If StrComp(oNew, oGroupName, vbBinaryCompare) = 0 Then oModel.RemoveElement oElement 'TODO: reactivate this count_annotation_elements = count_annotation_elements + 1 count_within_Model = count_within_Model + 1 'TODO: should this be count_annotation_elements ? End If End If End If Loop If count_within_Model > 0 Then count_Model_affected = count_Model_affected + 1 End If End If Set oElement = Nothing Set oModel = Nothing Set oScanEnumerator = Nothing Next ' Return to original model 'ActiveDesignFile.Models(currMod).Activate CadInputQueue.SendCommand "beep" If count_annotation_elements > 0 Then MsgBox CStr(count_annotation_elements) & " total annotation element(s) deleted from " & CStr(count_Model_affected) & " Drawing models." _ & vbNewLine _ & vbNewLine & "Removed Annotation Group: " _ & vbNewLine & Left(ph0.GetDisplayString, oSearch - 1) _ , , msdMessageCenterPriorityInfo, True Else MsgBox "No associated Civil Annotation found in any Drawing models", , msdMessageCenterPriorityWarning, True End If Loop 'eeInitialSelection.MoveNext End If Else CadInputQueue.SendCommand "beep" ShowMessage "ERROR - Tool can only be run in a Drawing model", , msdMessageCenterPriorityError, True End If GoTo finish skip: finish: CommandState.StartDefaultCommand Exit Sub End Sub
Awesome Derek, looks good.
I'm thinking of enhancing this to provide a dialog with a list of currently found Annotation Group instances instead of needing to pre-select an element from a group as another option. Hopefully will have that done in the not too distant future.
This looks like a great solution. I didn't find this on the OpenCivil Product Ideas site. Have you thought about adding it there so perhaps it can be added to the product itself? I'm certain it would get a lot of votes.
I submitted this to the Ideas page a week or two ago. Looks like it's still under review or maybe didn't go through yet. But I did get a confirmation email. I had also submitted Enhancement Request 977276 a few months ago.
Matt
Same here - i have about a dozen that haven't shown up from a few ago.