I am working on a MS-Word addin that reads the content of a document and replaces every occurence of a specific word by a hyperlink.
So far, I came up with this working algorithm.
// Initializes the Find parameters
searchRange.Find.ClearFormatting();
searchRange.Find.Forward = true;
searchRange.Find.Text = "foo";
do
{
searchRange.Find.Execute(Wrap: Word.WdFindWrap.wdFindStop);
if (searchRange.Find.Found)
{
// Creates a Hyperlink at the found location in the current document
this.WordDocument.Hyperlinks.Add(searchRange, externalLink, link, "bar");
}
searchRange.Find.Execute(Wrap: Word.WdFindWrap.wdFindStop);
} while (searchRange.Find.Found);
This code works, however, it can be slow on bigger documents. Thus, instead of adding hyperlinks one by one, I wanted to simply to use the Find.Replacement object and with the WdReplace.ReplaceAllproperty.
However, I cannot manage to replace my search result by a Hyperlink.
Is there a way to replace a piece of text by a hyperlink using the Replacemethod ?
In other words, I'd like to find a way to do this :
Find.Replacement.Text = new Hyperlink(...);
On an other side, I've seen that, by hitting Alt + F9in Word, we can see hyperlinks as code.
The code looks like this :
{ HYPERLINK \l "link" \o "Caption" }
Another solution would be to be able to set the text replacement as that string and make Word interpret it and thus, create the link.
Thanks for reading.
As far as I know, fields can only be inserted programmatically, or by using CTRL-F9. There are two possible reasons for this that I see:
They are not simple text. They have two ranges, the Code and the Result, only one of which is displayed at any time.
How else would a user insert text that looks like a code but is not supposed to be one, unless there was a special mechanism to create one?
Related
I'm trying to add a formula/expression in my Word document programatically. In my scenario I need to get the number of pages minus 1. If you try to do it in the document itself it should look like this:
{={NUMPAGES \*MERGEFORMAT }-1}
Now that I'm trying to do it via code I'm struggling... I've tried to do this:
RangeWord.Fields.Add(this.Range, Interop.WdFieldType.wdFieldExpression, "{NUMPAGES \*MERGEFORMAT }-1", true)
But in that case {NUMPAGES \*MERGEFORMAT} doesn't work as a field but as a plain text. How could I achieve what I want ? Should I add a new field for {NUMPAGES \*MERGEFORMAT} ?
I don't think it will work this way. Entering braces into code does not work in any way.
This, however, should do the trick just fine:
doc.Variables.Add("myNumPages", doc.ComputeStatistics(Interop.WdStatistic.wdStatisticPages) - 1);
RangeWord.Fields.Add(this.Range, Interop.WdFieldType.wdFieldDocVariable, "myNumPages");
.
Edit/AddIt: There is another way, with the advantage of then having a dynamic field that can be updated:
Insert a normal {NUMPAGES} field somewhere and give it a white font or make it hidden
Select the field, add a bookmark "numpages" covering this entire field
Now add a Formula field with the formula =numpages-1
Example:
var hidField = RangeWord.Fields.Add(this.Range, Interop.WdFieldType.wdFieldExpression, "NUMPAGES");
hidField.Result.Bookmarks.Add("numpages");
hidField.Result.Font.Hidden = 1;
RangeWord.Fields.Add(this.Range, Interop.WdFieldType.wdFieldFormula, "numpages-1");
You might have to play around with the range variable so as to not overwrite your hidden field.
I'm creating a MsOffice template application(Winforms) to insert/evaluate the word document.
I want to insert a cover page and later after changes in cover page then i want to evaluate it, using interop c#. I searched a lot on internet but i didn't find suitable one.
Can any one please help me.
Thanks
So if your word template is the same (If the document already exists) each time you essentially have to:
Copy The Template
Work On The Template
Save In Desired Format
Delete Template Copy
Each of the sections that you are replacing within your word document you have to insert a bookmark for that location (easiest way to input text in an area).
I always create a function to accomplish this, and I end up passing in the path - as well as all of the text to replace my in-document bookmarks. The function call can get long sometimes, but it works for me.
Application app = new Application();
Document doc = app.Documents.Open("sDocumentCopyPath.docx");
if (doc.Bookmarks.Exists("bookmark_1"))
{
object oBookMark = "bookmark_1";
doc.Bookmarks.get_Item(ref oBookMark).Range.Text =
"My Text To Replace bookmark_1";
}
if (doc.Bookmarks.Exists("bookmark_2"))
{
object oBookMark = "bookmark_2";
doc.Bookmarks.get_Item(ref oBookMark).Range.Text =
"My Text To Replace bookmark_2";
}
doc.ExportAsFixedFormat("myNewPdf.pdf", WdExportFormat.wdExportFormatPDF);
((_Document)doc).Close();
((_Application)app).Quit();
The above code will get inserting text working for you - is there a reason that you have to re-evaluate the document afterwards if you know (and can add in checks before you attempt to insert ie: if the bookmark doesn't exist).
If you need some more explanation I can help as well :) my example saves it as a .pdf, but you can do any format you prefer.
I have C# code that I am using to write entries in a Notes database. Below is a simple example of the kind of thing I am doing.
var text = "Line 1\r\nLine 2\r\nLine 3";
doc.ReplaceItemValue("Body", text);
doc.Save(false, false);
I would expect that when I view the document in Notes, I would see the body formatted as follows:
Line 1
Line 2
Line 3
However, Notes seems to eat up the newline characters, and what I actually see is this:
Line 1Line 2Line 3
I have tried using Environment.Newline and \n as well, but that doesn't make any difference in the formatting I observe in Notes.
I don't do a lot of Notes programming, so I'm a little confused as to why this is not working for me, since every example I have come across is similar to my code.
If you want to add new lines in the body of a document, you can use the NotesRichTextItem methods as follows:
//(note this is pseudo-code as I'm typing this from memory)
var richTextItem = new NotesRichTextItem(doc, "Body")
richTextItem.AppendText("Line 1");
richTextItem.AddNewLine(1);
doc.Save(false,false);
If it is a simple text field, define it as a multivaluefield in the notes form and then you could do something like
dim item as notesitem
set item = doc.replaceitemvalue("Body","Line 1")
call item.appendToTextlist("Line 2")
call item.appendToTextList("Line 3")
This looks a lot like the newline issue that the java API had before 8.5. You should be able to add newlines into any text item, not just RichText and not using hacks like messing about with lists.
Prior to the fix in 8.5 one workaround was to use the session.evaluate to manipulate the text in formula language.
So let's say I have a program with just a text box and an okay button. The user types in whatever word he wants, and when he clicks ok, it opens a specific file called Test.doc and CTRL+F for the word "test" and replaces it with whatever the user entered into the text box. How can I open said file and replace instances of the word test with the user's defined word?
Ignoring the format of the document, you could literally use the folowing for any type of file:
var contents = System.IO.File.ReadAllText(#"C:\myDoc.doc");
contents = contents.Replace("Test", "Tested");
System.IO.File.WriteAllText(#"C:\myDoc.doc", contents);
The best way would be to use the ms office interop library though.
Andrew
A number of things:
I'd recommend using a FileDialog to get the file's location. This lets you select the file to edit, but also gives you functionality to only show the file types that you want to handle in this program.
If you're handling .doc's, I'd suggest you look into VSTO and opening word docs. Here's a guide I found after a quick search. I'd suggest using it as a place to start, but you'll need to look around for more specifics.
Lastly, the string.Replace("", ""); method is probably very helpful in the CTRL-F functionality. You should be able to extract a string of the text from whatever document you're analyzing and use that method.
I am designing a crawler which will get certain content from a webpage (using either string manipulation or regex).
I'm able to get the contents of the webpage as a response stream (using the whole httpwebrequest thing), and then for testing/dev purposes, I write the stream content to a multi-line textbox in my ASP.NET webpage.
Is it possible for me to loop through the content of the textbox and then say "If textbox1.text.contains (or save the textbox text as a string variable), a certain string then increment a count". The problem with the textbox is the string loses formatting, so it's in one long line with no line breaking. Can that be changed?
I'd like to do this rather than write the content to a file because writing to a file means I would have to handle all sorts of external issues. Of course, if this is the only way, then so be it. If I do have to write to a file, then what's the best strategy to loop through each and every line (I'm a little overwhelmed and thus confused as there's many logical and language methods to use), looking for a condition? So if I want to look for the string "Hello", in the following text:
My name is xyz
I am xyz years of age
Hello blah blah blah
Bye
When I reach hello I want to increment an integer variable.
Thanks,
In my opinion you can split the content of the text in words instead of lines:
public int CountOccurences(string searchString)
{
int i;
var words = txtBox.Text.Split(" ");
foreach (var s in words)
if (s.Contains(searchString))
i++;
return i;
}
No need to preserve linebreaks, if I understand your purpose correctly.
Also note that this will not work for multiple word searches.
I do it this way in an project, there may be a better way to do it, but this works :)
string template = txtTemplate.Text;
string[] lines = template.Split(Environment.NewLine.ToCharArray());
That is a nice creative way.
However, I am returning a complex HTML document (for testing purposes, I am using Microsoft's homepage so I get all the HTML). Do I not have to specify where I want to break the line?
Given your method, if each line is in a collection (Which is a though I had), then I can loop through each member of the collection and look for the condition I want.
If textbox contents were returned with line-breaks representing where word-wrapping occurs, that result will be dependant on style (e.g. font-size, width of the textbox, etc.) rather than what the user actually entered. Depending on what you actually want to do, this is almost certainly NOT what you want.
If the user physically presses the 'carriage return / enter' key, the relevant character(s) will be included in the string.
Why do you need to have a textbox at all? Your real goal is to increment a counter based on the text that the crawler finds. You can accomplish this just by examining the stream itself:
Stream response = webRequest.GetResponse().GetResponseStream();
StreamReader reader = new StreamReader(response);
String line = null;
while ( line = reader.ReadLine() )
{
if (line.Contains("hello"))
{
// increment your counter
}
}
Extending this if line contains more than one instance of the string in question is left as an exercise to the reader :).
You can still write the contents to a text box if you want to examine them manually, but attempting to iterate over the lines of the text box is simply obscuring the problem.
The textbox was to show the contents of the html page. This is for my use so if I am running the webpage without any breakpoints, I can see if the stream is visually being returned. Also, it's a client requirement so they can see what is happening at every step. Not really worth the extra lines of code but it's trivial really, and the last of my concerns.
The code in the while loop I don't understand. Where is the instruction to go to the next line? This is my weakness with the readline method, as I seldom see the logic that forces the next line to be read.
I do need to store the line as a string var where a certain string is found, as I will need to do some operations (et a certain part of the string) so I've always been looking at readline.
Thanks!