How to?: Ensure code only operates on model reference with specified name?

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 If
Set 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.

Parents
  • 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

    Beware Multiple Attachments!

    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

    Regards, Jon Summers
    LA Solutions

     
    Regards, Jon Summers
    LA Solutions

  • 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").activate
    Set 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 Directory
    For 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.

    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.

    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

Reply
  • 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.

    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.

    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

Children
  • 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.

     
    Regards, Jon Summers
    LA Solutions

  • 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.

  • Barry,

    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 Cleanup
    End 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