我有一个 Word 文档,里面有一个版本表。版本表只是一个三列表格,其中包含版本号、编辑日期和更改摘要。文档中有几个地方使用了版本号和上次编辑日期。我希望这些操作能够自动完成。
我已经解决了版本问题。我在表格的顶部创建了一个“隐藏”行(无边框,白色字母),并使用了公式=MAX(BELOW)
。由于版本是递增的数字,因此这种方法有效,并且该单元格(不可见地)填充了最新版本号。我将该字段标记为书签LatestDocVersion
,并添加到{REF LatestDocVersion}
我希望自动更新的位置,瞧!全部完成。
日期是另一回事。目标是让该列的最后一项在文档的其他地方使用——当新版本添加到表中时,日期应自动更新为该版本的日期。我不能使用相同的方法,因为它MAX
似乎不理解日期并返回 0。我试图找到一种方法来引用列中的最后一个单元格(类似于{=R&(COUNT(BELOW)-1)&C2}
except,你知道,实际上是有用的),但这没有奏效,当它为特定单元格进行硬编码时,它只会返回 0。
有办法吗?我对公式和书签还很陌生,所以我可能会忽略一些非常明显的东西。
答案1
因为正如您所说,{ = }
字段功能仅适用于数值,所以很难想出一个真正易于使用的字段和/或书签的方案。
可能最简单的方法就是使用几个字段代码插入新的“当前版本日期”,如下所示:
{ SET lastedit "2020-05-29" }{ lastedit }
(并{ lastedit }
在文档中需要该日期的其他地方使用。)
为了实现这一点,您始终需要返回到先前版本的日期并在插入新日期之前取消两个相应字段的链接。
您可以通过使用稍微复杂一点的字段集来避免这种情况,如下所示:
{ SET "edit{ SEQ v }" "2020-05-30" }{ "edit{ SEQ v \c }" }{ SET lastedit { "edit{ SEQ v \c }" }
{ SEQ v }
在名为“v”的序列中插入下一个数字。{ SEQ v \c }
插入名为 v 的序列的当前值。因此,表中的每个日期都设置为不同的书签名称,edit1、edit2 等。
例如,对于表中的第三行数据,如下所示
{ SET edit3 "2020-05-30" }{ edit3 }{ SET lastedit { edit3 } }
如果您有自动文本或类似允许您插入该组字段的功能,您需要做的就是将它们插入到最终表行中,编辑日期,然后重新执行所有字段。
一个可能的优点是您还可以参考旧版本的日期。
你也许可以简化这一点。如果这只是为了你,那显然是可行的。但除此之外是否可行则需要判断。
您可以考虑使用映射的内容控件和重复组内容控件的完全不同的方法。您必须使用 VBA 进行设置,并且为了使其正常工作(即插入新日期会自动导致文档中其他地方的即时更改),您需要能够响应特定事件的 VBA。
但即使没有 VBA,用户只需保存、关闭并重新打开文档即可更新相关日期。
如果您想尝试一下,这里有一些设置代码。您需要从一个完全空白的文档开始,运行代码(我将让您自己了解如何安装和运行它)。
代码创建了一个“自定义 XML 部分”来存储文档中的数据。然后,它创建了一个 2 行 3 列的表格。
它在第二行的每个单元格中放置一个文本内容控件,并将这些控件“映射”到自定义 XML 部分。这意味着任何也映射到数据存储中的该项目的内容控件的值都将由 Word 自动更新。
然后,它将第 2 行包装在也映射到该部分的重复组内容控件中。这意味着,当您在表中创建新行时(选择该行并单击右侧出现的“+”框),您会在表中得到一个新行和与 Part 中的该行对应的新元素。
最后,代码会为最新版本号和最新编辑日期创建一个内容控件。这些内容会映射到部件中的最后一个适当元素。您只需复制这些内容并将副本粘贴到文档中的其他位置,即可让它们反映表中的值。
如果您首先在第 2 行、第 1 列和第 2 列中输入文本,则应该立即看到相关内容控件的任何副本中显示的值。如果您更改表中的值,其他值也应该会更改。我已锁定非表格内容控件以供编辑,因此您无法通过在其中输入值来破坏表格。
如果您现在使用该“+”功能在表中创建新行,并输入版本和日期值,则非表内容控件的值不会自动更新。这是因为 Microsoft 选择限制它在自定义 XML 部分中检测到的更改类型。(在我看来这并不不合理)。但是,如果您现在保存、关闭并重新打开文档,您应该会看到非表内容控件值现已更新。正如我之前所说,使用一小段 VBA 就可以立即实现这一点,但这真的有必要吗?
代码:
Sub recreateCXPandMapCCs()
' Specify a namespace for your CXP
Const myns As String = "vt1"
' Specify the name of the Bookmark that
' marks the Version Table
Const VTBmName As String = "VersionTable"
Dim bm As Word.Bookmark
Dim cc As Word.ContentControl
Dim ccs As Word.ContentControls
Dim cxp As Office.CustomXMLPart
Dim cxps As Office.CustomXMLParts
Dim doc As Word.Document
Dim i As Long
Dim rng As Word.Range
Dim s As String
Dim tbl As Word.Table
' Build the initial XML for our Custom XML Part
' You can use the names that you prefer.
s = ""
s = s & "<?xml version=""1.0"" encoding=""UTF-8""?>" & vbCrLf
s = s & "<versionTable xmlns='" & myns & "'>" & vbCrLf
s = s & " <theTable>" & vbCrLf
s = s & " <theRow>" & vbCrLf
s = s & " <versionNumber/>" & vbCrLf
s = s & " <editDate/>" & vbCrLf
s = s & " <summary/>" & vbCrLf
s = s & " </theRow>" & vbCrLf
s = s & " </theTable>" & vbCrLf
s = s & "</versionTable>"
' Point to the document we want to process
Set doc = ActiveDocument
With doc
' select and delete any existing CXPs with the specified namespace
Set cxps = .CustomXMLParts.SelectByNamespace(myns)
For Each cxp In cxps
cxp.Delete
Next
Set cxps = Nothing
' Create a new CXP
Set cxp = .CustomXMLParts.Add(s)
' Delete and recreate our versioning table, and insert
' which we have bookmarked usin the name "VersionTable"
' If the bookmark doesn't exist, create a new table
' at the end of the document
Set rng = Nothing
For Each bm In .Bookmarks
If bm.Name = VTBmName Then
Set rng = bm.Range
rng.Tables(1).Delete
rng.Text = ""
Exit For
End If
Next
If (rng Is Nothing) Then ' bookmark not found
Set rng = .Range(.Range.End - 1, .Range.End - 1)
rng.InsertParagraphBefore
End If
With rng
Set tbl = .Tables.Add(Range:=rng, numrows:=2, numcolumns:=3)
With tbl
.Range.Bookmarks.Add VTBmName
.Cell(1, 1).Range.Text = "Version"
.Cell(1, 2).Range.Text = "Date"
.Cell(1, 3).Range.Text = "Summary"
Set cc = .Cell(2, 1).Range.ContentControls.Add(wdContentControlText)
With cc
.Title = "Version"
.XMLMapping.SetMapping "//ns0:versionNumber[1]", , cxp
End With
Set cc = .Cell(2, 2).Range.ContentControls.Add(wdContentControlText)
With cc
.Title = "Date"
.XMLMapping.SetMapping "//ns0:editDate[1]", , cxp
End With
Set cc = .Cell(2, 3).Range.ContentControls.Add(wdContentControlText)
With cc
.Title = "Summary"
.XMLMapping.SetMapping "//ns0:summary[1]", , cxp
End With
Set cc = .Rows(2).Range.ContentControls.Add(wdContentControlRepeatingSection)
With cc
.AllowInsertDeleteSection = True
.RepeatingSectionItemTitle = "Version Info"
.XMLMapping.SetMapping "//ns0:theRow[1]", , cxp
End With
End With
Set tbl = Nothing
' Now add "CurrentVersion" and "VersionDate" ccs at the end of the document
.Start = doc.Range.End - 1
.End = doc.Range.End - 1
.InsertParagraphBefore
Set cc = .ContentControls.Add(wdContentControlText)
With cc
.Title = "LatestVersion"
' the key to all this is "last()"
.XMLMapping.SetMapping "/ns0:versionTable[1]/ns0:theTable[1]/ns0:theRow[last()]/ns0:versionNumber[1]", , cxp
' Ensure the user cannot type into this control
.LockContents = True
End With
.Collapse wdCollapseEnd
Set cc = .ContentControls.Add(wdContentControlText)
With cc
.Title = "LastEdited"
.XMLMapping.SetMapping "/ns0:versionTable[1]/ns0:theTable[1]/ns0:theRow[last()]/ns0:editDate[1]", , cxp
.LockContents = True
End With
Set cc = Nothing
End With
Set rng = Nothing
Set cxp = Nothing
End With
Set doc = Nothing
End Sub
答案2
您可以创建一种字符样式,该样式仅应用于表格中的日期单元格。然后,您只需在文档中的其他位置使用 STYLEREF 字段即可查找该新样式(该样式将始终位于表格的底部),因此该点之后的 STYLEREF 字段将始终找到最后一个日期。由于您将字符样式应用于单元格,因此当您创建新行时,该字符样式将自动延续到新行,因此当他们输入新日期时,它也会具有字符样式,然后您的 STYLEREF 字段将选择该新日期。