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

CreateShallowCopy ignoring IsInList

8 Answers 103 Views
RichTextBox
This is a migrated thread and some comments may be shown as answers.
Richard Ellis
Top achievements
Rank 1
Richard Ellis asked on 10 May 2013, 02:30 PM
We are using a DocXFormatProvider to load a Word document and then separating this out into separate RadDocuments based on Page Breaks.  Part of our code copies Paragraphs into new Documents and Sections as below:

paragraph.CreateShallowCopy() as Paragraph

This does not include copying of the IsInList boolean.

- Is this by design?
- Are there other properties which are not copied?
- Is there an alternate to CreateShallowCopy() which includes what we need?

Version: 2012.2.724.1040 for Silverlight 4.

Thanks

8 Answers, 1 is accepted

Sort by
0
Richard Ellis
Top achievements
Rank 1
answered on 13 May 2013, 06:48 AM
I tried copying the LIstStyles from one RadDocument to the other - but this had cleared once all sections and paragraphs had been copied over to the new RadDocument.

// Seperate into seperate Docs based on Page breaks.
RadDocument newDocument = originalDoc.CreateShallowCopy() as RadDocument;
foreach (var listStyle in originalDoc.ListManager.GetAllListStyles())
{
    newDocument.ListManager.RegisterListStyleIfNecessary(listStyle);
}

Is there anything else I can/need to do to get lists to be copied successfully?

Thanks.
Richard Ellis
0
Richard Ellis
Top achievements
Rank 1
answered on 13 May 2013, 12:38 PM
Looks like I've gotten to the bottom of this now.  The trick seems to be in creating new DocumentList objects using the new RadDocument and original ListStyle objects.  I am now using the following code when adding paragraphs in order to use only those List Styles that are required for each seperated out RadDocument.

/// <summary>
/// Adds Paragraph to a new section and copies any list styles required to the New Document
/// </summary>
/// <param name="newSection">New Section to add paragraph to.</param>
/// <param name="originalParagraph">Original Paragraph being copied.</param>
/// <param name="originalDocument"> Original Document from which to copy the List Styles.</param>
/// <returns></returns>
public static Paragraph AddParagraph(this Section newSection, Paragraph originalParagraph, RadDocument originalDocument)
{
    Paragraph newParagraph = originalParagraph.CreateShallowCopy() as Paragraph;
    if (originalParagraph.IsInList)
    {
        var newDocument = newSection.GetRootDocument();
        if (newDocument.ListManager.GetDocumentListById(originalParagraph.ListId) == null)
        {
            var docList = originalDocument.ListManager.GetDocumentListById(originalParagraph.ListId);
            if (docList != null)
            {
                var listStyle = docList.Style;
 
                // Add Style
                if (string.IsNullOrEmpty(listStyle.StyleLink)) listStyle.StyleLink = string.Concat("ListStyle", docList.ID);
                var doclist = new DocumentList(listStyle, newDocument, docList.ID);
            }
        }
    }
 
    newSection.Children.Add(newParagraph);
    return newParagraph;
}


This seems to be doing the job nicely - but is this the best way to go about it?
0
Petya
Telerik team
answered on 14 May 2013, 03:33 PM
Hello Richard,

To your question - yes, creating a shallow/deep copy of a paragraph is supposed to not copy the IsInList property. Actually, the CreateDeepCopy() and CreateShallowCopy() methods of document elements are usually not recommended for use and we advise you to use the API of RadRichTextBox instead.

What I believe will be the best solution in your case is to use the approach my colleague Boby explained here. I am also attaching a sample solution that demonstrates how this can be done for the whole document and not only the first "part", along with a sample document. You can verify that the SplitDocument() method generates exactly 5 smaller parts.

If this does not fit your needs, I'd like to point out that your current approach for copying document elements is not the best one. Alternatively, you can try selecting each of your paragraphs (originalParagraph in the code below) and inserting a DocumentFragment generated from that selection in the newly created document.

Let us know if you any further questions or concerns.

Regards,
Petya
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Richard Ellis
Top achievements
Rank 1
answered on 20 May 2013, 07:49 AM
At the moment the Split Document process is performed async without access to the UI.  Is this an issue?  Does your original code need the RichTextBox used need to be visible in the UI for the code to work.  Can it run on a non-UI thread?

Thanks.

UPDATE: This definately can not be done from a Non-UI thread (as expected to be honest) - it results in 'Invalid cross-thread access.'  Any chance there's a similar method which isn't restricted to the UI?  Otherwise I'll need to redesign our application a little.
0
Richard Ellis
Top achievements
Rank 1
answered on 21 May 2013, 09:49 AM
I'm now getting the following error on the final Page Break seperation.  When performing the final             
editor.Document.Selection.AddSelectionEnd(position);
I get the following error:
{System.NullReferenceException: Object reference not set to an instance of an object.
   at Telerik.Windows.Documents.UI.Extensibility.MiniToolBarManager.ShowImageMiniToolBar(Inline inline)
   at Telerik.Windows.Documents.UI.Extensibility.MiniToolBarManager.RegisterSelectionChanged()
   at Telerik.Windows.Documents.RichTextBoxCommands.ContextListeners.DocumentContextListener.ContextChangedEventHandler(Object sender, EventArgs e)
   at System.EventHandler.Invoke(Object sender, EventArgs e)
   at Telerik.Windows.Documents.Selection.DocumentSelection.OnSelectionChanged()
   at Telerik.Windows.Documents.Selection.DocumentSelection.AddSelectionEnd(DocumentPosition position, Boolean shouldExpandRanges)
   at Telerik.Windows.Documents.Selection.DocumentSelection.AddSelectionEnd(DocumentPosition position)
   at Cubiks.Etray3.ContentManagement.Tools.WordDocument.ReadWordDocument(Byte[] content, ContentLayoutDictionary layout, ValidationResults validationResults, DocumentLayoutMode layoutMode)
   at Cubiks.Etray3.ContentManagement.Services.ExerciseService.LoadRichTextDocument(Byte[] content, ContentLayoutDictionary layout)}

This system of using the Telerik RadRichTextBox to break up documents is turning out to be somewhat flaky.  Any help would be appreciated.

Thanks.

I should say that we've needed to pull out the first row as a reference resultign in the following code:
public static RichTextDictionary ReadWordDocument(byte[] content, ContentLayoutDictionary layout, ValidationResults validationResults, DocumentLayoutMode layoutMode = DocumentLayoutMode.Flow)
{
    if (content == null || content.Length == 0)
        throw new ArgumentNullException("content");
 
    RichTextDictionary seperatedDocs = new RichTextDictionary();
    StringBuilder refBuilder = new StringBuilder();
    bool firstline = true;
 
    // Load original Word Document into RichTextBox UI.
    DocxFormatProvider formatProvider = new DocxFormatProvider();
    RadDocument originalDoc = formatProvider.Import(content);
    originalDoc.LayoutMode = layoutMode;        /* Force to Default Layout Mode */
 
    RadRichTextBox editor = new RadRichTextBox();
    editor.Document = originalDoc;
 
    // Use UI to make selection in Documents base on Section and Page breaks - and break up into new Documents
    DocumentPosition position = new DocumentPosition(editor.Document);
    while (position.MoveToNextInline())
    {
        InlineLayoutBox inlineBox = position.GetCurrentInlineBox();
 
        if (firstline && !inlineBox.IsLastChild)  // Assumes last on line is formatting (line-break) etc
        {
            // Not formatting but is firstline - build-up reference
            refBuilder.Append(inlineBox.Text);
        }
 
        if (inlineBox.IsFormattingSymbol)
        {
            // Check formatting to determine if end of reference or end of Sub Document (via Page Break)
            FormattingSymbolLayoutBox formattingSymbolBox = (FormattingSymbolLayoutBox)inlineBox;
            if (firstline)
            {
                // Build up reference if first line of page/sub document
                if (formattingSymbolBox.FormattingSymbol == FormattingSymbols.LineBreak || formattingSymbolBox.IsLastOnLine)
                {
                    firstline = false;
 
                    position.MoveToNext();
                    editor.Document.Selection.SetSelectionStart(position);
                }
            }
            else if (formattingSymbolBox.FormattingSymbol == FormattingSymbols.PageBreak || formattingSymbolBox.IsSectionBreak)
            {
                // Deal with Reference
                string reference = refBuilder.ToString();
                refBuilder.Clear();
                firstline = true;
 
                // Build RadDocument from Selection - AddToDocumentsCollection method Sets layout of document and performs validation.
                editor.Document.Selection.AddSelectionEnd(position);
                AddToDocumentsCollection(seperatedDocs, reference, GetLayout(reference, layout), editor.Document.Selection.CreateDocumentFromSelection(), validationResults);
 
                position.MoveToNext();
            }
        }
    }
 
    string lastRef = refBuilder.ToString();
    position.MoveToLastPositionInDocument();
    editor.Document.Selection.AddSelectionEnd(position);
    AddToDocumentsCollection(seperatedDocs, lastRef, GetLayout(lastRef, layout), editor.Document.Selection.CreateDocumentFromSelection(), validationResults);
 
    return seperatedDocs;
}

We've also had some issues with the very first reference being incorrect (repetition of text or, occasionally, being set to an empty reference) and all thats on the 'page' which causes the error is a single large image.
0
Petya
Telerik team
answered on 21 May 2013, 03:49 PM
Hi Richard,

Actually, all methods used in the project I sent you are methods of DocumentSelection, which is a property of RadDocument. That said, it is possible to use the same code over a RadDocument instance that is not shown in RadRichTextBox. (Please note that the same does not apply to all methods of RadRichTextBox and that in Q1 2013 we introduced a safe way to modify a measured document without showing it RadRichTextBox - RadDocumentEditor.)

However, it is not possible to execute the wanted logic from a non-UI thread as some of the document elements cannot be properly created on a non-UI thread (for example images).

Regarding the exception you are observing - I am unfortunately unable to replicate that. Can you please list some steps that I can execute to create a document that will cause such issues in the sample I sent you. Also, it will be best if you open a support ticket and attach a sample solution and document which we can use to troubleshoot on our end.

I'm awaiting your reply.

Kind regards,
Petya
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Richard Ellis
Top achievements
Rank 1
answered on 03 Sep 2013, 08:11 AM
Thanks,

I'm now ignoring my previous changes and working off of your SplitDocument demo.  However I seem to have found another problem.  In order to quickly check the validity of the Split Documents I added the following line:
this.editor.Document = splittedDocument.First();

However it seems that the split has lost the word-wrapping of the text.  Using a longer example document each paragraph expands beyond the page (see before and after screenshots).

It's my hope that we can eventually use this method to split the document and keep as much of the original Word/RichTextBox formatting as possible.  However, we're some way from that as yet.

Thanks.
Richard
0
Petya
Telerik team
answered on 03 Sep 2013, 02:56 PM
Hello Richard,

Thank you for the follow-up!

If it is possible for you to upgrade to a more recent release of RadControls for Silverlight you can modify the code in the project I previously attached in order to use RadDocumentEditor like this:
if (formattingSymbolBox.FormattingSymbol == FormattingSymbols.PageBreak || formattingSymbolBox.IsSectionBreak)
{
    this.editor.Document.Selection.AddSelectionEnd(position);
  
    newDocument = new RadDocument() { LayoutMode = DocumentLayoutMode.Paged };
    RadDocumentEditor documentEditor = new RadDocumentEditor(newDocument);
    DocumentFragment fragment = new DocumentFragment(this.editor.Document.Selection);
    documentEditor.InsertFragment(fragment);
 
    splittedDocument.Add(documentEditor.Document);
 
    position.MoveToNext();
    this.editor.Document.Selection.SetSelectionStart(position);
}

In case this is not an option in your case, you can work around the issue by invalidating the newly created document so that it can be measured properly like this:
if (formattingSymbolBox.FormattingSymbol == FormattingSymbols.PageBreak || formattingSymbolBox.IsSectionBreak)
{
    this.editor.Document.Selection.AddSelectionEnd(position);
    newDocument = this.editor.Document.Selection.CreateDocumentFromSelection();
 
    newDocument.EnumerateChildrenOfType<Telerik.Windows.Documents.Model.Paragraph>().First().InvalidateAssociatedBoxesLayout();
    splittedDocument.Add(newDocument);
 
    position.MoveToNext();
    this.editor.Document.Selection.SetSelectionStart(position);
}


I hope this helps! Let us know if you have further questions or comments.

Regards,
Petya
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for SILVERLIGHT.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
Tags
RichTextBox
Asked by
Richard Ellis
Top achievements
Rank 1
Answers by
Richard Ellis
Top achievements
Rank 1
Petya
Telerik team
Share this question
or