Hi,
I am using the merge feature of the RichTextBox control for template documents. What I am trying to do is applying values provided by the system (my developed application) and let the end user fill other content within this document.
If Merge Fields are used in the document, and when the values are applied, the result shows the values both in the header/footer and the body. When the Save as functionality of the richtextbox control is used and the exported document is opened in Microsoft Word, the values of header/footer are gone only values of merge fields in the body is stable.
I am attaching the sample code, template document and exported document to showcase the problem. Is it an expected behavior or is there an alternative solution?
Main.cs
using
System;
using
System.Collections.Generic;
using
System.Data;
using
System.IO;
using
System.Linq;
using
System.Windows;
using
System.Windows.Controls;
using
Telerik.Windows.Controls;
using
Telerik.Windows.Controls.RibbonView;
using
Telerik.Windows.Documents;
using
Telerik.Windows.Documents.FormatProviders.OpenXml.Docx;
using
Telerik.Windows.Documents.Layout;
using
Telerik.Windows.Documents.Model;
namespace
DynamicMailMerge
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public
partial
class
MainWindow : Window
{
public
MainWindow()
{
InitializeComponent();
this
.insertMergeFieldButton.DropDownOpening += InsertMergeFieldButton_DropDownOpening;
}
private
void
InsertMergeFieldButton_DropDownOpening(
object
sender, RoutedEventArgs e)
{
if
(
this
.radRichTextBox.Document.MailMergeDataSource.ItemsSource ==
null
)
{
this
.InitializeMailMergeDynamicSource();
}
CreateMergeFieldNames();
}
private
void
CreateMergeFieldNames()
{
if
(
this
.radRichTextBox.Document.MailMergeDataSource.ItemsSource !=
null
)
{
StackPanel stackPanel =
new
StackPanel();
var enumerator =
this
.radRichTextBox.Document.MailMergeDataSource.ItemsSource.GetEnumerator();
enumerator.MoveNext();
MyDynamicObject myDynamicObject = enumerator.Current
as
MyDynamicObject;
if
(myDynamicObject !=
null
)
{
foreach
(
string
fieldName
in
myDynamicObject.GetColumnNames())
{
RadRibbonButton fieldButton =
new
RadRibbonButton()
{
Text = fieldName,
Size = ButtonSize.Medium,
HorizontalAlignment = HorizontalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Left
};
fieldButton.Command =
this
.radRichTextBox.Commands.InsertFieldCommand;
fieldButton.CommandParameter =
new
MergeField() { PropertyPath = fieldName };
stackPanel.Children.Add(fieldButton);
}
}
enumerator.Reset();
stackPanel.Width = 140;
this
.insertMergeFieldButton.DropDownContent = stackPanel;
}
}
private
void
InitializeMailMergeDynamicSource()
{
List<MyDynamicObject> mailMergeSource =
this
.GetMailMergeSource(
this
.radRichTextBox.Document);
this
.radRichTextBox.Document.MailMergeDataSource.ItemsSource = mailMergeSource;
this
.radRichTextBox.Document.MailMergeDataSource.MoveToFirst();
this
.radRichTextBox.ChangeAllFieldsDisplayMode(FieldDisplayMode.Result);
}
private
List<MyDynamicObject> GetMailMergeSource(RadDocument rad)
{
List<MyDynamicObject> mailMergeSource =
new
List<MyDynamicObject>();
MyDynamicObject myDynamicObject =
new
MyDynamicObject();
myDynamicObject.Set(
"HeaderMergeField"
,
"Header Merged Data"
);
myDynamicObject.Set(
"BodyMergeField"
,
"Body Merged Data"
);
mailMergeSource.Add(myDynamicObject);
return
mailMergeSource;
}
private
void
Button_Click(
object
sender, RoutedEventArgs e)
{
using
(var outStream =
new
FileStream(@
"c:\temp\sampleoutcode.docx"
, FileMode.Create))
{
var provider =
new
DocxFormatProvider();
provider.Export(
this
.radRichTextBox.Document, outStream);
}
}
}
}
MyDynamicObject.cs
using
System;
using
System.Collections.Generic;
using
System.Dynamic;
using
System.Linq;
namespace
DynamicMailMerge
{
public
class
MyDynamicObject : DynamicObject
{
private
readonly
Dictionary<
string
,
object
> dictionary =
new
Dictionary<
string
,
object
>();
public
int
Count
{
get
{
return
this
.dictionary.Count;
}
}
public
IEnumerable<String> GetColumnNames()
{
return
this
.dictionary.Keys;
}
public
void
Set(
string
propertyName,
object
value)
{
this
.TrySetMember(
new
MySetMemberBinder(propertyName,
false
), value);
}
public
object
Get(
string
propertyName)
{
object
result;
this
.TryGetMember(
new
MyGetMemberBinder(propertyName,
false
),
out
result);
return
result;
}
public
override
bool
TryGetMember(GetMemberBinder binder,
out
object
result)
{
string
propertyName = binder.Name;
return
this
.dictionary.TryGetValue(propertyName,
out
result);
}
public
override
bool
TrySetMember(SetMemberBinder binder,
object
value)
{
string
propertyName = binder.Name;
this
.dictionary[propertyName] = value;
return
true
;
}
}
}
MyGetMemberBinder.cs
using
System;
using
System.Dynamic;
using
System.Linq;
namespace
DynamicMailMerge
{
public
class
MyGetMemberBinder : GetMemberBinder
{
public
MyGetMemberBinder(
string
name,
bool
ignoreCase)
:
base
(name, ignoreCase)
{
}
public
override
DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
{
return
target;
}
}
}
MySetMemberBinder.cs
using
System;
using
System.Dynamic;
using
System.Linq;
namespace
DynamicMailMerge
{
public
class
MySetMemberBinder : SetMemberBinder
{
public
MySetMemberBinder(
string
name,
bool
ignoreCase)
:
base
(name, ignoreCase)
{
}
public
override
DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
{
return
target;
}
}
}
Thanks in advance,