I'm wondering if I can do the following:
Find a bookmark within a document
Identify the page number this bookmark is on
Insert another document before the identified page
My code so far:
Sub InsertDoc
Dim MasterDoc As Document
Dim bookmarkRng As Range
Dim pageNo As Long
Set MasterDoc = Documents.Open("Master.docx")
Set bookmarkRng = MasterDoc.Bookmarks("TheBookmark").Range
pageNo = bookmarkRng.Information(wdActiveEndPageNumber)
'1.This is where I need to specify to insert before/after the found page, not sure how
MasterDoc.InsertFile FileName:="AnotherDoc.docx"
'2.Is it possible to use this syntax instead and specify before/after insertion of a whole file?
MasterDoc.Bookmarks("TheBookmark").Range.InsertFile FileName:="AnotherDoc.docx"
MasterDoc.Save
MasterDoc.Close
Set MasterDoc = Nothing
End Sub
Any help is much appreciated, thanks.
It's best not to think in terms of pages, which ironically is an ill defined concept in Word. But if you're inserting material, you have to insert it at specific location anyhow. Since you find a range for the bookmark, and it looks like you want to insert after the bookmark, use the following:
MasterDoc.Bookmarks("TheBookmark").Range.InsertAfter "XXX"
Also, you could remove bookmarkRng and pageNo, then, unless you need them later for some reason.
Related
I am developing the document level program of Office2007 using C#, and I have the following issue:
Inside the building block gallery, there are many custom tables which I already stored previously. Now, I would like to insert some of them to the opening document, after inserting one specific building block(table inside) into the end of the document, I insert a page break after the table so that next table starts from a new page, below is my code:
Word.Range rg = theDoc.Content;
rg.Collapse(ref collapseEnd);//collapse = Word.WdCollapseDirection.wdCollapseEnd;
Word.Range insertedRange = utl.InsertIntoRange(rg, buildBlockName);//The InsertIntoRange method just retrieve the specific buildingblock and insert it into the range using the buildBlock's Insert method
insertedRange.Collapse(ref collapseEnd);
insertedRange.InsertBreak(Word.WdBreakType.wdPageBreak);
the code above lays in a button callback, when I first click the button, it worked as expected(Insert the table, and the a page break). However, when I click the button and the code above executed again, it just deletes the pagebreak which I inserted last time.
I have no idea why, I search many material online, but none of them could solve my problem, I guess the theDoc.Content just does not include the last page break? if so? How could I insert something inside the buildingblock into the document, and then add a page break after table?
Any help will be appreciated!
After doing some research, I narrow down the issues to building block insertion operation.
Below is my utl.InsertIntoRange(rg, buildBlockName) method
object categories = "test";
object isRichText = (object)true;
Word.Template tp = doc.Application.Templates[1];
Word.Categories ctgs = tp.BuildingBlockTypes.Item(Word.WdBuildingBlockTypes.wdTypeCustom1). Categories;
object buildBlockNameObj = (object) buildBlockName;
try{
Word.Category ctg1 =ctgs.Item(ref categories);
return ctg1.BuildingBlocks.Item(ref buildingBlockNameObj).insert(rg, ref isRichText);
}
If I insert a section normal text, the previous page break will not be deleted, however, If I insert a building block with the code above, the table will be inserted into the end of the document and delete the last page break I just inserted!
This problem is just gonna drive me crazy
Does the thisDocument.Content include the page break which I insert to the end of the document by programming?
Yes. You can verify it get the characters of the content. Then insert the page break using the code. At last if you get the characters again, you will find that two characters more than before.
Here is a piece of VBA to insert the “Hello” and a page break every time you run. Could this work for you?
Sub InsertText()
Dim rng As Range
Set rng = ActiveDocument.Content
rng.Collapse wdCollapseEnd
rng.InsertAfter "Hello!"
Set rng = ActiveDocument.Content
rng.Collapse wdCollapseEnd
rng.InsertBreak wdPageBreak
End Sub
And what’s the code for the utl.InsertIntoRange method?
Trying to write a function to delete blank pages in a Word doc. Nothing gets deleted. I appreciate it if somebody can take a look.
Public Function DeleteBlankPages(wd As Word.Document, wdApp As Word.Application)
Dim par As Paragraph
For Each par In wd.Paragraphs
If IsEmpty(par.Range.Text) Then
par.Range.Select
wdApp.Selection.Delete
End If
Next par
End Function
Look up the definition of IsEmpty in the VBA language reference. It doesn't do what you imagine.
The correct way to find out if there is textual content is to check the number of characters. In VBA, this is typically done with the function Len (=length). You'd think that it the comparision should be to 0 (zero), but that's not the case for a paragraph, because a Word paragraph always contains it's paragraph mark (ANSI 13).
Also, no need to select the paragraph or range in order to delete it, just use the Deletemethod directly on the par.Range. (Which means you also don't need to pass a Word.Application object.
Also note that your code doesn't do anything to pages, only to paragraphs... It could deleted empty pages, depending on how things are formatted, but it might be wise to rename the Function and comment how it's supposed to work.
So more like this:
Public Function DeleteBlankPages(wd As Word.Document)
Dim par As Paragraph
For Each par In wd.Paragraphs
If Len(par.Range.Text) <= 1 Then
par.Range.Delete
End If
Next par
End Function
I want to insert a table which is defined as building block. I placed a content control in specified location in the document and refer to it by "selectcontetcontrolsbytag". Unfortunetly when table is inserted to the conentcontrol, it is convertered to RichText. Here is my code:
ThisDocument.SelectContentControlsByTag("TermsConditions").Item(1).Range = _
ActiveDocument.AttachedTemplate.BuildingBlockTypes.Item(wdTypeTables).Categories.Item("Terms and Conditions Translation").BuildingBlocks.Item("Terms and Conditions Eng")
Could you help me with proper code to insert building block in specified location. Also I would like this building block to be replaced by another, when user will select other item from userform, combobox etc.
Complete solution for my problem is:
Solution proposed by Cindy Meister Replacing content inside content
control:
To change content inside content control "TermsConditions" I added following code:
If doc.SelectContentControlsByTag("TermsConditions").Item(1).Range.Text <> doc.SelectContentControlsByTag("TermsConditions").Item(1).PlaceholderText Then
doc.SelectContentControlsByTag("TermsConditions").Item(1).Range.Cut
Else
End If
I'm not sure what you mean by "it is converted to Rich Text"...
The accepted way to insert a BuildingBlock is to use the BuildingBlock.Insert method to which you pass the target Range object. For example (based on your code sample):
Dim doc as Word.Document
Dim rngTarget as Word.Range
Set doc = ActiveDocument
Set rngTarget = doc.SelectContentControlsByTag("TermsConditions").Item(1).Range
doc.AttachedTemplate.BuildingBlockTypes.Item(wdTypeTables).Categories.Item("Terms and and Conditions Translation").BuildingBlocks.Item("Terms and Conditions Eng").Insert rngTarget, true
Take a look at the example in the VBA Language Reference...
Also, you should not use ThisDocument in your code, use ActiveDocument. (Even better, declare a Document object, assign ActiveDocument to it, then use that.)
I am making lots of changes to a Word document using automation, and then running a VBA macro which - among other things - checks that the document is no more than a certain number of pages.
I'm using ActiveDocument.Information(wdNumberOfPagesInDocument) to get the number of pages, but this method is returning an incorrect result. I think this is because Word has not yet updated the pagination of the document to reflect the changes that I've made.
ActiveDocument.ComputeStatistics(wdStatisticPages) also suffers from the same issue.
I've tried sticking in a call to ActiveDocument.Repaginate, but that makes no difference.
I did have some luck with adding a paragraph to the end of the document and then deleting it again - but that hack seems to no longer work (I've recently moved from Word 2003 to Word 2010).
Is there any way I can force Word to actually repaginate, and/or wait until the repagination is complete?
I just spent a good 2 hours trying to solve this, and I have yet to see this answer on any forum so I thought I would share it.
https://msdn.microsoft.com/en-us/vba/word-vba/articles/pages-object-word?f=255&MSPPError=-2147217396
That gave me my solution combined with combing through the articles to find that most of the solutions people reference are not supported in the newest versions of Word. I don't know what version it changed in, but my assumption is that 2013 and newer can use this code to count pages:
ActiveDocument.ActiveWindow.Panes(1).Pages.Count.
I believe the way this works is ActiveDocument selects the file, ActiveWindow confirms that the file to be used is in the current window (in case the file is open in multiple windows from the view tab), Panes determines that if there is multiple windows/split panes/any other nonsense you want the "first" one to be evaluated, pages.count designates the pages object to be evaluated by counting the number of items in the collection.
Anyone more knowledgeable feel free to correct me, but this is the first method that gave me the correct page count on any document I tried!
Also I apologize but I cant figure out how to format that line into a code block. If the mods want to edit my comment to do that be my guest.
Try (maybe after ActiveDocument.Repaginate)
ActiveDocument.BuiltinDocumentProperties(wdPropertyPages)
It is causing my Word 2010 to spend half-second with "Counting words" status in status bar, while ActiveDocument.ComputeStatistics(wdStatisticPages) returns the result immediately.
Source: https://support.microsoft.com/en-us/kb/185509
After you've made all your changes, you can use OnTime to force a slight delay before reading the page statistics.
Application.OnTime When:=Now + TimeValue("00:00:02"), _
Name:="UpdateStats"
I would also update all the fields before this OnTime statement:
ActiveDocument.Range.Fields.Update
I found a possible workaround below, if not a real answer to the topic question.
Yesterday, the first ComputeStatistics line below was returning the correct total of 31 pages, but today it returns only 1.
The solution is to get rid of the Content object and the correct number of pages is returned.
Dim docMultiple As Document
Set docMultiple = ActiveDocument
lPageCount = docMultiple.Content.ComputeStatistics(wdStatisticPages) ' Returns 1
lPageCount = docMultiple.ComputeStatistics(wdStatisticPages) ' Returns correct count, 31
ActiveDocument.Range.Information(wdNumberOfPagesInDocument)
This works every time for me. It returns total physical pages in the word.
I used this from within Excel
it worked reliably on about 20 documents
none were longer than 20 pages but some were quite complex
with images and page breaks etc.
Sub GetlastPageFromInsideExcel()
Set wD = CreateObject("Word.Application")
Set myDoc = wD.Documents.Open("C:\Temp\mydocument.docx")
myDoc.Characters.Last.Select ' move to end of document
wD.Selection.Collapse ' collapse selection at end
lastPage = wD.Selection.Information(wdActiveEndPageNumber)
mydoc.close
wd.quit
Set wD = Nothing
End Sub
One problem I had in getting "ComputeStatistics" to return a correct page count was that I often work in "Web Layout" view in Word. Whenever you start Word it reverts to the last view mode used. If Word was left in "Web Layout" mode "ComputeStatistics" returned a page count of "1" page for all files processed by the script. Once I specifically set "Print Layout" view I got the correct page counts.
For example:
$MSWord.activewindow.view.type = 3 # 3 is 'wdPrintView', 6 is 'wdWebView'
$Pages = $mydoc.ComputeStatistics(2) # 2 is 'wdStatisticPages'
You can use Pages-Object and its properties such as Count. It works perfect;)
Dim objPages As Pages
Set objPage = ActiveDocument.ActiveWindow.Panes(1).Pages
QuantityOfPages = ActiveDocument.ActiveWindow.Panes(1).Pages.Count
Dim wordapp As Object
Set wordapp = CreateObject("Word.Application")
Dim doc As Object
Set doc = wordapp.Documents.Open(oFile.Path)
Dim pagesCount As Integer
pagesCount = doc.Content.Information(4) 'wdNumberOfPagesInDocument
doc.Close False
Set doc = Nothing
I need to create a text (2 lines, multiple fonts) programmatically, that I later place in several tables (<100) of my document.
The only way I found out to solve this, is to create a Word.Paragraph and copy its Range to the cells. The problem with this approach is: while creating a Paragraph, it's added to the Document.
I want to create a formatted text like creating a string, all in the code without modifying the Document.
One approach I have used is to use HTML or richtext, which is essentially a string anyway. I am fairly sure Word can interpret either of these with the right com object settings.
Another approach I have tried is using the clipboard instead of a word object. You can do something like this:
(importing system.windows.forms)
Clipboard.SetText(Me.RichTextBox1.Rtf, TextDataFormat.Rtf)
ApplicationName.Selection.Paste()
Could you use this on hidden text and this on deleting paragraphs?
Something like this:
Sub CreateNewWordDoc()
Dim para As Word.Paragraph
Set para = ActiveDocument.Paragraphs.Add
para.Range.Font.Hidden = True
' Do your manipulation
para.Range.Text = "Hello world"
para.Range.Font.Name = "Tahoma"
para.Range.Font.ColorIndex = wdBlue
' Now remove the paragraph as if it never existed!
para.Range.Delete
End Sub