We're sorry Aspose doesn't work properply without JavaScript enabled.

Free Support Forum - aspose.com

IFieldMergingCallback is not working as expected for multiple merge records

Follow up to this thread: IFieldMergingCallback: how to highlight unmerged field


When doing a simple merge with a single record, as shown in the above thread, it works fine, but when implementing IMailMergeDataSource with multiple records, things are not working as expected. Please see the example below.

What I wanted to achieve: highlight merged fields with yellow, highlight unmerged or empty value merged fields with red.

Example template:

Template.docx

{{FirstName}} {{LastName}}

When executing the test app below, the output looks like this:

first page (correct output):

John
Doe<o:p></o:p>

second page (incorrect output):

Mike
Smith<o:p></o:p>

third page (incorrect output):

«LastName»


The expected output should be:

first page:

John Doe<o:p></o:p>

second page:

«FirstName» Smith<o:p></o:p>

third page:

Mike «LastName»


My thoughts:

I think what’s happening is that on this line:
_documentBuilder.MoveToMergeField(args.FieldName);
it moves to the first occurrence of the FieldName and not the field name of the current record, therefore inserting “Mike” into the second page instead of the third page.

Is there a correct way of implementing IFieldMergingCallback to fix this issue?

Thanks!

Test console app (please see attached zip if you want to run the sample):
class Program
{
static void Main(string[] args)
{
var doc = new Document(@“Template.docx”);
doc.MailMerge.UseNonMergeFields = true;
doc.MailMerge.FieldMergingCallback = new HighLightFieldMergingCallback();
doc.MailMerge.Execute(GetDataSource());
doc.Save(@“Output.docx”, SaveFormat.Docx);
}
<span style="color:blue;">static</span> <span style="color:#2b91af;">IMailMergeDataSource</span> GetDataSource()
{
    <span style="color:blue;">var</span> dataDictionary = <span style="color:blue;">new</span> <span style="color:#2b91af;">List</span><<span style="color:#2b91af;">IDictionary</span><<span style="color:blue;">string</span>, <span style="color:blue;">string</span>>>
    {
        <span style="color:blue;">new</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:blue;">string</span>, <span style="color:blue;">string</span>>
        {
            { <span style="color:#a31515;">"FirstName"</span>, <span style="color:#a31515;">"John"</span> },
            { <span style="color:#a31515;">"LastName"</span>, <span style="color:#a31515;">"Doe"</span> }
        },
        <span style="color:blue;">new</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:blue;">string</span>, <span style="color:blue;">string</span>>
        {
            { <span style="color:#a31515;">"FirstName"</span>, <span style="color:#a31515;">""</span> },
            { <span style="color:#a31515;">"LastName"</span>, <span style="color:#a31515;">"Smith"</span> }
        },
        <span style="color:blue;">new</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:blue;">string</span>, <span style="color:blue;">string</span>>
        {
            { <span style="color:#a31515;">"FirstName"</span>, <span style="color:#a31515;">"Mike"</span> },
            { <span style="color:#a31515;">"LastName"</span>, <span style="color:#a31515;">""</span> }
        }
    };

    <span style="color:blue;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">MailMergeDataSource</span>(dataDictionary);
}

}

public class HighLightFieldMergingCallback : IFieldMergingCallback
{
private DocumentBuilder _documentBuilder;
<span style="color:blue;">public</span> <span style="color:blue;">void</span> FieldMerging(<span style="color:#2b91af;">FieldMergingArgs</span> args)
{
    <span style="color:blue;">if</span> (_documentBuilder == <span style="color:blue;">null</span>)
        _documentBuilder = <span style="color:blue;">new</span> <span style="color:#2b91af;">DocumentBuilder</span>(args.Document);

    <span style="color:blue;">if</span> (!<span style="color:blue;">string</span>.IsNullOrWhiteSpace(args.FieldValue <span style="color:blue;">as</span> <span style="color:blue;">string</span>))
    {
        _documentBuilder.MoveToMergeField(args.FieldName);
        _documentBuilder.Font.HighlightColor = <span style="color:#2b91af;">Color</span>.Yellow;
        _documentBuilder.Write(args.FieldValue.ToString());
        args.Text = <span style="color:blue;">string</span>.Empty;
    }
    <span style="color:blue;">else</span>
    {
        <span style="color:blue;">var</span> fieldCode = args.Field.GetFieldCode().Trim();
        _documentBuilder.MoveToMergeField(args.FieldName);
        _documentBuilder.Font.HighlightColor = <span style="color:#2b91af;">Color</span>.Salmon;
        _documentBuilder.InsertField(fieldCode);
    }
}

<span style="color:blue;">public</span> <span style="color:blue;">void</span> ImageFieldMerging(<span style="color:#2b91af;">ImageFieldMergingArgs</span> args)
{

}

}

public class MailMergeDataSource : IMailMergeDataSource
{
private readonly List<IDictionary<string, string>> _dataSources;
private int _index;
<span style="color:blue;">public</span> MailMergeDataSource(<span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">IDictionary</span><<span style="color:blue;">string</span>, <span style="color:blue;">string</span>>> dataSources)
{
    _dataSources = dataSources.ToList();
    _index = -1;
}

<span style="color:blue;">public</span> <span style="color:blue;">bool</span> MoveNext()
{
    _index++;
    <span style="color:blue;">return</span> _index < _dataSources.Count;
}

<span style="color:blue;">public</span> <span style="color:blue;">bool</span> GetValue(<span style="color:blue;">string</span> fieldName, <span style="color:blue;">out</span> <span style="color:blue;">object</span> fieldValue)
{
    <span style="color:blue;">var</span> currentRecord = _dataSources[_index];
    <span style="color:blue;">try</span>
    {
        fieldValue = currentRecord[fieldName];
        <span style="color:blue;">return</span> fieldValue != <span style="color:blue;">null</span>;
    }
    <span style="color:blue;">catch</span> (<span style="color:#2b91af;">KeyNotFoundException</span>)
    {
        fieldValue = <span style="color:blue;">null</span>;
        <span style="color:blue;">return</span> <span style="color:blue;">false</span>;
    }
}

<span style="color:blue;">public</span> <span style="color:#2b91af;">IMailMergeDataSource</span> GetChildDataSource(<span style="color:blue;">string</span> tableName)
{
    <span style="color:blue;">return</span> <span style="color:blue;">null</span>;
}

<span style="color:blue;">public</span> <span style="color:blue;">string</span> TableName => <span style="color:blue;">null</span>;

}

Hi Minh,


Thanks for your inquiry. Please use following code example to achieve your requirements. Hope this helps you. Please let us know if you have any more queries.

static void Main(string[] args)<o:p></o:p>

{

var doc = new Document(@"Template.docx");

doc.MailMerge.UseNonMergeFields = true;

doc.MailMerge.FieldMergingCallback = new HighLightFieldMergingCallback();

doc.MailMerge.Execute(GetDataSource());

DocumentBuilder builder = new DocumentBuilder(doc);

foreach (Bookmark bookmark in doc.Range.Bookmarks)

{

if (bookmark.Name.StartsWith("bm_"))

{

builder.MoveToBookmark(bookmark.Name);

builder.Font.HighlightColor = Color.Salmon;

builder.InsertField(@"MERGEFIELD " + bookmark.Name.Split('_')[1] + @" \* MERGEFORMAT");

}

}

doc.Save(@"Output.docx", SaveFormat.Docx);

}

static IMailMergeDataSource GetDataSource()

{

var dataDictionary = new List<IDictionary<string, string>>

{

new Dictionary<string, string>

{

{ "FirstName", "John" },

{ "LastName", "Doe" }

},

new Dictionary<string, string>

{

{ "FirstName", "" },

{ "LastName", "Smith" }

},

new Dictionary<string, string>

{

{ "FirstName", "Mike" },

{ "LastName", "" }

}

};

return new MailMergeDataSource(dataDictionary);

}

}

public class HighLightFieldMergingCallback : IFieldMergingCallback

{

private DocumentBuilder _documentBuilder;

private int i = 1;

public void FieldMerging(FieldMergingArgs args)

{

if (_documentBuilder == null)

_documentBuilder = new DocumentBuilder(args.Document);

if (!string.IsNullOrWhiteSpace(args.FieldValue as string))

{

_documentBuilder.MoveToMergeField(args.FieldName);

_documentBuilder.Font.HighlightColor = Color.Yellow;

_documentBuilder.Write(args.FieldValue.ToString());

args.Text = string.Empty;

}

else

{

var fieldCode = args.Field.GetFieldCode().Trim();

_documentBuilder.MoveToMergeField(args.FieldName);

_documentBuilder.StartBookmark("bm_" + args.FieldName + "_" + i);

_documentBuilder.EndBookmark("bm_" + args.FieldName + "_" + i);

i++;

}

}

public void ImageFieldMerging(ImageFieldMergingArgs args)

{

}