This is a migrated thread and some comments may be shown as answers.

Printing many documents/Appending many documents

6 Answers 144 Views
RichTextBox
This is a migrated thread and some comments may be shown as answers.
Matthew
Top achievements
Rank 1
Matthew asked on 17 May 2011, 04:30 PM
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:
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;
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!

6 Answers, 1 is accepted

Sort by
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
Iva Toteva
Telerik team
answered on 19 May 2011, 06:09 PM
Hello Matthew,

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));
}
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 
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.
0
Iva Toteva
Telerik team
answered on 27 May 2011, 01:17 PM
Hi Matthew,

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.

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 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:
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
Iva Toteva
Telerik team
answered on 02 Jun 2011, 12:10 PM
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
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
Tags
RichTextBox
Asked by
Matthew
Top achievements
Rank 1
Answers by
Matthew
Top achievements
Rank 1
Iva Toteva
Telerik team
Share this question
or