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

NullReferenceException when creating ReadOnlyRange

3 Answers 102 Views
RichTextBox
This is a migrated thread and some comments may be shown as answers.
Christoph
Top achievements
Rank 1
Christoph asked on 17 Jan 2012, 07:10 PM
Hi

i am creating readonly ranges using the InsertReadOnlyRange method.
This works well most of the times.
However I get a NullReferenceException deeply from the tk-lib code
with the following stacktrace:

    
Telerik.Windows.Documents.dll!Telerik.Windows.Documents.Model.RadDocument.GetCaretInline() Line 1319    C#
     Telerik.Windows.Documents.dll!Telerik.Windows.Documents.Model.RadDocument.GetCurrentSpanStyle() Line 1336 + 0xc bytes    C#
     Telerik.Windows.Documents.dll!Telerik.Windows.Controls.RadRichTextBox.UpdateCurrentStyles() Line 2974 + 0x20 bytes    C#
     Telerik.Windows.Documents.dll!Telerik.Windows.Documents.UI.DocumentWebLayoutPresenter.DoOnCaretLocationChanged() Line 441    C#
    Telerik.Windows.Documents.dll!Telerik.Windows.Documents.UI.DocumentWebLayoutPresenter.DoOnDocumentChanged.AnonymousMethod__6() Line 409 + 0xa bytes    C#

the line raising the exception goes like:

//Line 1319 in RadDocument.cs
    SpanLayoutBox previousSpanBox = DocumentStructureCollection.GetPreviousSiblingForDocumentElement(currentSpanBox,
                    currentSpanBox.Parent.AssociatedDocumentElement) as SpanLayoutBox;
                              //  ^^^^^NullReferenceException: Parent is null sometimes

"Parent" is null here.
I noticed that the "null-ness" and the exception only occur if the span is inserted using InsertInline:

RadDocument doc = editor.Document;
 var span1 = new Span("This text is protected");
// doc.InsertInline(span1); //this span's spanbox will have no Parent, causing a Null ref
 (doc.Sections.Last.Blocks.Last as Paragraph).Inlines.Add(span1); //this span's spanbox will have a Parent, not causing a Null ref
 DocumentPosition pos3 = new DocumentPosition(doc.DocumentLayoutBox, true);
 var spb1 = span1.FirstLayoutBox as SpanLayoutBox;
 pos3.MoveToInline(spb1, 0);
 
 DocumentPosition pos4 = new DocumentPosition(doc.DocumentLayoutBox, true);
 pos4.MoveToInline(spb1, spb1.PositionsCountInBox - 1);
 
 doc.InsertReadOnlyRange(pos3, pos4); // raises Null ref in RadDocument.GetCaretInline if using "doc.InsertInline"


so my wish to the telerik developpers is to fix this line of code.
There are circumstances where a spanbox has no Parent layoutbox.
(E.g. when appending it with InsertInline). So you can't use it to get its previous sibling.
If you anaylze the stack trace and the surrounding code of "GetCaretInline"
it's fully OK to null check the Parent property and in this case simply return
the span associated to the layoutbox "currentSpanBox".

Chris

3 Answers, 1 is accepted

Sort by
0
Iva Toteva
Telerik team
answered on 23 Jan 2012, 03:05 PM
Hi Chris,

Actually the correct way to insert a Span in the document if the document has already been measured and arranged is through the InsertInline method of RadRichTextBox or RadDocument. (The document is automatically measured and arranged when shown in an editor in the visual tree.) The difference between the analogical methods of RadDocument and RadRichTextBox is that the history stack will be cleared if you use the method of the document - the same goes for the InsertReadOnlyRange method.

On the other hand, if you add the span directly to the Inlines of a Paragraph, the document structure will become invalid, because the last Inline of a Paragraph must contain the paragraph end symbol which is created automatically on measure.

To cut the long story short, you can insert read-only text in the document like this:

string text = "This text is protected";
 
DocumentPosition start = new DocumentPosition(this.editor.Document.CaretPosition);
 
start.AnchorToCurrentBoxIndex();
this.editor.Insert(text);
start.RestorePositionFromBoxIndex();
 
this.editor.Document.Selection.SetSelectionStart(start);
this.editor.Document.Selection.AddSelectionEnd(this.editor.Document.CaretPosition);
 
this.editor.InsertReadOnlyRange();

I have used the methods of the editor, in order to preserve the undo/redo capability.

In case you want to set some font properties on the text you are inserting, you can also use the InsertInline method passing a Span as a parameter:
string text = "This text is protected";
 
DocumentPosition start = new DocumentPosition(this.editor.Document.CaretPosition);
 
start.AnchorToCurrentBoxIndex();
this.editor.InsertInline(new Span(text) { FontWeight = FontWeights.Bold, ForeColor = Colors.Blue });
start.RestorePositionFromBoxIndex();
 
this.editor.Document.Selection.SetSelectionStart(start);
this.editor.Document.Selection.AddSelectionEnd(this.editor.Document.CaretPosition);
 
this.editor.InsertReadOnlyRange();


Kind regards,
Iva Toteva
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Cameron Molyneux
Top achievements
Rank 1
answered on 29 Feb 2012, 05:29 PM
Hi,

I am trying to do this with MergeFields, however I am not inserting the MergeFields when trying to make them readonly.

I need to get the end position of the MergeField so I can say where the "AddSelectionEnd" is, rather than the caret position which is at the beginning, and since I am not inserting them, the caret isn't moving to the end. Is there a way to achieve this?

Thanks.
0
Iva Toteva
Telerik team
answered on 06 Mar 2012, 09:28 AM
Hello Cameron,

If rangeStart and rangeEnd are the FieldRangeStart and FieldRangeEnd pair, you can navigate positions to them and insert a read-only range in the following way:

DocumentPosition start = new DocumentPosition(this.editor.Document);
DocumentPosition end = new DocumentPosition(this.editor.Document);
 
InlineLayoutBox inlineLayoutBox = rangeEnd.FirstLayoutBox as InlineLayoutBox;
InlineLayoutBox nextLayoutBox = inlineLayoutBox.AssociatedInline.NextSibling.FirstLayoutBox as InlineLayoutBox;
 
start.MoveToInline(rangeStart.FirstLayoutBox as InlineLayoutBox, 0);
end.MoveToInline(nextLayoutBox, 0);
 
this.editor.Document.InsertReadOnlyRange(start, end);

I hope this helps.

Greetings,
Iva Toteva
the Telerik team
Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
Tags
RichTextBox
Asked by
Christoph
Top achievements
Rank 1
Answers by
Iva Toteva
Telerik team
Cameron Molyneux
Top achievements
Rank 1
Share this question
or