I'm currently working on a MailMerge Word-doc. It is partially filled with strings, and partially with html (which can contain tables, pictures, bold/italic/underlined text, etc.). The word doc also has a custom alignment compared to the default word alignment (so the ruler for left, top, right, bottom
is something like 1.5, 0.3, 0.3, 0.3
in my MailMerge word-doc, while the word-default it's something like 2.5, 2.5, 2.5, 2.5
.)
Now the issue is that the InsertHtml
jumps in (and seem to follow the default word-alignement, instead of our custom one), instead of being aligned by the static text and tables present in the word-doc.
I know the MailMerging uses the default MS Word functions for inserting html, so perhaps the issue lies within that default function instead of Apose's MailMerging. I was just wondering if someone knows a solution.
Here is a visual example of what the result looks like. I've included the ruler where X
is the position set on the ruler for alignement. Let's say the text we insert at the HTML part is something very basic, like plain text: "this is a test HTML text". The Word-doc template looks like this:
+ . 2 . | X 1 ............................................... 17 . | . X . |
X *Start of a table*
. ...
. Value: | {{Value}}
. *End of the table*
.
. *A bold title*
.
. {{html_Text}}
.
. *Another bold title*
.
X
29
+
But the result after MailMerging looks like this:
+ . 2 . | X 1 ............................................... 17 . | . X . |
X *Start of a table*
. ...
. Value: | 2500
. *End of the table*
.
. *A bold title*
.
. this is a test HTML text
.
. *Another bold title*
.
X
29
+
The html text is incorrectly aligned following the default Word-ruler, instead of the custom one of that document.
(PS: I know the MailMerging with brackets {{Something}}
is less used than <<Something>>
, but both work the same. I've had people question the MailMerge-syntax we use in the past, therefore this heads-up.)
Here is the relevant code in our .NET project:
Print DTO object:
public class OurObjectPrintDto
{
public OurObjectPrintDto(OurObject ob)
{
...
Value = ob.Value;
...
html_Text = ob.Text;
}
public string Value { get; private set; }
public string html_Text { get; private set; }
}
Method when we click on the Generate Document button:
[HttpGet]
public ActionResult Print(Guid id)
{
var ourObject = NhSession.GetByGuid<OurObject>(id);
var printData = new OutObjectPrintDto(ourObject);
var documentAsByteArray = _documentService.CreateMyObjectPrintAsBytes(printData);
return File(documentAsByteArray, "application/pdf");
}
CreateMyObjectPrintAsBytes
-method:
public byte[] CreateMyObjectPrintAsBytes(MyObject printData)
{
return GenerateDocument("myobject.docx", printData);
}
private byte[] GenerateDocument(string fileName, object printData)
{
if (printData == null) throw new ArgumentNullException("printData");
var path = Path.Combine(_templatePath, fileName);
using (var fileStream = new File.OpenRead(path))
{
var dataSource = new DocumentDataSource(printData);
return DocumentConverter.GenerateDocument(fileStream, dataSource);
}
}
DocumentConvert.GenerateDocument
-method:
public byte[] GenerateDocument(Stream template, DocumentDataSource dataSource)
{
var doc = new Document(template);
doc.MailMerge.UseNonMergeFields = true;
doc.MailMerge.CleanupOptions = MailMergeCleanupOption.RemoveContainingFields |
MailMergeCleanupOptions.RemoveUnusedFields |
MailMergeCleanupOptions.RemoveUnusedRegions |
MailMergeCleanupOptions.RemoveEmptyParagraphs;
doc.ResourceLoadingCallback = new ImageLoadingHandler();
// Support html MailMerge-fields
doc.MailMerge.FieldMergingCallback = new HandleMergeFieldInsertHtml();
doc.MailMerge.Execute(dataSource);
doc.MailMerge.ExecuteWithRegions((IMailMergeDataSourceRoot) dataSource);
doc.UpdateFields();
using (var memoryStream = new MemoryStream())
{
doc.Save(memoryStream, SaveFormat.Pdf);
return memoryStream.ToArray();
}
}
HandleMailMergeFieldInsertHtml
-class:
using Aspose.Words;
using Aspose.Words.Reporting;
namespace Sogyo.Util.Pdf
{
public class HandleMergeFieldInsertHtml : IFieldMergingCallback
{
// This is called when merge field is atually merged with data in the document
void IFieldMergingCallback.FieldMerging(FieldMergingArgs e)
{
// All merge field that expect HTML data should be marked with the prefix 'html_'
if (e.DocumentFieldName.StartsWith("html_") && e.FieldValue != null)
{
// Insert the text for this merge field as HTML data
var documentBuilder = new DocumentBuilder(e.Document);
documentBuilder.MoveToMergeField(e.DocumentFieldName);
documentBuilder.InsertHtml((string) e.FieldValue);
// The HTML text itself should not be inserted.
// We have already inserted it as an HTML.
e.Text = "";
}
}
void IFieldMergingCallback.ImageFieldMerging(ImageFieldMergingArgs e)
{
}
}
}
I did try to set the documentBuilder
's .PageSetup.LeftMargin
in code to change the ruler of the doc. This does change the ruler-alignment of the document, but the inserted html text still jumps in by the same amount, as if a tab is before it or something..
Ok, the problem is fixed.. As a test I tried temporary changing the out-put to .docx
instead of .pdf
, so I could better look at the tabs and such in the converted document:
doc.Save(memoryStream, SaveFormat.Pdf);
// changed to
doc.Save(memoryStream, SaveFormat.Docx);
and
return File(documentAsByteArray, "application/pdf");
// changed to
return File(documentAsByteArray, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
When I opened the converted .docx
I quickly spotted the issue.. It didn't had anything to do with the MailMerging, but with the ruler of the doc itself. The Word-doc ruler has both a grey part and a hourglass-kinda-thingy (the X
in my question).
After aligning both the hourglass-thingy AND the grey part in my Word doc on top of each other, the html text is also correctly aligned with the rest after MailMerging.