Simple question that I'm not finding an answer to. My code below is in a loop and finds the first text matching "{{foo}}" in a Word doc. I then want to reset the Find so that it begins its next search at the beginning of the doc again. Currently, it picks up where after the "foo".
Selection sel = application.Selection;
sel.Find.ClearFormatting();
sel.Find.MatchWildcards = true;
sel.Find.Text = #"\{\{?#\}\}";
sel.Find.Forward = true;
sel.Find.Execute();
How do I reset the starting location of Find?
It's always "better" to use Range rather than Selection in Word, whenever possible. You can have only one selection, but code can work with multiple ranges. In addition, the screen is quieter and execution tends to be faster. There are situations where Selection is necessary, but this is not one of them.
To get the Range of the entire document
Word.Range rngDoc = document.Content;
To "find" using the range:
rngDoc.Find.ClearFormatting();
rngDoc.Find.MatchWildcards = true;
rngDoc.Find.Text = #"\{\{?#\}\}";
rngDoc.Find.Forward = true;
rngDoc.Find.Wrap = Word.WdFindWrap.wdFindStop //ensure Word won't entire an infinite loop
rngDoc.Find.Execute();
When "find" is successful, the Range (or Selection) contains only what was found. To "reset" to start again from the beginning of the document (including the whole document):
rngDoc = document.Content;
And (what people ask more frequently) to continue searching from just beyond the "found" term to the end of the document:
object oCollapseEnd = Word.WdCollapseDirection.wdCollapseEnd;
rngDoc.Collapse(ref oCollapseEnd); //go just beyond what was found
rngDoc.End = document.Content.End;
In VBA we'd use:
Selection.HomeKey Word.WdUnits.wdStory
So, in your C# code would that convert to?
Sel.HomeKey(Word.wdUnits.wdStory);
.Find.Execute always resets the range to the found range. Accordingly, you need to either re-set it to the entire document (as per Olivier's comment) or use the C# equivalent of .Wrap = wdFindContinue (VBA) to instruct Word to continue searching from the top after getting to the end of the document.
Related
I am using the following code to find some strings in my document:
Application application = Addin.Application;
Document document = application.ActiveDocument;
Range rng = document.Content;
rng.Find.ClearFormatting();
rng.Find.Forward = true;
rng.Find.Text = findText;
while (rng.Find.Execute() && rng.Find.Found)
{
//here: rng.Text == findText
//however rng.Find.HitHighlight(findText, WdColor.wdColorAqua);
//highlights all occurrences in the document, not in the current range
}
as the comments in the code state, I'd expect rng.Find.HitHighlight(findText, WdColor.wdColorAqua); to only work on the current range but instead it executes on the whole document.
Interestingly if I start from a different range this works as I would expect... ie.
Range rng = document.Content.Paragraphs.First.Range;
rng.Find.HitHighlight("video", WdColor.wdColorAqua);
will only HitHighlight the findText in the first paragraph.
This is inconsistent... Any ideas on how to perform HitHighlight only on the range selected using Find?
NOTE: I tried this in a NetOffice addin and I get the same behavior.
It seems like the Find.HitHighlight method is not intended to be used at the same time as Find.Execute. It seems to use whatever range was present when you call Execute. If you don't call execute, it uses the current range.
Remarks
The HitHighlight method applies primarily to search highlighting in Office Outlook when Word is specified as the email editor. However, you can use this method on documents inside Word if you want to highlight found text. Otherwise, use the Execute method.
I suspect there is no way to do this except by iterating through each paragraph, which you already know about.
I realize this is not a complete answer but VSTO is not a popular tag and this may be the best you are going to get. Most questions go completely unanswered, and often without comments as well.
I have a word template where some paragraphs needs to be duplicated programmitacaly. I tried to use range.duplicate, but it wouldn't do the job.
Now, i have this code:
document.Bookmarks["Experience"].Select();
Word.Range range = application.Selection.Range;
range.Copy();
range.Paste();
But it doesn't insert anything to the documentum. Can you please help me?
The problem is that the two ranges are identical. It's like when you're working in the document using the mouse or keyboard: If you have a selection and paste, what you paste will replace what was selected. In order to have the one follow the other you first need to press the right-arrow key or click somewhere.
So you need to specify a second Range (such as the end of the document or another bookmark), or as suggested in #HansPassant comment, "collapse" the Range (like pressing an arrow key).
Another thing to keep in mind is that you shouldn't use the Clipboard, if at all possible. The alternative in Word is to use FormattedRange to transfer foramtted content. The sample code below shows both variations.
//Possibility 1:
Word.Range rangeSource = document.Bookmarks["Experience"].Range;
Word.Range rangeTarget = rangeSource.Duplicate();
rngTarget.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
rngTarget.FormattedText = rngSource.FormattedText;
//Possibility 2:
Word.Range rangeSource = document.Bookmarks["Experience"].Range;
rangeSource.Copy();
rngSource.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
rangeSource.Paste();
Microsoft word didn't provide a spelling tool for my language and I want to do it with my self, every this is going fine and there is a small problem I need to solve.
In order to spell check for each words I need to get each words first. obviously if I used
var doc = Globals.ThisAddIn.Application.ActiveDocument;
int counts = doc.Words.Count;
List<string> words=new List<string>;
for (int i=0;i<counts;i++)
{
words.Add(doc.Words[i].Text.Trim());
}
to get each words, it will run very slowly.
after that I write my own method to get each words, it runs good. after that I need to mark the wrong spelled words. I used
bool check = diccheck(word);
if (check == false)
{
doc.Words[i].Font.Underline = Word.WdUnderline.wdUnderlineWavy;
doc.Words[i].Font.UnderlineColor = Word.WdColor.wdColorRed;
}
and it is run very slow again. can any one help me show the way how to mark the wrong spelled words quickly?
What do you think about a thread runs while you writes?
Are you trying to correct wrong words?
If i get it right, may be more usefull if you only checks the text that changed.
I have one master document into which I want to insert a number of files. These should be inserted into the file one after another at a certain point in the middle of the document.
So I have created a bookmark at this point called "TESTS", since this seems to be the easiest way of programatically finding the point.
I am able to insert a single file using this code:
Microsoft.Office.Interop.Word.Application oWord = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document oWordDoc = oWord.Documents.Open(#"C:\master.doc");
oWordDoc.Bookmarks.Cast<Bookmark>().First(b => b.Name == "TESTS").Range.InsertFile(#"C:\test1.doc");
But this removes the bookmark, making it impossible to insert a second file at the same point. I don't mind losing the bookmark, but only once I have inserted all files.
Can this be done? I am guessing that the above code replaces the range with the bookmark so finding the location just before or after and then deleting the bookmark range would be best - but I just can't find the code for it. Everything I have tried seems to replace the whole document.
Alternatively, is there any way to do this without the Interop (i.e. by parsing the file - no touching MS Word at all)?
There must be something particular about the way your document is set up and the exact range of the the bookmark because I am able to get this to work without losing the bookmark. According to this MVP article Inserting text at a bookmark without deleting the bookmark, adding Text to a bookmarked range should delete the bookmark; maybe you are running into similar issue with InsertFile.
Try their suggestion of storing the bookmark's range into a variable ie MyRange and then calling Bookmarks.Add "mybookmark", MyRange
Dim BMRange As Range
Set BMRange = ActiveDocument.Bookmarks("MyBookmark").Range
BMRange.Text = "Hello world"
ActiveDocument.Bookmarks.Add "MyBookmark", BMRange
I want to replace each character in file with another one.
Now I'm implementing it by using Find.Execute() method, but in this case it spends time for searching and then replaces it, then search for another character from the beginning of file again, so if I want to replace all the alphabetic letters it will go through the whole document 26 x2 (lower case and upper case) =48 times, but I want it to replace by 1 lookup, so like: It get the first character it is "a" replace with " a' ", if the next char is "c" replace with "s" etc, make it by one look up, so it goes through the whole document only one time.
I know I can implement it just by writing my own code, but I'm wondering may be there is some built-in class that can ease my life :)
What about:
using Word = Microsoft.Office.Interop.Word;
//...
Word.Application app = new Word.Application();
Word.Document myDoc = app.Documents.Add(pathToMyDoc);
for(int n = 0; n < myDoc.Characters.Count; ++n)
{
myDoc.Characters[n].Text = LookupReplacement(myDoc.Characters[n].Text);
}
Completely untested but might help you. Link I looked at:
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.documentclass(v=office.11).aspx
Try this for reference , Hope this helps:
http://weblogs.asp.net/guystarbuck/archive/2008/05/13/automated-search-and-replace-in-multiple-word-2007-documents-with-c.aspx