Gembox Document Mail Mergin with custom object

Hi,

I need to generate a Word document that will receive as the input document.MailMerge.Execute() following enumerable: Dictionary<string, object>.

The object of the dictionary will be a complex object and not a simple type such as a string or an integer. Indeed, my requirement is to display 2 sets of data and their differences.

For instance, in the first set of data, I have a property call Amount = 10 and in the second set I have Amount = 20. My current code builds a Dictionary<string, object> instance with object being a complex Difference class:

public class Difference
{
    public string Label { get; set; }
    public DiffState State { get; set; }
    public object SourceValue { get; set; } = string.Empty;
    public object TargetValue { get; set; } = string.Empty;
    public string Color { get; set; } = string.Empty;
} 

DiffState is an enum that shows the state between source and target data such as: unchanged, added, removed, and changed.

How can I access my Difference instance using Word merge fields knowing the key of the dictionary? For example, I would like to generate in the Word document something like:

Amout : 20 (old: 10)

Note: 20 would be the Difference.SourceValue and 10 would be Difference.TargetValue

Other question: I need to show the line only if Difference.State != Unchanged. Is it possible to do this?

Thanks.

Hi Omid,

Try using this:

Amount: «Amount.SourceValue» (old: «Amount.TargetValue»)

After executing the mail merge process with this source:

var document = DocumentModel.Load("input.docx");
var source = new Dictionary<string, object>();
source.Add("Amount", new Difference() { SourceValue = 20, TargetValue = 10 });
document.MailMerge.Execute(source);
document.Save("output.docx");

The result will be:

Amount: 20 (old:10)

Also regarding the DiffState, you can put this condition in an IF field:

For example, like this:
{ IF "{ MERGEFIELD Amount.State }" <> "Unchanged" "Amount: { MERGEFIELD Amount.SourceValue } (old:{ MERGEFIELD Amount.TargetValue })" "" }

I hope this helps.

Regards,
Mario

Hi Mario,

Thanks for the answer. I already tried to navigate through the object but I always end up with the error message: Cannot save a PDF document with no pages

It’s like the data source I give to document.MailMerge.Execute() is not compatible with what I use in the Word template.

In addition to the Amount, I have an Id property also with a SourceValue and TargetValue and I use it like this: { MERGEFIELD Id.SourceVale}
But I always get the error message as the merge process ends up by having no field to merge.

Let me precise that in my code, I use FieldMerging event to handle custom property such as Html:xxxxx or Date:xxxxx :

document.MailMerge.FieldMerging += (sender, e) =>
{
if (e?.Value == null || !e.IsValueFound)
return;
//Removed for clarity
}

In my case, all the fields ends up with e.Value == NULL so the code returns. I don’t know if it can have an impact.

Thanks.

Please send us a small Visual Studio project that reproduces your issue so that we can investigate it.
You can send it via email or support ticket, see the Contact page.

Hi Mario,

I found the issue: fields were not merging as expected because I declared the Dictionary the following way:
var source = new Dictionary<string, Difference>();

When I change to:

var source = new Dictionary<string, object>();

It works as expected.

Thanks.

Hi Mario,

I have a second issue. As my model has nested objects, I create a dictionary with keys that can be like “Customer. Contact email”:

source.Add(“Customer.Contact email”, new Difference() { SourceValue = “test1@test.com”, TargetValue = “test2@test.com” });

In my word document I add a merge field :

{ MERGEFIELD Customer.Contact email.TargetValue }

Unfortunately it doesn’t work. Any idea?

By the way, computed dictionary keys such as “Customer.Conact email” works when dictionary object is a base type (ex: string).

First, note that you’ll need to quote those MERGEFIELD names, like this:

{ MERGEFIELD "Customer.Contact email.TargetValue" }

Second, I’m afraid you cannot mix the meaning of ‘.’ character. In other words, either dots represent the sub-properties or they don’t.

So, if they represent sub-properties you should have two nested sources for those two dots.
For instance, something like this:

var nestedSource2 = new Dictionary<string, object>();
nestedSource2.Add("SourceValue", "test1@test.com");
nestedSource2.Add("TargetValue", "test2@test.com");

var nestedSource1 = new Dictionary<string, object>();
nestedSource1.Add("Contact email", nestedSource2);

var source = new Dictionary<string, object>();
source.Add("Customer", nestedSource1);

document.MailMerge.Execute(source);

I hope this helps.

Regards,
Mario

Ok thanks Mario. It makes sense.

In the meantime I changed the way I generate the property names so “Customer.Contact email” is now generated as “CustomerContactEmail” so I don’t have the issue anymore.