This example shows how to Generate reports using a custom data source (collection of custom classes 'Actor' and 'Order').
Create a template in MS Word with Merge Fields or use a ready file «OrdersTemplate.docx».
After execution of mail merge method we'll get the «Orders.docx» as result.
Complete code
using System.Collections.Generic;
using SautinSoft.Document;
using SautinSoft.Document.MailMerging;
namespace Sample
{
class Sample
{
static void Main(string[] args)
{
// Get your free 100-day key here:
// https://sautinsoft.com/start-for-free/
CustomDataSource();
}
/// <summary>
/// Generate reports using a custom data source (collection of custom classes Actor and Order).
/// </summary>
/// <remarks>
/// Details: https://sautinsoft.com/products/document/help/net/developer-guide/mail-merge-custom-data-source-net-csharp-vb.php
/// </remarks>
static void CustomDataSource()
{
// Populate some data that we will use in the mail merge.
List<Actor> actors = new List<Actor>();
actors.Add(new Actor("Arnold Schwarzenegger", "12989 Chalon Road, Los Angeles, CA 90049"));
actors.Add(new Actor("Sylvester Stallone", "30 Beverly Park Terrace, Beverly Hills, CA 90210"));
// Populate some data for nesting in the mail merge.
actors[0].Orders.Add(new Order("Bowflex SelectTech 1090 Adjustable Dumbbell", 2));
actors[0].Orders.Add(new Order("Gold's Gym Kettlebell Kit, 5-15 Lbs.", 1));
actors[1].Orders.Add(new Order("Weider Cast Iron Olympic Hammertone Weight Set, 300 Lb.", 1));
// Load the template document.
DocumentCore dc = DocumentCore.Load(@"..\..\..\OrdersTemplate.docx");
// To be able to mail merge from your own data source, it must be wrapped into an object that implements the IMailMergeDataSource interface.
CustomMailMergeDataSource customDataSource = new CustomMailMergeDataSource(actors);
// Execute the mail merge.
dc.MailMerge.Execute(customDataSource);
string resultPath = "Orders.docx";
// Save the output to file.
dc.Save(resultPath);
// Open the result for demonstration purposes.
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(resultPath) { UseShellExecute = true });
}
/// <summary>
/// An example of a class that contain actor's data.
/// </summary>
public class Actor
{
private string _fullName;
private string _address;
private List<Order> _orders;
public string FullName
{
get { return _fullName; }
set { _fullName = value; }
}
public string Address
{
get { return _address; }
set { _address = value; }
}
public List<Order> Orders
{
get { return _orders; }
set { _orders = value; }
}
public Actor(string fullName, string address)
{
_fullName = fullName;
_address = address;
_orders = new List<Order>();
}
}
/// <summary>
/// An example of a class that contain order's data.
/// </summary>
public class Order
{
private string _name;
private int _quantity;
public string Name
{
get { return _name; }
set { _name = value; }
}
public int Quantity
{
get { return _quantity; }
set { _quantity = value; }
}
public Order(string name, int quantity)
{
_name = name;
_quantity = quantity;
}
}
/// <summary>
/// A custom mail merge data source that allows SautinSoft.Document to retrieve data from Actor objects.
/// </summary>
public class CustomMailMergeDataSource : IMailMergeDataSource
{
private readonly List<Actor> _actors;
private int _recordIndex;
/// <summary>
/// The name of the data source.
/// </summary>
public string Name
{
get { return "Actor"; }
}
/// <summary>
/// SautinSoft.Document calls this method to get a value for every data field.
/// </summary>
public bool TryGetValue(string valueName, out object value)
{
switch (valueName)
{
case "FullName":
value = _actors[_recordIndex].FullName;
return true;
case "Address":
value = _actors[_recordIndex].Address;
return true;
default:
// A field with this name was not found
value = null;
return false;
}
}
/// <summary>
/// A standard implementation for moving to a next record in a collection.
/// </summary>
public bool MoveNext()
{
return (++_recordIndex < _actors.Count);
}
public IMailMergeDataSource GetChildDataSource(string sourceName)
{
switch (sourceName)
{
case "Order":
return new OrderMailMergeDataSource(_actors[_recordIndex].Orders);
default:
return null;
}
}
public CustomMailMergeDataSource(List<Actor> actors)
{
_actors = actors;
// When the data source is initialized, it must be positioned before the first record.
_recordIndex = -1;
}
}
public class OrderMailMergeDataSource : IMailMergeDataSource
{
private readonly List<Order> _orders;
private int _recordIndex;
/// <summary>
/// The name of the data source.
/// </summary>
public string Name
{
get { return "Order"; }
}
/// <summary>
/// SautinSoft.Document calls this method to get a value for every data field.
/// </summary>
public bool TryGetValue(string valueName, out object value)
{
switch (valueName)
{
case "Name":
value = _orders[_recordIndex].Name;
return true;
case "Quantity":
value = _orders[_recordIndex].Quantity;
return true;
default:
// A field with this name was not found
value = null;
return false;
}
}
/// <summary>
/// A standard implementation for moving to a next record in a collection.
/// </summary>
public bool MoveNext()
{
return (++_recordIndex < _orders.Count);
}
// Return null because Order haven't any child elements.
public IMailMergeDataSource GetChildDataSource(string tableName)
{
return null;
}
public OrderMailMergeDataSource(List<Order> orders)
{
_orders = orders;
// When the data source is initialized, it must be positioned before the first record.
_recordIndex = -1;
}
}
}
}
Imports System.Collections.Generic
Imports SautinSoft.Document
Imports SautinSoft.Document.MailMerging
Namespace Sample
Friend Class Sample
Shared Sub Main(ByVal args() As String)
CustomDataSource()
End Sub
''' Get your free 100-day key here:
''' https://sautinsoft.com/start-for-free/
''' <summary>
''' Generate reports using a custom data source (collection of custom classes Actor and Order).
''' </summary>
''' <remarks>
''' Details: https://sautinsoft.com/products/document/help/net/developer-guide/mail-merge-custom-data-source-net-csharp-vb.php
''' </remarks>
Private Shared Sub CustomDataSource()
' Populate some data that we will use in the mail merge.
Dim actors As New List(Of Actor)()
actors.Add(New Actor("Arnold Schwarzenegger", "12989 Chalon Road, Los Angeles, CA 90049"))
actors.Add(New Actor("Sylvester Stallone", "30 Beverly Park Terrace, Beverly Hills, CA 90210"))
' Populate some data for nesting in the mail merge.
actors(0).Orders.Add(New Order("Bowflex SelectTech 1090 Adjustable Dumbbell", 2))
actors(0).Orders.Add(New Order("Gold's Gym Kettlebell Kit, 5-15 Lbs.", 1))
actors(1).Orders.Add(New Order("Weider Cast Iron Olympic Hammertone Weight Set, 300 Lb.", 1))
' Load the template document.
Dim dc As DocumentCore = DocumentCore.Load("..\..\..\OrdersTemplate.docx")
' To be able to mail merge from your own data source, it must be wrapped into an object that implements the IMailMergeDataSource interface.
'INSTANT VB NOTE: The variable customDataSource was renamed since Visual Basic does not handle local variables named the same as class members well:
Dim customDataSource_Renamed As New CustomMailMergeDataSource(actors)
' Execute the mail merge.
dc.MailMerge.Execute(customDataSource_Renamed)
Dim resultPath As String = "Orders.docx"
' Save the output to file.
dc.Save(resultPath)
' Open the result for demonstration purposes.
System.Diagnostics.Process.Start(New System.Diagnostics.ProcessStartInfo(resultPath) With {.UseShellExecute = True})
End Sub
''' <summary>
''' An example of a class that contain actor's data.
''' </summary>
Public Class Actor
Private _fullName As String
Private _address As String
Private _orders As List(Of Order)
Public Property FullName() As String
Get
Return _fullName
End Get
Set(ByVal value As String)
_fullName = value
End Set
End Property
Public Property Address() As String
Get
Return _address
End Get
Set(ByVal value As String)
_address = value
End Set
End Property
Public Property Orders() As List(Of Order)
Get
Return _orders
End Get
Set(ByVal value As List(Of Order))
_orders = value
End Set
End Property
Public Sub New(ByVal fullName As String, ByVal address As String)
_fullName = fullName
_address = address
_orders = New List(Of Order)()
End Sub
End Class
''' <summary>
''' An example of a class that contain order's data.
''' </summary>
Public Class Order
Private _name As String
Private _quantity As Integer
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Property Quantity() As Integer
Get
Return _quantity
End Get
Set(ByVal value As Integer)
_quantity = value
End Set
End Property
Public Sub New(ByVal name As String, ByVal quantity As Integer)
_name = name
_quantity = quantity
End Sub
End Class
''' <summary>
''' A custom mail merge data source that allows SautinSoft.Document to retrieve data from Actor objects.
''' </summary>
Public Class CustomMailMergeDataSource
Implements IMailMergeDataSource
Private ReadOnly _actors As List(Of Actor)
Private _recordIndex As Integer
''' <summary>
''' The name of the data source.
''' </summary>
Public ReadOnly Property Name() As String Implements IMailMergeDataSource.Name
Get
Return "Actor"
End Get
End Property
''' <summary>
''' SautinSoft.Document calls this method to get a value for every data field.
''' </summary>
Public Function TryGetValue(ByVal valueName As String, <System.Runtime.InteropServices.Out()> ByRef value As Object) As Boolean Implements IMailMergeDataSource.TryGetValue
Select Case valueName
Case "FullName"
value = _actors(_recordIndex).FullName
Return True
Case "Address"
value = _actors(_recordIndex).Address
Return True
Case Else
' A field with this name was not found
value = Nothing
Return False
End Select
End Function
''' <summary>
''' A standard implementation for moving to a next record in a collection.
''' </summary>
Public Function MoveNext() As Boolean Implements IMailMergeDataSource.MoveNext
_recordIndex += 1
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: return (++_recordIndex < _actors.Count);
Return (_recordIndex < _actors.Count)
End Function
Public Function GetChildDataSource(ByVal sourceName As String) As IMailMergeDataSource Implements IMailMergeDataSource.GetChildDataSource
Select Case sourceName
Case "Order"
Return New OrderMailMergeDataSource(_actors(_recordIndex).Orders)
Case Else
Return Nothing
End Select
End Function
Public Sub New(ByVal actors As List(Of Actor))
_actors = actors
' When the data source is initialized, it must be positioned before the first record.
_recordIndex = -1
End Sub
End Class
Public Class OrderMailMergeDataSource
Implements IMailMergeDataSource
Private ReadOnly _orders As List(Of Order)
Private _recordIndex As Integer
''' <summary>
''' The name of the data source.
''' </summary>
Public ReadOnly Property Name() As String Implements IMailMergeDataSource.Name
Get
Return "Order"
End Get
End Property
''' <summary>
''' SautinSoft.Document calls this method to get a value for every data field.
''' </summary>
Public Function TryGetValue(ByVal valueName As String, <System.Runtime.InteropServices.Out()> ByRef value As Object) As Boolean Implements IMailMergeDataSource.TryGetValue
Select Case valueName
Case "Name"
value = _orders(_recordIndex).Name
Return True
Case "Quantity"
value = _orders(_recordIndex).Quantity
Return True
Case Else
' A field with this name was not found
value = Nothing
Return False
End Select
End Function
''' <summary>
''' A standard implementation for moving to a next record in a collection.
''' </summary>
Public Function MoveNext() As Boolean Implements IMailMergeDataSource.MoveNext
_recordIndex += 1
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: return (++_recordIndex < _orders.Count);
Return (_recordIndex < _orders.Count)
End Function
' Return null because Order haven't any child elements.
Public Function GetChildDataSource(ByVal tableName As String) As IMailMergeDataSource Implements IMailMergeDataSource.GetChildDataSource
Return Nothing
End Function
Public Sub New(ByVal orders As List(Of Order))
_orders = orders
' When the data source is initialized, it must be positioned before the first record.
_recordIndex = -1
End Sub
End Class
End Class
End Namespace
If you need a new code example or have a question: email us at support@sautinsoft.com or ask at Online Chat (right-bottom corner of this page) or use the Form below: