PDA

View Full Version : ContentControls and EditPaste



Hawkansson
06-14-2017, 07:28 AM
Hi,

in one of my documents I've worked a lot with xml mapped content controls. Basically it is a large table with about 40 rows and 11 columns. All cells contain some sort of content Control (date picker, Rich text Control, Combo box Control etc.). Some of these content Controls are mapped to its own xml node. The xml structure goes something like this:

TableRow[1]
Date[1]
Time[1]
Frequency[1]
Mode[1]
Comment[1]

TableRow[2]
Date[1]
Time[1]
Frequency[1]
Mode[1]
Comment[1]

and so on. We use this as a test protocol at my job. Now sometimes a user wants to copy the information from example row 1 to row 2, and then modify the text within the content controls on row 2.

Now to the problem. As the user copy pastes the entire row 1, the mapped content controls gets duplicated. When the user then modifies the information on row 2, the information on row 1 also gets changed (since they are mapped to the same xml nodes).

I have tried to work with the EditPaste function, to try avoid mapped content controls to be duplicated. Basically the function is: "IF the source we are copying is a mapped content Control, THEN just paste the information within the content control rather than the content control itself." This works pretty well when the user copies one cell (one content control) at a time, but it doesn't work when a whole row of 11 different content controls is pasted to another row.

Can someone give me some tips about how to get around this? Are there more sofisticated ways to do this?

Best regards, David

gmaxey
06-14-2017, 04:51 PM
Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Dim oCC As ContentControl
Selection.Paste
For Each oCC In Selection.Range.ContentControls
oCC.XMLMapping.Delete
Next
lbl_Exit:
Exit Sub

End Sub

Hawkansson
06-15-2017, 05:38 AM
Thanks Greg, I think you're on to something. But I was not clear enough on what I wanted to do. The content Controls on the destination row are already mapped. When I paste row 1 to row 2 I want row 2 to keep its mapping, but get the content of row 1.

And to make it even more complicated, when pasting to a table you never know how many cells you are pasting to. For example I could copy cell(1,1) to cell(4,11) and then paste it to cell(5,1), so cell(5,1) to cell(8,11) gets overwritten. But I can never know how many cells I overwrite until I've actually pasted the content...

Sorry if I over-complicate stuff... Tricky situation here..

gmaxey
06-15-2017, 03:10 PM
I suppose you could capture the mapping XPath then delete and recreate it, but this could me futile:


Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Dim oCC As ContentControl
Dim arrXPath() As String
Dim strXpath As String
Dim lngCC As Long
Dim strText As String
Dim oPart As CustomXMLPart
lngCC = 0
For Each oCC In Selection.Range.ContentControls
ReDim Preserve arrXPath(lngCC)
lngCC = lngCC + 1
With oCC.XMLMapping
arrXPath(UBound(arrXPath)) = .XPath
End With
Next
Selection.Paste
lngCC = 0
For Each oCC In Selection.Range.ContentControls
strText = oCC.Range.Text
Set oPart = ActiveDocument.CustomXMLParts.SelectByID(oCC.XMLMapping.CustomXMLPart.ID)
With oCC.XMLMapping
.Delete
.SetMapping arrXPath(lngCC), , oPart
End With
lngCC = lngCC + 1
oCC.Range.Text = strText
Next
lbl_Exit:
Exit Sub
End Sub

Hawkansson
06-16-2017, 01:31 AM
Yes, this would work perfectly IF the user selects all the cells he/she is intending to paste to, so the whole range is selected when the paste is initiated. But it would not work if only the first cell is selected (I mean, you can paste a whole row even though you only selected the first cell).

For that reason, I suppose the challenge here is to find out which range will be affected by the paste command, since that is not necessarily the same as the current selection. Does Word have any such functions to tell the future? :)

I'm thinking maybe the macro could
1) paste the content
2) track what changed
3) undo the paste
4) save the mappings of the affected range
5) paste again and recreate the mappings

But that seems like an awful lot of trouble...

gmaxey
06-16-2017, 04:50 AM
Futile I think.

Hawkansson
06-16-2017, 06:25 AM
OK, I spent some time thinking about it. What if I use the EditCopy() function to monitor the selection that is copied. I can for example store how many cells, rows and columns I'm copying. Then I can put some conditions in the EditPaste() function based on that. I think this is a solution to my problem.

Now the only question is how to transfer the information from EditCopy() to EditPaste(). I'm not so familiar with how public variables work in Word. Can I store for example the range that is copied as a public variable? So that I can access the range in the EditPaste() function?

gmaxey
06-16-2017, 10:32 AM
Option Explicit
Dim m_oRng As Range
Sub EditCopy()
Set m_oRng = Selection.Range
Selection.Copy
End Sub
Sub EditPaste()
If Selection.Range.ContentControls.Count <> m_oRng.ContentControls.Count Then
'MsgBox "The selected paste target resemble the copied text range."
Selection.Paste
Else
ScratchMacro
End If

End Sub
Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Dim oCC As ContentControl
Dim arrXPath() As String
Dim strXpath As String
Dim lngCC As Long
Dim strText As String
Dim oPart As CustomXMLPart
lngCC = 0
For Each oCC In Selection.Range.ContentControls
ReDim Preserve arrXPath(lngCC)
lngCC = lngCC + 1
With oCC.XMLMapping
arrXPath(UBound(arrXPath)) = .XPath
End With
Next
Selection.Paste
lngCC = 0
For Each oCC In Selection.Range.ContentControls
strText = oCC.Range.Text
Set oPart = ActiveDocument.CustomXMLParts.SelectByID(oCC.XMLMapping.CustomXMLPart.ID)
With oCC.XMLMapping
.Delete
.SetMapping arrXPath(lngCC), , oPart
End With
lngCC = lngCC + 1
oCC.Range.Text = strText
Next
lbl_Exit:
Exit Sub
End Sub