【问题标题】:For each loop instantly jumps to the last result对于每个循环立即跳转到最后一个结果
【发布时间】:2019-03-29 21:40:39
【问题描述】:

我正在尝试使代码在包含重复部分内容控件 (RepSecCC) 的 word 文档中运行,其中包含多个嵌套的 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

【问题讨论】:

  • 比较字符串是一个潜在的雷区,尤其是从 Word 文档中提取其中一个字符串时。使用 Instr 功能更安全。例如,使用 'If Instr(CC.Tag,"LI_NO")>0 Then' 而不是 'If CC.Tag = "LI_NO" Then'。如果您需要精确匹配,请添加一个比较两个字符串长度的子句 'If (Instr(CC.Tag,"LI_NO")>0) AND (len(CC.Tag)=len("LI_ON")) Then '
  • 这个文档是如何设置的,真的一点都不清楚。重复部分内容控件是否都具有相同的标题?如果是这样,我将使用 SelectContentControlsByTitle 作为重复部分内容控件并循环生成的数组。事实上,在顶层循环中,您正在循环嵌套控件以及部分控件,这可能会导致意外结果。
  • 我重新考虑了我的整个代码并执行了一些测试。结束从头开始重写它(几乎)。你说得对,二级循环不能正常工作。同样重复 CC 部分并没有像我应该的那样工作。我会做更多的测试,将来可能会发布另一个关于它的问题。

标签: vba ms-word word-contentcontrol


【解决方案1】:

我自己想通了,原来我的初始代码有两个问题:

1) 第二个 For each...next 循环遍历每个 CC 并调整变量,直到到达最后一个 CC 并且变量值保持不变。因此,我的文档只收到了最后一部分的信息。

2) 另一个问题是由以下事实引起的,由于某种原因,重复的 CC 部分未被视为单独的对象,因此,整个重复的 CC 被计为一个,因此只创建了一个文档。

我通过改变整个代码的工作原理设法克服了这些问题:

首先,我为每个相关的 CC 创建了New Collection,然后我遍历了所有文档并将这些 CC 值添加到适当的集合中。

然后,我再次遍历文档,并为每个带有特定标签的 CC 创建新文档,该文档从 Collections 中获取值。由于集合中的值是按顺序排列的,所以我只添加了计数器,它计算循环次数并由此确定要使用集合中的哪个值。

我确信这可能不是最有效的方式,但它可以以令人满意的速度运行。

我的最终代码,也许有人可以使用它:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-01
    • 2015-01-10
    • 2018-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多