Hi,
As the title says I am wondering how in code I can target a specific model reference (ignoring all other model references in a designfile).An existing Macro I am trying to modify uses this:
Set oDgnFile = OpenDesignFileForProgram(oFile.Path, False)For modelCount = 1 To oDgnFile.Models.Count If oDgnFile.Models(modelCount).Type = msdModelTypeSheet Then myModel = oDgnFile.Models(modelCount).Name ElseIf oDgnFile.Models(modelCount).Type = msdModelTypeNormal Then myModel = oDgnFile.Models(modelCount).Name End IfSet oEnumerator = oDgnFile.Models(myModel).Scan(oScanCriteria)
What I am wanting is for my oEnumerator to only scan on a modelreference called Sheet. I know of the .Name property and its probably very easy to do but I can think how to put it all together.
Any help is appreciated.
Function IsAttachment ( _ ByVal oAttachment As Attachment, _ ByVal name As String) As Boolean IsAttachment = (0 = StrComp (name, oAttachment.Name, _ vbTextCompare)) End Function
Dim oAttachment As Attachment For Each oAttachment In ActiveModelReference.Attachments If IsAttachment (oAttachment, "Barry") Then ' scan this attachment End If Next oAttachment
It's common practise to attach a model more than once. Multiple attachments of the same model must each be assigned a unique logical name.
To work in all circumstances, your code should check both the Attachment.Name and the Attachment.LogicalName properties.
Regards, Jon Summers LA Solutions
Hi Jon, thanks for the quick response.
I think my terminology was somewhat incorrect but I'm not looking to work with reference attachments, but activemodelreferences. What I'm trying to do is target a specific Sheet Model (which also happens to be named sheet suprisingly...) in each designfile and then have my code operate only on that Model ignoring any others.
Sorry for any confusion
Unknown said: I'm looking to work with ActiveModelReferences
There's only one ActiveModelReference. If you want to iterate the ModelReferences of a DGN file, then similar code applies.
Dim oModel As ModelReference For Each oModel In ActiveDesignFile.Models If 0 = StrComp (oModel.Name, "Barry", vbTextCompare) Then ' Do something with oModel oModel.Activate ' Make it the active model End If Next oModel
More succinctly, if you are sure a model exists …
ActiveDesignFile.Models("Barry").Activate
Yeah I'm sure that a model exists so would choose the latter. Is it definitely the case that when iterating through all design files within a folder (using opendesignfileforprogram) that simply using .activate (as per your 2nd example in the above post) will only have the succeeding code affect that model and not any other? I guess it makes sense seeing as I'm not looping through models in the file, but I'm just wanting to be sure.
Assuming that works, how would you modify this line
Set oEnumerator = oDgnFile.Models(myModel).Scan(oScanCriteria)
Does this look ok?
Set oDgnFile = OpenDesignFileForProgram(oFile.Path, False)oDgnFile.Models("Sheet").activateSet oEnumerator = oDgnFile.Models("sheet").Scan(oScanCriteria)
Afternoon Jon, I've tried using both code examples however they both return the same error:
Choosing debug highlights the line where I use .activate. I have my suspicions that its related to using my variable oDgnFile which uses OpenDesignFileForProgram and not ActiveModelReference as per your suggestion and all other ElementEnumerator/Scan examples.
Code currently looks like this:
'Loop through each file in Target DirectoryFor Each oFile In oSourceFolder.Files Select Case oFile.Type Case "Bentley MicroStation Design"'Open Microstation Files for programming Set oDgnFile = OpenDesignFileForProgram(oFile.Path, True) For Each oModel In oDgnFile.Models If 0 = StrComp(oModel.Name, "Sheet", vbTextCompare) Then oModel.Activate 'Execute Next code..... End If Next oModel oDgnFile.Close End Select Next Set oFSO = Nothing oTextStream.Close Set oTextStream = Nothing MsgBox "Completed"End Sub
Barry,
With OpenDesignFileForProgram the "active" model concept doesn't apply.So it is not necessary, or even supported, to activate a model.You as the developer need to handle this explicitly.If you do not explicitly reference a particular model reference, then it would attempt to apply to the Default model of the file.
Also take note that workDgn files do not automatically save, you must do this explicitly as well; otherwise you will lose your changes.
I would recommend a sub routine that accepts a model reference as a parameter and call that.You are mostly there already and not certain that this is really any different than what you are doing now, aside from the Activate attempt.
For Each oModel In oDgnFile.Models If 0 = StrComp(oModel.Name, "Sheet", vbTextCompare) Then ' oModel.Activate <- Remove ProcessMyModel oModel End If Next oModel oDgnFile.Save '<- Add this, very important oDgnFile.Close
Hi Gerald, thanks for you input.
Unknown said: Barry, With OpenDesignFileForProgram the "active" model concept doesn't apply.So it is not necessary, or even supported, to activate a model.
With OpenDesignFileForProgram the "active" model concept doesn't apply.So it is not necessary, or even supported, to activate a model.
After unsuccesful testing I was beginning to think that was the case.
Unknown said: You as the developer need to handle this explicitly.If you do not explicitly reference a particular model reference, then it would attempt to apply to the Default model of the file.
You as the developer need to handle this explicitly.If you do not explicitly reference a particular model reference, then it would attempt to apply to the Default model of the file.
All my target files within a designated folder that the macro operates on are DGN files containing 1 or more design models and a single Sheet Model called Sheet. Its is this sheet model that I want to work with and ignore any other models.
Unknown said: Also take note that workDgn files do not automatically save, you must do this explicitly as well; otherwise you will lose your changes.
In this case I am only extracting tag values to put into a CSV file therefore I do not see the need within this sub procedure to use oDgnFile.Save , unless I'm missing something?
Unknown said: I would recommend a sub routine that accepts a model reference as a parameter and call that.You are mostly there already and not certain that this is really any different than what you are doing now, aside from the Activate attempt.
Can you expand on what this additional sub would do and how it helps achieve the desired result? I can see you have added the textra line to call the sub but what sort of code would ProcessMyModel contain?
Thanks again
Unknown said:Can you expand on what this additional sub would do?
A procedure encapsulates a unit of work. Since you are the author of your code, it does whatever you want it to do.
Unknown said:How does it help achieve the desired result?
Huge monolithic blocks of code are hard to read and hard to maintain. Breaking large chunks of code into small procedures that perform a single function make it easier to follow program logic and make your code easier to maintain.
Hi Jon,
I know exactly what a sub does and how they help code readability. What I was querying was what Gerald's code suggestion was that would allow my use of OpenDesignFileForProgram to target a specific Sheet Model seeing as using .activate method does not work.
WRT: How does this help to create a sub routine vs not...Well it doesn't really. Just helps for readability, maintainability, and compartmentalizing. Not necessary, just nice.
WRT: If you are not updating anything and only scanning is there any need to use the "Save" method? Nope, doesn't matter then.
Below is just a simple example showing a method you could call and pass in a model reference.
'--------------------------------------------------Public Function CountElemsWithTagsOnLevel( _ ByVal mdlRef As ModelReference, _ ByVal lvlName As String) As Long Dim result As Long Dim lvl As Level Dim ee As ElementEnumerator Dim sc As ElementScanCriteria On Error GoTo errHandler Set lvl = mdlRef.Levels.Find(lvlName) If lvl Is Nothing Then ' Level doesn't exist result = -1 GoTo Cleanup End If Set sc = New ElementScanCriteria With sc .ExcludeNonGraphical .ExcludeAllLevels .IncludeLevel lvl End With Set ee = mdlRef.Scan(sc) Do While ee.MoveNext With ee.Current If .HasAnyTags Then result = result + 1 End If End With Loop Cleanup: Set lvl = Nothing Set sc = Nothing Set ee = Nothing CountElemsWithTagsOnLevel = result Exit Function errHandler: result = -1 Resume CleanupEnd Function'--------------------------------------------------
The nice thing about this method is it doesn't care where the model reference came from.Could be active model, reference model, model from background file opened with OpenDesignFileForProgram, etc.
Not exactly what you asked for, but demonstrates the methodology.The key to this is passing in the model reference and explicitly using that instead of "ActiveModelReference".
Hope this helps,-G-
Hi Gerald
Thanks for the example. I think before I misunderstood your first post, I was thinking that your example line ProcessMyModel oModel
contained additional code that you had not yet revealed. However I now realise that you were recommend that I encapsulate my succeeding code within the new sub. So having clarified all of that, I have done just that and it now seems to be on only the sheet reporting as desired. No doubt further quirks await but thay will save for another day.
Thanks again guys