The DataSourceManager explained

The DataSourceManager encapsulates the complete handling, logic and ready-to-use dialog boxes for the reporting template creation task. Essentially, the DataSourceManager provides all information required to create a fully-featured template designer. Like with MailMerge, a data source can be loaded from a DataSet, DataTable, Json, an object or XML. In this sample, a simple .NET class is used as a data source. The following screenshot shows this sample that illustrates the typical work-flow of a template designer.

After clicking the button Load Data Source, a new instance of the DocumentServer.DataSources.DataSourceManager is created and the data object is loaded.

[C#]
Order order = new Order()
{
    OrderID = 123,
    Customer = new Customer()
    {
        Name = "Peter Welch"
    },
    OrderItems = new List<OrderItem>()
    {
        new OrderItem() {
            Product = new Product() {
                Name = "Product A" },
            Quantity = 2 }
    }
};

dsManager = new DataSourceManager();
dsManager.LoadSingleObject(order);
[Visual Basic]
Dim order As New Order() With { _
	.OrderID = 123, _
	.Customer = New Customer() With { _
		.Name = "Peter Welch" _
	}, _
	.OrderItems = New List(Of OrderItem)() From { _
		New OrderItem() With { _
			.Product = New Product() With { _
				.Name = "Product A" _
			}, _
			.Quantity = 2 _
		} _
	} _
}

dsManager = New DataSourceManager()
dsManager.LoadSingleObject(order)

When a data source is loaded into the DocumentServer.DataSources.DataSourceManager, a ComboBox is bound to all available DataTables. Additionally, the events DocumentServer.DataSources.DataSourceManager.PossibleMergeFieldColumnsChanged and DocumentServer.DataSources.DataSourceManager.PossibleMergeBlockTablesChanged are attached to update two other ComboBoxes that list the available merge fields and merge blocks.

[C#]
dsManager.PossibleMergeFieldColumnsChanged += 
    DsManager_PossibleMergeFieldColumnsChanged;
dsManager.PossibleMergeBlockTablesChanged += 
    DsManager_PossibleMergeBlockTablesChanged;

cbMasterTable.DataSource = 
    dsManager.DataTables.ToList<DataTableInfo>();
cbMasterTable.DisplayMember = "TableName";
[Visual Basic]
AddHandler dsManager.PossibleMergeFieldColumnsChanged, AddressOf DsManager_PossibleMergeFieldColumnsChanged
AddHandler dsManager.PossibleMergeBlockTablesChanged, AddressOf DsManager_PossibleMergeBlockTablesChanged

cbMasterTable.DataSource = dsManager.DataTables.ToList()
cbMasterTable.DisplayMember = "TableName"

When the internal master table is changed, the ComboBoxes are updated with the available fields and blocks:

[C#]
private void DsManager_PossibleMergeBlockTablesChanged(object sender, EventArgs e)
{
	cbMergeBlocks.Text = "";
    cbMergeBlocks.DataSource =
        dsManager.PossibleMergeBlockTables.ToList<DataTableInfo>();
    cbMergeBlocks.DisplayMember = "TableName";
}

private void DsManager_PossibleMergeFieldColumnsChanged(object sender, EventArgs e)
{
    cbMergeFields.Text = "";
    cbMergeFields.DataSource =
        dsManager.PossibleMergeFieldColumns.ToList<DataColumnInfo>();
    cbMergeFields.DisplayMember = "ColumnName";
}
[Visual Basic]
Private Sub DsManager_PossibleMergeBlockTablesChanged(sender As Object, e As EventArgs)
	cbMergeBlocks.Text = ""
	cbMergeBlocks.DataSource = dsManager.PossibleMergeBlockTables.ToList()
	cbMergeBlocks.DisplayMember = "TableName"
End Sub

Private Sub DsManager_PossibleMergeFieldColumnsChanged(sender As Object, e As EventArgs)
	cbMergeFields.Text = ""
	cbMergeFields.DataSource = dsManager.PossibleMergeFieldColumns.ToList()
	cbMergeFields.DisplayMember = "ColumnName"
End Sub

If the input position is inside a merge block, only the available fields and blocks inside this block should be available. Therefore, the TextControl.SubTextPartEntered event is used to define a new internal master table. The ComboBoxes are updated automatically through the attached events.

[C#]
private void textControl1_SubTextPartEntered(object sender, 
                                             TXTextControl.SubTextPartEventArgs e)
{
    if (DataSourceManager.IsMergeBlock(e.SubTextPart))
    {
        if(dsManager.DataTables.Contains(e.SubTextPart.Name.Remove(0, 5)))
            dsManager.MasterDataTableInfo = 
            dsManager.DataTables[e.SubTextPart.Name.Remove(0,5)];
    }
}

private void textControl1_SubTextPartLeft(object sender, 
                                          TXTextControl.SubTextPartEventArgs e)
{
    dsManager.MasterDataTableInfo = cbMasterTable.SelectedItem as DataTableInfo;
}
[Visual Basic]
Private Sub textControl1_SubTextPartEntered(sender As Object, e As TXTextControl.SubTextPartEventArgs) Handles textControl1.SubTextPartEntered
	If DataSourceManager.IsMergeBlock(e.SubTextPart) Then
		If dsManager.DataTables.Contains(e.SubTextPart.Name.Remove(0, TXTextControl.DocumentServer.MailMerge.MergeBlockNamePrefix.Length)) Then
			dsManager.MasterDataTableInfo = dsManager.DataTables(e.SubTextPart.Name.Remove(0, TXTextControl.DocumentServer.MailMerge.MergeBlockNamePrefix.Length))
		End If
	End If
End Sub

Private Sub textControl1_SubTextPartLeft(sender As Object, e As TXTextControl.SubTextPartEventArgs) Handles textControl1.SubTextPartLeft
	dsManager.MasterDataTableInfo = TryCast(cbMasterTable.SelectedItem, DataTableInfo)
End Sub

When clicking the Preview button, the DocumentServer.DataSources.DataSourceManager.Merge method of the DataSourceManager is used to merge the data into the template:

[C#]
private void cbPreview_CheckedChanged(object sender, EventArgs e)
{
    if (cbPreview.Checked)
    {
        gbMergeElements.Enabled = false;
        textControl1.EditMode = TXTextControl.EditMode.ReadAndSelect;
        textControl1.Save(out previewTemplate, 
            TXTextControl.BinaryStreamType.InternalUnicodeFormat);

        IList<byte[]> documents = 
            dsManager.Merge(previewTemplate, textControl1);

        textControl1.Load(documents[0], 
            TXTextControl.BinaryStreamType.InternalUnicodeFormat);
    }
    else
    {
        gbMergeElements.Enabled = true;
        textControl1.EditMode = TXTextControl.EditMode.Edit;
        textControl1.Load(previewTemplate, 
            TXTextControl.BinaryStreamType.InternalUnicodeFormat);
    }
}
[Visual Basic]
Private Sub cbPreview_CheckedChanged(sender As Object, e As EventArgs) Handles cbPreview.Click
	If cbPreview.Checked Then
		gbMergeElements.Enabled = False
		textControl1.EditMode = TXTextControl.EditMode.ReadAndSelect
		textControl1.Save(previewTemplate, TXTextControl.BinaryStreamType.InternalUnicodeFormat)

		Dim documents As IList(Of Byte()) = dsManager.Merge(previewTemplate, textControl1)

		textControl1.Load(documents(0), TXTextControl.BinaryStreamType.InternalUnicodeFormat)
	Else
		gbMergeElements.Enabled = True
		textControl1.EditMode = TXTextControl.EditMode.Edit
		textControl1.Load(previewTemplate, TXTextControl.BinaryStreamType.InternalUnicodeFormat)
	End If
End Sub

Using the DataSourceManager, the complete task of designing mail merge templates can be realized. The class encapsulates the work-flow, logic and all required dialog boxes and preview functionality.