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?
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;
}