I have some VBA code that iterates through a document to remove tables from a document. The following code works fine in VBA:
Set wrdDoc = ThisDocument
With wrdDoc
For Each tbl In wrdDoc.Tables
tbl.Select
Selection.Delete
Next tbl
End With
Unfortunately, I cannot easily translate this code to C#, presumably because there is a newer Range.Find method. Here are three things I tried, each failing.
First attempt (re-write of the VBA code):
foreach (var item in doc.Tables)
{
item.Delete; //NOPE! No "Delete" function.
}
I tried this:
doc = app.Documents.Open(sourceFolderAndFile); //sourceFolderAndFile opens a standard word document.
var rng = doc.Tables;
foreach(var item in rng)
{
item.Delete; //NOPE! No "Delete" function.
}
I also tried this:
doc = app.Documents.Open(sourceFolderAndFile); //sourceFolderAndFile opens a standard word document.
var rng = doc.Tables;
Range.Find.Execute(... //NOPE! No Range.Find available for the table collection.
...
Could someone please help me understand how I can use C# and Word Interop (Word 2013 and 2016) to iterate through a document, find a table, and then perform a function, like selecting it, deleting it, or replacing it?
Thanks!
It took me some time to figure this answer out. With all the code samples online, I missed the need to create an app. For posterity, here is how I resolved the problem.
Make sure you have a Using statement, like this:
using MsWord = Microsoft.Office.Interop.Word;
Open the document and then work with the new msWord reference, the range, and the table. I provide a basic example below:
//open the document.
doc = app.Documents.Open(sourceFolderAndFile, ReadOnly: true, ConfirmConversions: false);
//iterate through the tables and delete them.
foreach (MsWord.Table table in doc.Tables)
{
//select the area where the table is located and delete it.
MsWord.Range rng = table.Range;
rng.SetRange(table.Range.End, table.Range.End);
table.Delete();
}
//don't forget doc.close and app.quit to clean up memory.
You can use the Range (rng) to replace the table with other items, like text, images, etc.
Related
I'm looking for a solution in ASPOSE .Net to decrement the NUMPAGES. Reason is that I don't want to count the last page of the document. Here is what I tried so far:
builder.Write("Page ");
builder.InsertField("Page", "");
builder.Write(" of ");
builder.InsertField("NUMPAGES", $"{(doc.PageCount - 1)}");
// Another try in separate build
builder.InsertField("NUMPAGES - 1", "");
// Another try in separate build
builder.InsertField("NUMPAGES", "NUMPAGES - 1");
Document either doesn't display anything or count the last page as well.
You should use formula and nested NUMPAGES field to get the desired output. Field code in your MS Word document should look like this:
{={NUMPAGES}-1}. To insert such field using Aspose.Words you can use code like this:
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
// Insert formula field
Field formula = builder.InsertField("=", "");
// Move document builder inside field code of the inserted field
// And put NUMPAGES field in it.
builder.MoveTo(formula.Separator);
builder.InsertField("NUMPAGES");
builder.Write("-1");
doc.UpdateFields();
doc.Save(#"C:\Temp\out.docx");
Please see Aspose.Words documentation to learn how to work with fields.
I need to create a new word 2016 file, using VS2017, insert content (that's the easy part), and also to control it like doing the following:
Merge certain cells in same row, or same column
Define Right to Left or LTR
color the text/the background.
and more similar tasks.
I can open a document using
using Microsoft.Office;
using Word = Microsoft.Office.Interop.Word;
I can add text and save the document, yet still I don't see a way to fine control the color/direction and more parameters. After reading the documentation, it seems that this is probably not supported, unless I missed it.
I would appreciate if anyone can guide to a detailed documentation how to edit a word file from C# program.
Anyway, I can bypass it by creating an excel file which is simple using Interop and then insert it.
Here is a working solution for merging cells in a table, using VS2017 c#
var doc = DocX.Create(word_fname);
Table table = doc.AddTable(tableSize, 3);
table.Rows[row_cnt].MergeCells(1, 2); // to merge the 2nd & 3rd cells in the specific row
I have a word document template which contains several form fields that need to be filled using c# code.
below is the document image
The code below is used to reach and fill the document form fields,
But when i reach the table sections sometimes the rows need to be filled are more than what is pre defined inside the template.
red marked area is the table which i want to fill it with data and create as many rows as needed.
the code i use for filling the data is
string fileName = Path.GetTempFileName();
File.WriteAllBytes(fileName, Properties.Resources.DocumentTemplate);
Word.Application word = new Word.Application();
Word.Document doc = new Word.Document();
doc = word.Documents.Add(fileName);
doc.Activate();
doc.FormFields["file_num"].Range.Text = "some text";
doc.FormFields["fam_size"].Range.Text = "another text";
doc.FormFields["nationality"].Range.Text = "another text";
for(int i =0; i< rowsInDatabaseCount; i++)
{
//i don't know how to add row and reach each form field inside
}
I hope someone can help me on how to achieve what i want.
Thank you in advance...
There are multiple ways to handle that.
1) Since the data is coming from a database, one way is to use InsertDatabase method.
2) You could insert the block as tab or comma separated text then convert to a table using ConvertToTable() method.
3) You might use Rows and Cols collections (of Table) and .Add method to add new rows.
4) You might instead create your template as an XSL and transform data (XML) using that XSL to generate final HTM. Word is able to open an HTM file.
(All these options worked for me in "resume", "test results" ... creations which have similar layouts to the ones you gave. I found final option 4 to be the most dynamic one, where end users could define their own templates using simple HTML editors - worked better than word templates for me).
In ms word2010 I have a bookmark with bookmark name: nameOfBookmark
Now the bookmark content could be anything from just text to a mix of pictures, tables and whatever you could think of putting in a word document.
The problem is as following:
I've got my bookmark with some contents I want to delete. However each time I try to delete the contents it also deletes my bookmark which I want to keep.
I've tried this, which simply deletes the whole thing:
public void cleanBookmark(string bookmark)
{
var start = currentDocument.Bookmarks[nameOfBookmark].Start;
var end = currentDocument.Bookmarks[nameOfBookmark].End;
Word.Range range = currentDocument.Range(start, end);
range.Delete();
}
I've also tried to set the range to this:
Word.Range range = currentDocument.Range(start +1, end -1);
But then I end up with a bookmark that still contains the first and the last character of the content I wanted to delete.
Well I wonder why I have to keep answering my own questions, please notify me if you think it could be something about the way I ask questions.
Anyway I found a solution after a bit more research and it seems like the thing I want simply can't be done or at least not the way I thought it could be done.
If you delete the contents of a bookmark it also deletes the bookmark. So what you have to do is to store the name and range of the bookmark in a local variable and then add the bookmark again after deleting it.
public void cleanBookmark(string bookmark)
{
var start = currentDocument.Bookmarks[bookmark].Start;
var end = currentDocument.Bookmarks[bookmark].End;
Word.Range range = currentDocument.Range(start, end);
range.Delete();
//The Delete() only deletes text so if you got tables in the doc it leaves the tables empty.
//The following removes the tables in the current range.
if (range.Tables.Count != 0)
{
for (int i = 1; i <= range.Tables.Count; i++)
{
range.Tables[i].Delete();
}
}
currentDocument.Bookmarks.Add(bookmark, range);
}
If you want to read more about this topic see this question.
I have found that if you convert your text into a table and insert the single I beam bookmark in the cell where you need it to go, the table protects the bookmark even if you delete the content. Then once you have worked out all of your vba for the form, if you convert the form into a dotm, the users shouldn't have any issue with removing the bookmarks by accident and you having to troubleshoot the form to fix their mistake.
You can try this:
ActiveDocument.Bookmarks("name").Range.Characters.First.Delete
P.S.
Still trying to solve for multiple bookmarks.
For sure many people will encounter the same problem — as I did, too.
The difference is that I am programming in VBA (not C#).
Some search led me to the ultimate solution: see
The Anchorange (by Gregory K. Maxey)
Thus I designed the following, quite simple procedure:
Sub PasteIntoBookmark_Test()
Dim BookRange As Word.Range, NewText As String, BookName As String
NewText = ""
BookName = "Name"
If ActiveDocument.Bookmarks.Exists(BookName) Then
Set BookRange = ActiveDocument.Bookmarks(BookName).Range
Debug.Print BookRange.Text
BookRange.Text = NewText
ActiveDocument.Bookmarks.Add BookName, BookRange
Debug.Print BookRange.Text
If ActiveDocument.Bookmarks.Exists(BookName) Then
Debug.Print "Bookmark " & BookName & " still exists"
Else ' Just in case the above wouldn't work (but it does):
With ActiveDocument.Bookmarks
.Add Range:=BookRange, Name:=BookName
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
End If
Else
Stop
End If
End Sub
In this way one can easily clear a bookmark without deleting it !
Of course one can later on write new text into this bookmark.
I have a template Word document which i fill details into with openXML SDK 2.0 (using c#).
I also need to insert a table into file, and i found this tutorial on MSDN.
But - the example is appending the table to the end of the document, and I want it to be somewhere in the middle.
I may need to replace this line:
doc.MainDocumentPart.Document.Body.Append(table);
with something else. (The full code is in the link above).
Please help me.. I found nothing yet.
Thanks.
One way to do this may be to use Content Controls as placeholders to insert the table into them from code.
var myContentControl = doc.MainDocumentPart.Document.Body.Descendants<SdtBlock>()
.Where(e => e.Descendants<SdtAlias>().FirstOrDefault().Val == "myTablePlaceholder").FirstOrDefault();
SdtContentBlock sdtContentBlock1 = new SdtContentBlock();
sdtContentBlock1.Append(table); // Your table
myContentControl.Append(sdtContentBlock1);