Для каждого цикла мгновенно переходит к последнему результату

Я пытаюсь сделать код для запуска через текстовый документ, содержащий элементы управления содержимым повторяющихся разделов (RepSecCC), содержащие несколько вложенных CC внутри. Я хочу написать макрос, который для каждого RepSecCC будет генерировать новый документ Word (из шаблона) и заполнять его информацией из вложенных CC.

Проблема в том, что мой текущий код генерирует только один документ и заполняет его информацией из последнего RepSecCC. Я не могу понять, почему он пропускает все остальные RepSecCC. Где мне изменить свой код?

    Dim objWord As Object
    Dim objDoc As Object
    Dim pack As String, Reg_No As String, VP_name As String, 
    Dim CC As Word.ContentControl
    Dim rCC As Word.ContentControl

    Set objWord = CreateObject("Word.Application")

    MsgBox "Document's are generated. Please wait"

    For Each rCC In ActiveDocument.ContentControls

        If rCC.Title = "New_section" Then

            For Each CC In rCC.Range.ContentControls
                If CC.Tag = "LI_NO" Then
                    Reg_No = CC.Range.Text
                ElseIf CC.Tag = "VP_pav" Then
                    VP_name = CC.Range.Text
                ElseIf CC.Tag = "Pack" Then
                    pack = CC.Range.Text
                    pack = UCase(Left(pack, 1)) & Mid(pack, 2)
                End If
            Next CC

            Set objDoc = objWord.Documents.Add(Template:="S:\bendri\VRS\VRS Administravimas\6 Lygiagretus importas\LI registracijos sarasas\LI_sablonasM.dotm", NewTemplate:=False, DocumentType:=0)
            objWord.Visible = True

            With objDoc
                .ContentControls.Item(1).Range.Text = Reg_No
                .ContentControls.Item(2).Range.Text = VP_name
                .ContentControls.Item(4).Range.Text = pack
            End With
        End If
    Next rCC

    MsgBox "Finished. Please continue"

End Sub

person Gexas    schedule 25.10.2018    source источник
comment
Сравнение строк - потенциальное минное поле, особенно когда одна из строк извлекается из документа Word. Безопаснее использовать функцию Instr. Например, вместо «Если CC.Tag = LI_NO Then» используйте «If Instr (CC.Tag, LI_NO)› 0 Then ». если вам нужно точное совпадение, добавьте предложение, сравнивающее длину двух строк «If (Instr (CC.Tag, LI_NO)› 0) AND (len (CC.Tag) = len (LI_ON)) Then »   -  person freeflow    schedule 25.10.2018
comment
Совершенно непонятно, как устроен этот документ. Все ли элементы управления содержимым повторяющегося раздела имеют одинаковый заголовок? Если это так, я бы использовал SelectContentControlsByTitle для элементов управления содержимым повторяющегося раздела и зацикливал бы полученный массив. Как бы то ни было, в цикле верхнего уровня вы зацикливаете вложенные элементы управления, а также элементы управления секциями, что может привести к неожиданным результатам.   -  person Cindy Meister    schedule 25.10.2018
comment
Я переосмыслил весь свой код и провел несколько тестов. Закончил переписывание (почти) с нуля. Вы были правы, петля второго уровня не работает должным образом. Кроме того, повторение раздела CC не работало так, как я должен был. Я проведу еще несколько тестов и в будущем, возможно, опубликую еще один вопрос по этому поводу.   -  person Gexas    schedule 26.10.2018


Ответы (1)


Я сам разобрался, оказывается, у моего исходного кода были две проблемы:

1) второй цикл For each...next проходил через каждую CC и настраивал переменные до тех пор, пока не достиг последней CC, и значение переменной оставалось неизменным. Из-за этого мой документ получал информацию только из последнего раздела.

2) другая проблема была связана с тем, что по какой-то причине повторяющиеся разделы CC не считались отдельными объектами и из-за этого весь повторяющийся CC засчитывался как один, поэтому в свою очередь создавался только один документ.

Мне удалось преодолеть эти проблемы, изменив принцип работы всего кода:

Сначала для каждой соответствующей CC я создал New Collection, затем я перебрал весь документ и добавил эти значения CC в соответствующие коллекции.

Затем я снова просмотрел документ и для каждого CC с определенным тегом создал новый документ, который взял значения из коллекций. Поскольку значения в коллекции были в последовательном порядке, я просто добавляю счетчик, который подсчитывает номер цикла и тем самым определяет, какое значение из коллекции использовать.

Я уверен, что это, вероятно, не самый эффективный способ, но он работает и работает с удовлетворительной скоростью.

Мой последний код, может быть, кто-нибудь сможет его использовать:

Public Sub generate_docs()

    Dim objWord As Object
    Dim objDoc As Object
    Dim pack As New Collection, Reg_number As New Collection, VP_name As New Collection, Client As New Collection
    Dim Number As String
    Dim CC As Word.ContentControl
    Dim TagCC As Word.ContentControl
    Dim ccRepSec As Word.ContentControl
    Dim i As Long
    Dim x As String

    i = 0

    Set objWord = CreateObject("Word.Application")
    Set ccRepSec = ActiveDocument.SelectContentControlsByTitle("Nauja registracija").Item(1)

    MsgBox "Documents are being generated. Please wait"

    For Each CC In ccRepSec.Range.ContentControls
        If CC.Tag = "LI_NO" Then
            x = CC.Range.Text
            Reg_number.Add Item:=x
        ElseIf CC.Tag = "VP_pav" Then
            x = CC.Range.Text
            VP_name.Add Item:=x
        ElseIf CC.Tag = "Par_pav" Then
            x = CC.Range.Text
            Client.Add Item:=x
        ElseIf CC.Tag = "Package" Then
         'I needed for value to start in upper case, and since in original document its written in lower case used this code
            x = CC.Range.Text
            x = UCase(Left(x, 1)) & Mid(x, 2)
            pack.Add Item:=x
        End If
    Next CC

    For Each TagCC In ccRepSec.Range.ContentControls
        If TagCC.Tag = "LI_NO" Then
            i = i + 1
            Set objDoc = objWord.Documents.Add(Template:="S:\shared\LI\LI_template.dotm", NewTemplate:=False, DocumentType:=0)
            objWord.Visible = True

            With objDoc

                .ContentControls.Item(1).Range.Text = Reg_number(i)
                .ContentControls.Item(2).Range.Text = VP_name(i)
                .ContentControls.Item(5).Range.Text = Client(i)
                .ContentControls.Item(4).Range.Text = pack(i)

                ' I wanted for name to have middle part of Reg_number variable so used code below, to extract it
                Number = Split(Reg_number(i), "/")(3)
                NewFileName = Number & Format(Now, "_yyyy-mm-dd") & ".docx"
                'I wanted to save documents in the same place as original document is located
                .SaveAs2 FileName:=Application.Documents(Application.Documents.Count).Path & "\\" & NewFileName
            End With
        End If
    Next TagCC

    MsgBox "Documents are created. Continue."

End Sub
person Gexas    schedule 26.10.2018