Если вы пытаетесь получить текст из элемента управления содержимым, вам нужно самое большее
Set ccs = doc.SelectContentControlsByTag(TagName)
Set cc = ccs(1)
' Let's just show the "display name"
Debug.Print cc.Range.Text
Вы можете сократить это до
Set ccs = doc.SelectContentControlsByTag(TagName)
' Let's just show the "display name"
Debug.Print ccs(1).Range.Text
или даже дальше, если хотите.
Причина того, что код, который у вас есть на данный момент, не работает, заключается в том, что он на самом деле пытается поместить текст в элемент управления содержимым. Вы можете сделать это с помощью элемента управления Text, но не с раскрывающимся списком.
(В продолжение вашего комментария) Если вы хотите установить для раскрывающегося списка определенное значение, вам в основном нужно определить, какой элемент в коллекции DropDownListEntries является правильным, а затем выбрать его. Каждый DropDownListEntry в ContentControl имеет уникальный индекс, уникальный текст (отображаемый текст) и значение (скрытое значение).
Вы можете получить текст из раскрывающегося списка, просмотрев .Range.Text исходного ContentControl, но вы не можете использовать его в качестве индекса в записях списка целевого ContentControl, поэтому вам нужно повторить :
Итак, если ccc содержит текст, который вы хотите отобразить, вам понадобится что-то вроде
Set ccs = doc.SelectContentControlsByTag(TagName)
Set cc = ccs(1)
' This asumes you know this is a dropdown list cc
Dim ddle as Word.ContentControlListEntry
For Each ddle in cc.DropdownListEntries
If ddle.Text = ccc Then
ddle.Select
Exit For
End If
Next
Или вы можете получить Index из системы управления версиями (для этого вам придется повторять попытки прослушивания системы управления версиями). Допустим, это переменная idx
. Тогда все, что вам нужно, это
Set ccs = doc.SelectContentControlsByTag(TagName)
Set cc = ccs(1)
cc.DropdownListEntries(idx).Select
(На самом деле вы можете сделать все это в одном
doc.SelectContentControlsByTag(TagName)(1).DropDownlistEntries(idx).Select
но я обычно считаю, что использование нескольких операторов упрощает отладку).
Поэтому, используя этот подход, вам нужно либо перебрать один набор записей списка, либо другой (или оба, если вы хотите использовать значение).
Другой метод заключается в сопоставлении элемента управления с элементом в CustomXMLPart и простом обновлении значения элемента. Затем Word распространяет значение на все элементы управления ContentControl, сопоставленные с этим элементом. Здесь нужно многому научиться, и это может показаться усложнением, которое вам не нужно, но когда вы дойдете до конца, я надеюсь, вы поймете, почему это на самом деле довольно изящный подход.
В простейшем случае это работает так. Предположим, в вашем документе есть один элемент управления содержимым DropDown.
Затем вы можете (повторно) создать XML-часть и сопоставить с ней элемент управления содержимым следующим образом. Вам нужно будет выполнить этот фрагмент кода только один раз для документа. Если ваши документы основаны на шаблонах или сделаны из копий других документов, это один раз для шаблона/оригинала.
Option Explicit
' A namespace URI can just be a piece of text, but its better if you can use
' something that you "own" such as a domain name.
' There is nothing special about this name.
Const myNameSpace As String = "myns0"
Sub recreateCXPandMapCCs()
Dim ccs As Word.ContentControls
Dim cxp As Office.CustomXMLPart
Dim i As Integer
Dim r As Word.Range
Dim s As String
' There is nothing special about these element names.
' You can use your own
s = ""
s = s & "<?xml version=""1.0"" encoding=""UTF-8""?>" & vbCrLf
s = s & "<ccvalues1 xmlns='" & myNameSpace & "'>" & vbCrLf
s = s & " <dropdown1/>" & vbCrLf
s = s & "</ccvalues1>"
With ActiveDocument
' select and delete any existing CXPs with this namespace
For Each cxp In .CustomXMLParts.SelectByNamespace(myNameSpace)
cxp.Delete
Next
' Create a new CXP
Set cxp = .CustomXMLParts.Add(s)
' Connect your dropdown. Instead, you can do this manually in the XML Mapping
' Pane in the Developer tab
' For an XML Part that only has one namespace the prefix mapping should always be "ns0".
.ContentControls(1).XMLMapping.SetMapping "/ns0:ccvalues[1]/ns0:dropdown1[1]", , cxp
Set cxp = Nothing
End With
End Sub
Затем, чтобы установить значение вашего раскрывающегося списка (и это должно быть скрытое значение, а не индекс или текст, вы можете сделать что-то подобное в том же модуле Итак, у вас настроена константа myNameSpace. Допустим, вы хотите установить постоянное значение xyzvalue.
Sub populateDropdown1Element()
With ActiveDocument.CustomXMLParts.SelectByNamespace(myNameSpace)(1)
.SelectSingleNode("/ns0:ccvalues1[1]/ns0:dropdown1[1]").Text = "xyzvalue"
End With
End Sub
Конечно, если исходный документ имеет те же сопоставления, вы можете получить значение раскрывающегося списка исходного документа из того же элемента в XML исходного документа. Дело в том, что если у вас есть тот же XML, те же сопоставления и т. д., в идеале вы должны иметь возможность заменить всю CustomXMLPart в целевом документе на часть из исходного документа. Одна из причин, по которой были изобретены CustomXMLParts, заключалась в том, чтобы позволить людям, использующим Office Open XML SDK, делать именно это. К сожалению, это не работает в VBA с открытым документом, потому что Word имеет тенденцию отключать элементы управления содержимым от части.
Но что вы можете сделать, так это перебрать все узлы Element и Attribute (например) и заменить текст в цели текстом из источника. Как это:
' You would need to pass in a reference to the document you want to get your data *from*
Sub replaceXML(sourceDocument As Word.Document)
Dim s As String
Dim cxn As Office.CustomXMLNode
Dim sourcePart As Office.CustomXMLPart
' You still need that definition of "myNameSpace"
Set sourcePart = sourceDocument.CustomXMLParts.SelectByNamespace(myNameSpace)(1)
With ActiveDocument
For Each cxn In .CustomXMLParts.SelectByNamespace(myNameSpace).Item(1).SelectNodes("//*[not(*)] | //@*")
cxn.Text = sourcePart.SelectSingleNode(cxn.XPath).Text
Next
End With
End Sub
Что выбирает "//*[not(*)] | //@*"
? Ну, "//*[not(*)]"
выбирает конечные элементы (включая элементы, у которых есть атрибуты), "//@*"
выбирает все атрибуты (которые всегда являются конечными узлами), а |
в основном является Or или объединением.
Большинство пользовательских xml, которые я видел в Word, хранят данные только в Elements, и в этом случае вам понадобится только "//*[not(*)]"
person
Community
schedule
08.07.2020