Mail Merge with two different data sources

Hello there,

I have been testing Mail Merge feature with one data source till now as:

ProMailMergeDataSource mmDataSource = new PropMailMergeDataSource(new List());
objDocument.MailMerge.Execute(mmDataSource);

So, whatever fields I needed to replace were all coming from the custom object, MyObject.

Now, I have another requirement to have fields to be replaced during mail merge from two different objects say, MyObject1 and MyObject2.

One option for me is to create another class that will be essentially MyObject1+MyObject2.

Can you please suggest of any other approach to achive same, where I can mail merge fields from two separate objects?

Thank you!

Hi

Thanks for your request. I think the technique you mentioned (by using IMailMergeDatasource) is the best way to achieve this.

Best regards.

Thank you Alexey for your response.

That’s fine if all the mail merge fields belong to one custom object type.

But what if my document contains mail merge fields some of which belong to one custom object type(say, MyObject1) while other fields in the same document are associated to other custom object type(say, MyObject2).

I am not able to see any other way other than creating a separate custom object type which will be a combination of MyObject1+MyObject2 and then use this new object type for setting the data source for mail merge.

Could you please suggest some other good approach to achieve above?

Thank you!

Hi

Thanks for your request. I think, you can try using IMailMergeDataSource, like shown in the example below:

// Create Datasource.
MyMailMergeDataSource dataSource = new MyMailMergeDataSource(null);
// Add few items.
dataSource.AddItem(new object[] { new MyClass1("item1", "item2"), new MyClass2("item3", "item4") });
dataSource.AddItem(new object[] { new MyClass2("item3_1", "item4_1"), new MyClass1("item1_1", "item2_1") });
// open template
Document doc = new Document(@"Test001\in.doc");
// Execute mail merge.
doc.MailMerge.Execute(dataSource);
// Save output document.
doc.Save(@"Test001\out.doc");
private class MyMailMergeDataSource : IMailMergeDataSource
{
    public MyMailMergeDataSource(string tableName)
    {
        mTableName = tableName;
        mDataCollection = new List<Dictionary<string, object>>();
        // When the data source is initialized, it must be positioned before the first record.
        mRecordIndex = -1;
    }

    ///
    /// Adds new item into the datasource. Item is array of objects, which contain values of fields.
    ///
    public void AddItem(object[] item)
    {
        Dictionary<string, object> nameValueCollection = new Dictionary<string, object>();
        foreach (object part in item)
        {
            // Get type of current object
            Type curentRecordType = part.GetType();
            // Use reflection to get properties of the current object.
            PropertyInfo[] properties = curentRecordType.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                string name = property.Name;
                object value = property.GetValue(part, null);
                nameValueCollection[name] = value;
            }
        }
        // Add name value collection to the data collection.
        mDataCollection.Add(nameValueCollection);
    }

    ///
    /// A standard implementation for moving to a next record in a collection.
    ///
    public bool MoveNext()
    {
        if (!IsEof)
            mRecordIndex++;
        return (!IsEof);
    }

    public bool GetValue(string fieldName, out object fieldValue)
    {
        fieldValue = mDataCollection[mRecordIndex][fieldName];
        return mDataCollection[mRecordIndex].ContainsKey(fieldName);
    }

    public IMailMergeDataSource GetChildDataSource(string tableName)
    {
        return null;
    }

    ///
    /// The name of the data source. Used by Aspose.Words only when executing mail merge with repeatable regions.
    ///
    public string TableName
    {
        get { return mTableName; }
    }

    private bool IsEof
    {
        get { return (mRecordIndex >= mDataCollection.Count); }
    }

    private readonly string mTableName;
    private readonly List<Dictionary<string, object>> mDataCollection;
    private int mRecordIndex;
}

// These are test classes.
private class MyClass1
{
    public MyClass1(string item1, string item2)
    {
        mItem1 = item1;
        mItem2 = item2;
    }

    public string Item1
    {
        get { return mItem1; }
    }

    public string Item2
    {
        get { return mItem2; }
    }
    private string mItem1;
    private string mItem2;
}

private class MyClass2
{
    public MyClass2(string item3, string item4)
    {
        mItem3 = item3;
        mItem4 = item4;
    }

    public string Item3
    {
        get { return mItem3; }
    }

    public string Item4
    {
        get { return mItem4; }
    }

    private string mItem3;
    private string mItem4;
}

Hope this helps.

Best regards.