How to use advanced find in MS Word with .NET C# - c#

I have a problem like this: I need to use advanced find to find a specific text (base on Font of the text, the text string, wildcard,...), and write down to a notepad file which page did I find that text.
I see that in C# .Net has this Find.Execute method, but I don't know if it's possible to do this, I have googled around but no hope.
But my idea is like this code
using Microsoft.Office.Core;
using Word = Microsoft.Office.Interop.Word;
using System.Reflection;
...
Word.Application oWord;
Word._Document oDoc;
oWord = new Word.Application();
oWord.Visible = false;
oDoc = oWord.Documents.Open(strPath, ReadOnly: true);
Word.Range findRange;
Word.Range resultRange;
int nPage;
//Get the range of the whole word document
int nEnd;
nEnd = oDoc.Paragraphs.Last.Range.Sentences.First.End;
findRange = oDoc.Range(0, nEnd);
//Setup find condition
//The color of the found text: RGB(243,99, 195) . Please help!
//Execute find --> Loop until not found anymore
{
//findRange.Find.Execute... Please help!
//Get the range of the found text
//resultRange = ... Please help!
//Get page of the result range
nPage = resultRange.get_Information(Word.WdInformation.wdActiveEndPageNumber);
//Do anything you like with nPage
}
//Close the process
oDoc.Close(Word.WdSaveOptions.wdDoNotSaveChanges);
((Word._Application)oWord).Quit(Word.WdSaveOptions.wdDoNotSaveChanges);
Thank you in advance.

Thank God, I found my solution.
After I read:
this article to find out how to loop the find next feature.
This article to find out that must use Find.Font.Color instead of Find.Font.TextColor.RGB
This article to get the page range (the code is pretty unclean, but usable)
Ok, here it goes
Word.Application oWord;
Word._Document oDoc;
oWord = new Word.Application();
oWord.Visible = false;
oDoc = oWord.Documents.Open(strWorkingPath, ReadOnly: true);
//===================Excute===================
/*Word 2013*/
oWord.ActiveWindow.View.ReadingLayout = false;
// Get pages count
Word.WdStatistic PagesCountStat = Word.WdStatistic.wdStatisticPages;
int nTotalPage = oDoc.ComputeStatistics(PagesCountStat);
int nEndOfTheDoc = oDoc.Paragraphs.Last.Range.Sentences.First.End;
int nStart = 0;
int nEnd = nEndOfTheDoc;
List<int> lstPage = new List<int>();
int color = 696969;//The color you can get by read the Font.Color of the Range in Debug view
Word.Range findRange;
object What = Microsoft.Office.Interop.Word.WdGoToItem.wdGoToPage;
object Which = Microsoft.Office.Interop.Word.WdGoToDirection.wdGoToAbsolute;
object nCrtPage;
object nNextPage;
bool bPageIsIn = false;
/*Loop the pages*/
for (int i = 1; i <= nTotalPage; i++)
{
/*Get the start and end position of the current page*/
nCrtPage = i;
nNextPage = i + 1;
nStart = oWord.Selection.GoTo(ref What,
ref Which, ref nCrtPage).Start;
nEnd = oWord.Selection.GoTo(ref What,
ref Which, ref nNextPage).End;
/*The last page: nStart will equal nEnd*/
if(nStart == nEnd)
{
/*Set nEnd for the last page*/
nEnd = nEndOfTheDoc;
}
/*Set default for Count page trigger*/
bPageIsIn = false;
/*Set the find range is the current page range*/
findRange = oDoc.Range(nStart, nEnd);
/*Set up find condition*/
findRange.Find.Font.Color = (Word.WdColor)color;
findRange.Find.Format = true;
findRange.Find.Text = "^?";
do
{
/*Loop find next*/
findRange.Find.Execute();
/*If found*/
if (findRange.Find.Found)
{
/*If found data is still in the page*/
if (findRange.End <= nEnd)
{
/*If found data is visible by human eyes*/
if (!string.IsNullOrWhiteSpace(findRange.Text))
{
/*Ok, count this page*/
bPageIsIn = true;
break;/*no need to find anymore for this page*/
}
}
}
else
break;/*no need to find anymore for this page*/
}while (findRange.End < nEnd);/*Make sure it is in that page only*/
if (bPageIsIn)
lstPage.Add(i);
}
//===================Close===================
oDoc.Close(Word.WdSaveOptions.wdDoNotSaveChanges);
((Word._Application)oWord).Quit(Word.WdSaveOptions.wdDoNotSaveChanges);
foreach (var item in lstPage)
{
builder.AppendLine(item.ToString());//Do anything you like with the list page
}

Related

Splitting word document into separate pages using c#

An hour ago I been searching for a code that split word document into separate pages I found this question
Using the code in the thread
static class PagesExtension {
public static IEnumerable<Range> Pages(this Document doc) {
int pageCount = doc.Range().Information[WdInformation.wdNumberOfPagesInDocument];
int pageStart = 0;
for (int currentPageIndex = 1; currentPageIndex <= pageCount; currentPageIndex++) {
var page = doc.Range(
pageStart
);
if (currentPageIndex < pageCount) {
//page.GoTo returns a new Range object, leaving the page object unaffected
page.End = page.GoTo(
What: WdGoToItem.wdGoToPage,
Which: WdGoToDirection.wdGoToAbsolute,
Count: currentPageIndex+1
).Start-1;
} else {
page.End = doc.Range().End;
}
pageStart = page.End + 1;
yield return page;
}
yield break;
}
}
I call the code above using this code
var app = new Microsoft.Office.Interop.Word.Application();
object missObj = System.Reflection.Missing.Value;
app.Visible = false;
var doc = app.Documents.Open(fileLocation);
int pageNumber = 1;
foreach (var page in doc.Pages())
{
Microsoft.Office.Interop.Word.Document newDoc = app.Documents.Add(ref missObj, ref missObj, ref missObj, ref missObj);
page.Copy();
var doc2 = app.Documents.Add();
doc2.Range().Paste();
object newDocName = pageNumber.ToString() + ".docx";
Console.WriteLine(newDocName);
doc2.SaveAs2(newDocName, Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatXMLDocument,
CompatibilityMode: Microsoft.Office.Interop.Word.WdCompatibilityMode.wdWord2010);
pageNumber++;
}
app.ActiveDocument.Close();
app.Quit();
But I'm getting an error in a specific document and here is the error
This method or property is not available because no text is selected.
What is the reason for it? i checked the document and found out that the document contains lots of spaces before the next page. How can I solve this?
And using the code above it didn't copy the header and footer. Thank you
Update: Error
This method or property is not available because no text is selected.
at Microsoft.Office.Interop.Word.Range.Copy()
at retrieveObjects(String location) in Document.cs:line 31
and this is the line
page.Copy();

Adding multiple word tables into word using interop

I'm trying to insert multiple tables into a word document using c#, but when I add another block of code to add a table in I am getting an error and the second table is not being inserted. How do I move the range down to the bottom of the page and then add another table? I tried creating a new range using the end of doc reference but this doesn't seem to work, can anyone give me some help?
Word._Application objApp;
Word._Document objDoc;
try
{
object objMiss = System.Reflection.Missing.Value;
object objEndOfDocFlag = "\\endofdoc"; /* \endofdoc is a predefined bookmark */
//Start Word and create a new document.
objApp = new Word.Application();
objApp.Visible = true;
objDoc = objApp.Documents.Add(ref objMiss, ref objMiss,
ref objMiss, ref objMiss);
//Insert a paragraph at the end of the document.
Word.Paragraph objPara2; //define paragraph object
object oRng = objDoc.Bookmarks.get_Item(ref objEndOfDocFlag).Range; //go to end of the page
objPara2 = objDoc.Content.Paragraphs.Add(ref oRng); //add paragraph at end of document
objPara2.Range.Text = "Test Table Caption"; //add some text in paragraph
objPara2.Format.SpaceAfter = 10; //defind some style
objPara2.Range.InsertParagraphAfter(); //insert paragraph
//Insert a table
Word.Table objTab1; //create table object
Word.Range objWordRng = objDoc.Bookmarks.get_Item(ref objEndOfDocFlag).Range; //go to end of document
objTab1 = objDoc.Tables.Add(objWordRng, 9, 2, ref objMiss, ref objMiss); //add table object in word document
objTab1.Range.ParagraphFormat.SpaceAfter = 6;
objTab1.Range.Borders[Word.WdBorderType.wdBorderBottom].LineStyle = Word.WdLineStyle.wdLineStyleThickThinLargeGap;
objTab1.Range.Borders[Word.WdBorderType.wdBorderHorizontal].LineStyle = Word.WdLineStyle.wdLineStyleDouble;
objTab1.Range.Borders[Word.WdBorderType.wdBorderTop].LineStyle = Word.WdLineStyle.wdLineStyleDouble;
objTab1.Range.Borders[Word.WdBorderType.wdBorderLeft].LineStyle = Word.WdLineStyle.wdLineStyleDouble;
objTab1.Range.Borders[Word.WdBorderType.wdBorderRight].LineStyle = Word.WdLineStyle.wdLineStyleDouble;
objTab1.Columns.Borders[Word.WdBorderType.wdBorderVertical].LineStyle = Word.WdLineStyle.wdLineStyleDouble;
objTab1.Columns[1].Shading.BackgroundPatternColor = Word.WdColor.wdColorGray20;
objTab1.Columns[1].Width = objApp.CentimetersToPoints(3.63f);
objTab1.Columns[2].Width = objApp.CentimetersToPoints(13.11f);
int iRow, iCols;
string[] col = new string[9];
col[0] = "Row1";
col[1] = "row2";
col[2] = "Row3";
col[3] = "row4";
col[4] = "row5";
col[5] = "row6";
col[6] = "row7";
col[7] = "row8";
col[8] = "tow9";
for (iRow = 1; iRow <= 9; iRow++)
{
objTab1.Rows[iRow].Range.Font.Bold = 1;
for (int i = 0; i <= col.Length; i++)
{
string s = col[i];
objTab1.Rows[iRow++].Range.Text = s;
objTab1.Rows[iRow].Range.Font.Bold = 1;
}
}
objApp.Selection.TypeParagraph();
//Insert a paragraph at the end of the document.
Word.Paragraph objPara3; //define paragraph object
object oRng2 = objDoc.Bookmarks.get_Item(ref objEndOfDocFlag).Range; //go to end of the page
objPara3 = objDoc.Content.Paragraphs.Add(ref oRng2); //add paragraph at end of document
objPara3.Range.Text = "hello"; //add some text in paragraph
objPara3.Format.SpaceAfter = 10; //defind some style
objPara3.Range.InsertParagraphAfter(); //insert paragraph
//Insert a 2 x 2 table, (table with 2 row and 2 column)
Word.Table objTab2; //create table object
Word.Range objWordRng2 = objDoc.Bookmarks.get_Item(ref objEndOfDocFlag).Range; //go to end of document
objTab2 = objDoc.Tables.Add(objWordRng2, 9, 2, ref objMiss, ref objMiss); //add table object in word document
objTab2.Range.ParagraphFormat.SpaceAfter = 6;
object stylename2 = "Table Grid";
I get the following exception "the requested member of the collection does not exist"
Without fully following how you want the layout to appear. There are a couple of issues with the posted code. First in the for loops where you are adding the text to the first table, I am not sure what you are doing with the following lines:
objTab1.Rows[iRow++].Range.Text = s;
objTab1.Rows[iRow].Range.Font.Bold = 1;
The iRow++ increment in the first line is going to throw off where the row is in the table. I am guessing you may want:
objTab1.Rows[iRow].Range.Font.Bold = 1;
objTab1.Rows[iRow].Range.Text = s;
iRow++;
The other issue is how the code is getting the last paragraph like below:
object oRng2 = objDoc.Bookmarks.get_Item(ref objEndOfDocFlag).Range;
objPara3 = objDoc.Content.Paragraphs.Add(ref oRng);
The oRng2 range is the end of doc range however, the next line uses oRng which is the top of the document. Changing the add paragraphs to the proper range should fix this.
objPara3 = objDoc.Content.Paragraphs.Add(ref oRng2);
Hope this helps.

Optimal Column Width OpenOffice Calc

I'm entering data from a CSV file into a OpenOffice spreadsheet.
This code gets the a new sheet in a spreadsheet:
Public Spreadsheet getSpreadsheet(int sheetIndex, XComponent xComp)
{
XSpreadsheet xSheets = ((XSpreadsheetDocument)xComp).getSheets();
XIndexAccess xSheetIA = (XIndexAccess)xSheets;
XSpreadsheet XSheet = (XSpreadsheet)xSheetsA.getByIndex(sheetIndex).Value;
return XSheet;
}
I then have method that enters a list into a cell range one cell at a time. I want to be able to automatically set the column size for these cells. which is something like
string final DataCell;
Xspreadsheet newSheet = getSpreadsheet(sheetIndex, xComp);
int numberOfRecords = ( int numberOfColumns * int numberOfRows);
for(cellNumber = 0; cellNumber < numberOfrecords; cellNumber++)
{
XCell tableData = newSheet.getCellbyPosition(columnValue, rowValue);
((XText)tableData).setString(finalDataCell);
column Value++;
if(columnValue > = numberOfColumns)
{
rowVal++ column = 0;
}
}
After googling i have found the function:
columns.OptimalWidth = True on http://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=31292
but im unsure on how to use this. Could anyone explain this further or think of another way to have the cell autofit?
I understand the comments in the code are in Spanish I think, but the code is in English. I ran the comments through Google translate so now they are in English. I copied it from here:
//Auto Enlarge col width
private void largeurAuto(string NomCol)
{
XCellRange Range = null;
Range = Sheet.getCellRangeByName(NomCol + "1"); //Recover the range, a cell is
XColumnRowRange RCol = (XColumnRowRange)Range; //Creates a collar ranks
XTableColumns LCol = RCol.getColumns(); // Retrieves the list of passes
uno.Any Col = LCol.getByIndex(0); //Extract the first Col
XPropertySet xPropSet = (XPropertySet)Col.Value;
xPropSet.setPropertyValue("OptimalWidth", new one.Any((bool)true));
}
What this does it this: First it gets the range name and then gets the first column. The real code, though, is XpropertySet being used, which is explained REALLY well here.
public void optimalWidth(XSpreadsheet newSheet)
{
// gets the used range of the sheet
XSheetCellCursor XCursor = newSheet.createCursor();
XUsedAreaCursor xUsedCursor = (XUsedAreaCursor)XCursor;
xUsedCursor.gotoStartOfUsedArea(true);
xUsedCursor.gotoEndOfUsedArea(true);
XCellRangeAddressable nomCol = (XCellRangeAddressable)xUsedCursor;
XColumnRowRange RCol = (XColumnRowRange)nomCol;
XTableColumns LCol = RCol.getColumns();
// loops round all of the columns
for (int i = 0; i < nomCol.getRangeAddress().EndColumn;i++)
{
XPropertySet xPropSet = (XPropertySet)LCol.getByIndex(i).Value;
xPropSet.setPropertyValue("OptimalWidth", new uno.Any(true));
}
}

counting page breaks in a word doc using word interp

I've been searching the internet on how to get the page breaks in a word doc but to no avail. Microsoft offers little help on this topic. I'd appreciate any help in getting the number of page breaks using word interop. I'm using winform.
Thanks
You can count the page breaks by searching for ^012, like so:
int totalPageBreaks = 0;
Microsoft.Office.Interop.Word.Range rng;
rng = doc.Range();
rng.Collapse(WdCollapseDirection.wdCollapseStart);
while (true) {
rng.Find.ClearFormatting();
rng.Find.Text = "^012";
rng.Find.Forward = true;
rng.Find.Wrap = WdFindWrap.wdFindStop;
rng.Find.Format = false;
rng.Find.MatchCase = false;
rng.Find.MatchWholeWord = false;
rng.Find.MatchWildcards = false;
rng.Find.Execute();
if (!rng.Find.Found)
break;
// increment counter
totalPageBreaks++;
// do some processing here if you'd like
// reset the range
rng.Collapse(WdCollapseDirection.wdCollapseEnd);
}

Find text in a word document and replace it with a table

I am trying to search a word document for some specific text and then replace it with a custom table. I seem to almost have it working but it seems to add the table halfway through the previous word rather than right where it found the text.
This is my function
public void AddTableAtCursor(string tabledata,
string find,
Boolean flh = true,
string name = "Table")
{
object replaceAll = Word.WdReplace.wdReplaceAll;
Word.Range srng = Application.ActiveDocument.Content;
srng.WholeStory();
srng.Find.ClearFormatting();
srng.Find.Text = find;
srng.Find.Replacement.ClearFormatting();
srng.Find.Replacement.Text = "";
int FirstChr = srng.Text.IndexOf(find);
if (FirstChr != -1)
{
Word.Range ts =
Application.ActiveDocument.Range(FirstChr, FirstChr);
this.Application.Selection.TypeParagraph();
srng.Find.Execute(
ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref replaceAll, ref missing,
ref missing, ref missing, ref missing);
string[] rows = tabledata.Split('|');
string[] c = rows[0].Split('^');
rows[0] = null;
object styleName = "Light List - Accent 1";
Word.Table tbl = null;
Word.Range currentSelection = srng;
int hclen = c.Length;
if (TomData.IndPrices != "on") { hclen = hclen - 2; }
tbl = Application.ActiveDocument.Content.Tables.Add(
ts, rows.Length + 1, hclen);
tbl.set_Style(ref styleName);
tbl.PreferredWidth = 90;
tbl.PreferredWidthType =
Word.WdPreferredWidthType.wdPreferredWidthPercent;
// First Row, Put the name into the first cell
for (int i = 1; i <= hclen; i++)
{
if (i == 1)
{
tbl.Cell(1, i).Range.InsertBefore(name);
}
else
{
tbl.Cell(1, i).Range.InsertBefore("");
}
}
// 2nd row, put the headers in
for (int i = 1; i <= hclen; i++)
{
int t = i - 1;
tbl.Cell(2, i).Range.InsertBefore(c[t]);
}
int tblrow = 3;
// after that just put the data
for (int rc = 0; rc < rows.Length; rc++)
{
if (rows[rc] != null)
{
string[] coldata = rows[rc].Split('^');
int tblcol = 1;
int clen = coldata.Length;
if (TomData.IndPrices != "on") { clen = clen - 2; }
for (int nc = 0; nc < clen; nc++)
{
tbl.Cell(tblrow, tblcol).Range.InsertBefore(
coldata[nc]);
tblcol++;
}
tblrow++;
}
}
}
}
What am I doing wrong?
You've got lots of problems here, so I'd recommend working through 1 step at a time.
1) you've got to FIND the text you're replacing. Since you're replacing it with a table, you really can't use the REPLACEALL option of the find object, so get rid of all that. Get the CONTENT range of the document into a Range variable, the FIND from that, and then execute your find. The range that you got the FIND from will be reset to point to the specific text found (if any) and THEN you can manipulate that range.
For instance
Set myRange = ActiveDocument.Content
myRange.Find.Execute FindText:="blue", Forward:=True
If myRange.Find.Found = True Then myRange.Bold = True
2) Next, you're confusing Offsets within a string, with offsets within a document, as in this code
int FirstChr = srng.Text.IndexOf(find);
if (FirstChr != -1)
{
Word.Range ts = Application.ActiveDocument.Range(FirstChr,FirstChr);
That will sometimes, but only rarely, work. It depends on lots of stuff within Word. Better to find what you need using find and then manipulate text only with ranges.
There's a really good article here about FIND and REPLACE in word.
http://msdn.microsoft.com/en-us/library/aa211953%28office.11%29.aspx
I'd write a routine to FIND and SELECT the text you're after first. Make sure that works in all cases, THEN, using the range of the found text, work with replacing it with a table.
once you've found the text you're after

Categories

Resources