I am working on something akin to a mail merge for users to send to clients. I need to be able to print many documents at once or append them to one RadDocument to ensure that they print at once.
For example:
Obviously, the tags would be replaced with something more useful than "Foo" (like an aggregate field).
I would use reporting but the end-users for this system want to be able to create their own templates (in a word-like setup) and have the system fill in the data as needed at report-time.
Anyway, thank you in advance!
For example:
this
.editor.Document.Selection.Clear();
var original = (RadDocument)
this
.editor.Document.CreateDeepCopy();
DocumentTextSearch search =
new
DocumentTextSearch(
this
.editor.Document);
foreach
(var textRange
in
search.FindAll(Regex.Escape(
"<test>"
)))
{
this
.editor.Document.Selection.AddSelectionStart(textRange.StartPosition);
this
.editor.Document.Selection.AddSelectionEnd(textRange.EndPosition);
this
.editor.Insert(
"Foo"
);
}
//Append or build print queue for this.editor.Document
this
.editor.Document = original;
I would use reporting but the end-users for this system want to be able to create their own templates (in a word-like setup) and have the system fill in the data as needed at report-time.
Anyway, thank you in advance!
6 Answers, 1 is accepted
0

Matthew
Top achievements
Rank 1
answered on 17 May 2011, 11:12 PM
Well, after playing around for a few arduous hours I got something that does what it needs to without hacky tricks.
private
void
ReplaceTestWithFoo(RadRichTextBox box,
int
copies)
{
var document = box.Document;
document.Selection.SelectAll();
DocumentFragment fragment = document.Selection.CopySelectedDocumentElements();
for
(
int
i = 0; i < copies; i++)
{
DocumentTextSearch search =
new
DocumentTextSearch(document);
var textRanges = search.FindAll(Regex.Escape(
"<test>"
));
foreach
(var textRange
in
textRanges)
{
document.Selection.AddSelectionStart(textRange.StartPosition);
document.Selection.AddSelectionEnd(textRange.EndPosition);
box.Insert(
"Foo"
);
}
if
(i + 1 < copies)
{
AppendOnPageBreak(document, fragment);
}
}
}
void AppendOnPageBreak(RadDocument document, DocumentFragment fragment)
{
DocumentPosition position = new DocumentPosition(document);
document.CaretPosition.MoveToLastPositionInDocument();
document.InsertInline(new Span(FormattingSymbolLayoutBox.PAGE_BREAK));
position.MoveToLastPositionInDocument();
document.InsertFragment(fragment, position);
}
0
Hello Matthew,
The reason is that copying document elements may not work correctly for lists (the numbers of numbered lists in particular. They have been fixed in the development version, which is to be released in the Q2 Beta in mid-June).
At the same time, exporting and importing the document should work in all cases:
Other than that, the code from the snipper in your post looks right from RadRichTextBox's point of view. The second
in the AppendOnPageBreak method is not needed, as the position will be moved there anyway.
On a side note, perhaps you should check if you have reached the last document only with regard to inserting the page break? The way it is, a page break will be inserted after the last but one copy and the last copy will not be inserted at all. Just my five cents.
If you have any questions, do not hesitate to get back to us.
Regards,
Iva
the Telerik team
We have mail merge on the agenda and it should be ready for the official release in July.
As for your code-snippet, it is quite close to what can be done with the current version of the controls. You can also check the Bookmarks API (BookmarkRangeStart, BookmarkRangeEnd and the methods for Selecting, and deleting Bookmarks).
If you decide to continue with the approach you have adopted, I can recomment the following modification:
private
RadDocument ReplaceTestWithFoo(RadDocument document)
{
XamlFormatProvider provider =
new
XamlFormatProvider();
RadRichTextBox box =
new
RadRichTextBox();
//if document is not measured and arranged (it has not been shown in a RadRichTextBox), uncomment the following line
// MeasureAndArrangeInDefaultSize(document);
box.Document = provider.Import(provider.Export(document));
MeasureAndArrangeInDefaultSize(box.Document);
//after import, the document is not measured
box.Document.Selection.Clear();
DocumentTextSearch search =
new
DocumentTextSearch(box.Document);
var textRanges = search.FindAll(Regex.Escape(
"<test>"
));
foreach
(var textRange intextRanges)
{
box.Document.Selection.AddSelectionStart(textRange.StartPosition);
box.Document.Selection.AddSelectionEnd(textRange.EndPosition);
box.Insert(
"Foo"
);
}
return
box.Document;
}
private
void
MeasureAndArrangeInDefaultSize(RadDocument document)
{
document.Measure(RadDocument.MAX_DOCUMENT_SIZE);
document.Arrange(newRectangleF(PointF.Empty, document.DesiredSize));
}
At the same time, exporting and importing the document should work in all cases:
Other than that, the code from the snipper in your post looks right from RadRichTextBox's point of view. The second
position.MoveToLastPositionInDocument();
in the AppendOnPageBreak method is not needed, as the position will be moved there anyway.
On a side note, perhaps you should check if you have reached the last document only with regard to inserting the page break? The way it is, a page break will be inserted after the last but one copy and the last copy will not be inserted at all. Just my five cents.
If you have any questions, do not hesitate to get back to us.
Regards,
Iva
the Telerik team
Do you want to have your say when we set our development plans?
Do you want to know when a feature you care about is added or when a bug fixed?
Explore the
Telerik Public Issue Tracking
system and vote to affect the priority of the items
0

Matthew
Top achievements
Rank 1
answered on 23 May 2011, 10:24 PM
While I would like to use the more "robust" method of printing, I can neither find a way of printing many, imported, documents nor figure out how to append entire documents.
EDIT:
I also saw the numbering problem you mentioned using the DocumentFragment.
EDIT:
I also saw the numbering problem you mentioned using the DocumentFragment.
0
Hi Matthew,
Iva
the Telerik team
There is a sample code snippet in this forum thread illustrating how inserting whole documents into another can be done (Mike's post from March 11).
If that does not help, we would appreciate it if you could provide a sample application, so that we can see what goes wrong and suggest alternatives.
Iva
the Telerik team
Do you want to have your say when we set our development plans?
Do you want to know when a feature you care about is added or when a bug fixed?
Explore the
Telerik Public Issue Tracking
system and vote to affect the priority of the items
0

Matthew
Top achievements
Rank 1
answered on 27 May 2011, 04:46 PM
The method Mike posted uses the same method, CopySelectedDocumentElements/InsertFragment, as I had posted before and thus still suffers from the ordered lists problem. The ordered lists are not of huge concern currently, but if there is a way that does not use the InsertFragment method (or a "stable" dev build where it is working fully) then I'd like to know.
On the bright side, everything else is working wonderfully now and I have a pretty extensible "mail-merge" method that should work in almost any situation:
In this case the user has to insert some tags (like bb code, defined in converter) into the document and this will replace them with information based in the blob.
Thanks,
Matt
On the bright side, everything else is working wonderfully now and I have a pretty extensible "mail-merge" method that should work in almost any situation:
private
Dictionary<
string
, Action<RadRichTextBox, dynamic>> Converter;
private
RadDocument currentDocument;
private
void
InitilizeConverter()
{
Converter =
new
Dictionary<
string
, Action<RadRichTextBox, dynamic>>();
// Example usage:
Converter[
"<FooAddress>"
] = (textbox, o) => InsertString(textbox, o.Foo.Address);
}
private
void
CreateLetters(
string
letter, List<Foo> Foos)
{
orginalLetter = letter;
currentDocument =
null
;
XamlFormatProvider provider =
new
XamlFormatProvider();
foreach
(var foo
in
Foos)
{
dynamic blob =
new
{ Foo = foo };
CreateLetter(currentDocument, orginalLetter, foo);
}
CurrentDocumentXAML = provider.Export(currentDocument);
EndBusyEvent();
}
private
void
CreateLetter(RadDocument oldDocument,
string
letter, dynamic blob)
{
XamlFormatProvider provider =
new
XamlFormatProvider();
var newDocument = provider.Import(letter);
MeasureAndArrangeInDefaultSize(newDocument);
ReplaceItems(newDocument, blob);
AppendOnPageBreak(oldDocument, newDocument);
}
private
void
ReplaceItems(RadDocument newDocument, dynamic blob)
{
RadRichTextBox box =
new
RadRichTextBox();
box.Document = newDocument;
foreach
(var key
in
Converter.Keys)
{
box.Document.Selection.Clear();
DocumentTextSearch search =
new
DocumentTextSearch(box.Document);
var textRanges = search.FindAll(Regex.Escape(key));
foreach
(var textRange
in
textRanges)
{
box.Document.Selection.AddSelectionStart(textRange.StartPosition);
box.Document.Selection.AddSelectionEnd(textRange.EndPosition);
Converter[key].Invoke(box, blob);
}
}
}
void
AppendOnPageBreak(RadDocument oldDocument, RadDocument newDocument)
{
newDocument.Selection.SelectAll();
DocumentFragment fragment = newDocument.Selection.CopySelectedDocumentElements();
if
(oldDocument !=
null
)
{
DocumentPosition position =
new
DocumentPosition(oldDocument);
oldDocument.CaretPosition.MoveToLastPositionInDocument();
oldDocument.InsertInline(
new
Span(FormattingSymbolLayoutBox.PAGE_BREAK));
position.MoveToLastPositionInDocument();
oldDocument.InsertFragment(fragment, position);
}
else
{
currentDocument = newDocument;
}
}
private
void
MeasureAndArrangeInDefaultSize(RadDocument document)
{
document.Measure(RadDocument.MAX_DOCUMENT_SIZE);
document.Arrange(
new
RectangleF(PointF.Empty, document.DesiredSize));
}
private
static
void
InsertString(RadRichTextBox textbox,
string
item)
{
if
(item !=
null
)
{
textbox.Insert(item);
}
else
{
textbox.Insert(
" "
);
}
}
In this case the user has to insert some tags (like bb code, defined in converter) into the document and this will replace them with information based in the blob.
Thanks,
Matt
0
Hi Matthew,
There is no internal build that resolves the issue, but if we decide that the development version is stable enough to prepare one, we will drop you a note.
In any case, the Q2 Beta which is due in 2 weeks' time will include the fix.
Greetings,
Iva
the Telerik team
There is no internal build that resolves the issue, but if we decide that the development version is stable enough to prepare one, we will drop you a note.
In any case, the Q2 Beta which is due in 2 weeks' time will include the fix.
Greetings,
Iva
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items