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

How to make document Table cell ReadOnly

10 Answers 275 Views
RichTextBox
This is a migrated thread and some comments may be shown as answers.
Alexander
Top achievements
Rank 1
Alexander asked on 25 Dec 2012, 10:37 AM
Hi everyone,

I use a RadRichText box and I need to insert a Telerik.Windows.Documents.Model.Table object(It is generated in Runtime)
into a Document, and in each cell I add a placeholder using InlineUIContainer,
so the question is how can I disable editing of my cell that contains a placeholder,
because currently all my functionality works perfect but cells are editable.

Method below initializes a TableCell instance where a placeholder is injected.
private double InitDataCell(TableCell dataCell, DynamicColumnViewModel columnVm, bool isWidth100, double percent)
{
            double cellHeight = 0;
 
            dataCell.Tag = columnVm.DynamicCellData.TableID.ToString();
 
            if (isWidth100)
            {
                dataCell.PreferredWidth = new TableWidthUnit(TableWidthUnitType.Percent, percent);
            }
            else
            {               
                dataCell.PreferredWidth = new TableWidthUnit(TableWidthUnitType.Fixed, columnVm.Width);
            }           
 
            dataCell.TextAlignment = columnVm.Alignment;
            dataCell.VerticalAlignment = RadVerticalAlignment.Center;
            var paragraph = new Paragraph();
            paragraph.TextAlignment = columnVm.Alignment;
            dataCell.Blocks.Add(paragraph);
 
            dataCell.Background = columnVm.DynamicCellData.Background;         
 
            var tb = new TextBlock
            {
                Text = columnVm.Expression,
                Tag = string.Format("{0}{1}", DynamicTableCommon.DynamicTable.TABLE_TAG_ID_PREFIX, columnVm.DynamicCellData.TableID.ToString()),
                FontSize = columnVm.DynamicCellData.FontSize,
                Background = new SolidColorBrush(columnVm.DynamicCellData.Background),
                Foreground = new SolidColorBrush(columnVm.DynamicCellData.Foreground),
                FontFamily = columnVm.DynamicCellData.FontFamily,
                FontWeight = columnVm.DynamicCellData.FontWeight,
                FontStyle = columnVm.DynamicCellData.FontStyle,
                TextDecorations = columnVm.DynamicCellData.TextDecoration
            };
 
            tb.VerticalAlignment = VerticalAlignment.Bottom;
 
            tb.HorizontalAlignment = PlaceHolderReplaceManager.ConvertRadTextAlignmentToHorAlignment(columnVm.Alignment);
 
            System.Windows.Controls.Border border = new System.Windows.Controls.Border();
            border.BorderThickness = new Thickness(0);
            border.BorderBrush = Brushes.Transparent;
            border.Background = new SolidColorBrush(columnVm.DynamicCellData.Background);           
            border.VerticalAlignment = VerticalAlignment.Center;
            border.HorizontalAlignment = HorizontalAlignment.Center;
            border.Child = tb;
 
            border.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));        
 
            Size s = new Size(border.DesiredSize.Width + 1, tb.DesiredSize.Height - 1);
            var uic = new DynamicCellInlineUIContainer(border, s);                         
 
            paragraph.Tag = columnVm.DynamicCellData.TableID.ToString();
            paragraph.Inlines.Add(uic);
 
            cellHeight = uic.Height + 10;
 
            return cellHeight;
 }

and another question is - In what Table property can I save my ViewModel ID(table ID) value, because when
I try to save it in a Tag property, it dissapears when I do an export my Document(contains a table with Tag initialized property) to Html using HtmlFormatProvider?

Thanks in advance.

10 Answers, 1 is accepted

Sort by
0
Petya
Telerik team
answered on 27 Dec 2012, 02:57 PM
Hello Alexander,

I am not sure what your exact scenario is, but generally you can implement uneditable regions in your document using either ReadOnlyRanges or PermissionRanges. 

The idea behind ReadOnlyRanges is that most of the document would be editable and only certain parts will be read only. As all ranges are specified using a range start and range end, which are Inline document elements, that means that you cannot prevent the user from typing before or after the annotation range, i.e. the user will always be able to insert new content at the beginning and the end of the document. They are only persisted when exporting to XAML.

PermissionRanges on the other hand, fulfill the opposite scenario, when most of the document is uneditable and different users can edit only certain parts of the document. When the protection is lifted, all users can insert new permission ranges. When protection is enforced, the current user can only edit the parts he has rights to - he can insert new content in the document or define new permission ranges. You can take a look at the way document protection can be used in this help article and our demos and decide whether it fits your case. They are exported to docx and XAML formats.

As for your other note, indeed the Tag property of document elements is not exported to HTML. The HtmlFormatProvider aims at exporting valid HTML code and the currently supported tags are listed here. When it comes to the Tag property, it can only be exported to XAML, as this is the native format for RadDocument and provides almost lossless export/import round trips.

 
Regards,
Petya
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Alexander
Top achievements
Rank 1
answered on 21 Jan 2013, 05:43 PM
Hi again,

I got you idea about ReadOnlyRanges but I still couldn't find any solution, because as I mentioned above I create a Table and its TableCell's programatically, and each cell contains a Paragraph, and an InlineUIContainer inside it(please see Code Block above),

so could you give me some code sample how can I make a cell readonly.

Because based on the samples from other posts I tried to do something like this, and I am having a problem
with MoveToInline(lBox, 0) method:

DocumentPosition docPositionStart = new DocumentPosition(this.richEditor.Document.DocumentLayoutBox, true);
ParagraphLayoutBox lBox = paragraph.FirstLayoutBox as ParagraphLayoutBox;  
 
//Here I have a problem, because ParagraphLayoutBox isn't inherited from a InlineLayoutBox
docPositionStart.MoveToInline(lBox, 0);//??????????????????

Thanks in advance,
Alexander


0
Alexander
Top achievements
Rank 1
answered on 23 Jan 2013, 09:30 AM
0
Petya
Telerik team
answered on 23 Jan 2013, 05:53 PM
Hi Alexander,

You can make a paragraph read only using the following approach:
Paragraph paragraph = editor.Document.CaretPosition.GetCurrentInline().GetParentOfType<Paragraph>();
 
DocumentPosition docPositionStart = new DocumentPosition(this.editor.Document);
DocumentPosition docPositionEnd = new DocumentPosition(this.editor.Document);
 
docPositionStart.MoveToInline(paragraph.Inlines.First);
docPositionEnd.MoveToInline(paragraph.Inlines.First);
 
docPositionStart.MoveToFirstPositionInParagraph();
docPositionEnd.MoveToLastPositionInParagraph();
 
editor.Document.InsertReadOnlyRange(docPositionStart, docPositionEnd);
This will make the paragraph where the caret is located read-only. However, please bear in mind that TableCells and Paragraphs are not equivalent document elements. Actually, a table cell can contain multiple paragraphs, and the above code will not prevent users from adding additional content in the cell.

Unfortunately, as table cells are not inlines, it is not possible to add range starts and ends within the Table structure itself.

I hope this is helpful!
 
All the best,
Petya
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Alexander
Top achievements
Rank 1
answered on 24 Jan 2013, 09:07 AM
Good day Petya,

your solution didn't help me, after that logic had been applied to a paragraph in each TableCell, user still can edit the cell.

If it is impossible to make readonly TableCells - do you have any solution how to make ReadOnly the whole table?

Thanks,
Alexander.
0
Petya
Telerik team
answered on 25 Jan 2013, 03:05 PM
Hello Alexander,

I am sorry this solution does not fit your needs. Indeed, as I previously said, inline elements such as range start and end cannot be added around a table cell, as the element hierarchy does not allow it.

As for making a whole table read-only, the logic is pretty much the same - you should locate the positions prior and after the table and insert the read-only range. This can be implemented as follows:
TableCellLayoutBox tableCell = this.editor.Document.CaretPosition.GetCurrentTableCellBox();
Table table = tableCell.AssociatedTableCell.Row.Table;
  
DocumentPosition start = new DocumentPosition(editor.Document);
DocumentPosition end = new DocumentPosition(editor.Document);
  
start.MoveToInline((table.PreviousSibling as Paragraph).Inlines.First);
start.MoveToLastPositionInParagraph();
  
end.MoveToInline((table.NextSibling as Paragraph).Inlines.First);
end.MoveToFirstPositionInParagraph();
  
editor.Document.InsertReadOnlyRange(start, end);

I hope the latter solution will fit your requirements.
 
Kind regards,
Petya
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Alexander
Top achievements
Rank 1
answered on 27 Jan 2013, 07:52 PM
Hi Petya,

You solution is what I actually need, but it throws an NullReferenceException in line
start.MoveToInline((table.PreviousSibling as Paragraph).Inlines.First);
because the table.PreviousSibling property is null.

I just create a table, insert rows, cells etc., and it is inserted into a my RadReachTextBox.
what logic do I have:
Table table = new Table(2, 3);
//Add rows, cells
 
//richEditor - is my Rad reach text box control
this.richEditor.InsertTable(table);
this.richEditor.Document.UpdateLayout();
this.richEditor.UpdateEditorLayout();
 
//And your code:
DocumentPosition start = new DocumentPosition(this.richEditor.Document);
DocumentPosition end = new DocumentPosition(richEditor.Document);

//+++++++NullReferenceException, table.PreviousSibling is NULL???++++++
start.MoveToInline((table.PreviousSibling as Paragraph).Inlines.First);  
start.MoveToLastPositionInParagraph();
end.MoveToInline((table.NextSibling as Paragraph).Inlines.First);
end.MoveToFirstPositionInParagraph();
richEditor.Document.InsertReadOnlyRange(start, end);

So what is wrong here in my logic?

Regards,
Alexander
0
Petya
Telerik team
answered on 28 Jan 2013, 04:25 PM
Hi Alexander,

DocumentPositions are associated with a RadDocument instance - the one passed as a parameter to their constructor. The table you are trying to access when moving the position:
start.MoveToInline((table.PreviousSibling as Paragraph).Inlines.First);
is the instance you've previously created from code. When you insert a document element, it is copied and its copy is inserted in the document, so this is not the table located in the document currently shown in the editor. Thus, this Table instance does not have a root document and siblings.

Instead, you should locate the table in the document which is shown in the editor and move the positions to its siblings:
start.MoveToInline((editor.Document.EnumerateChildrenOfType<Table>().First().PreviousSibling as Paragraph).Inlines.First);
start.MoveToLastPositionInParagraph();
end.MoveToInline((editor.Document.EnumerateChildrenOfType<Table>().First().NextSibling as Paragraph).Inlines.First);
end.MoveToFirstPositionInParagraph();
editor.Document.InsertReadOnlyRange(start, end);

I hope this makes things clearer.
 
Kind regards,
Petya
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Alexander
Top achievements
Rank 1
answered on 28 Jan 2013, 05:53 PM
Hi Petya,

thank's for clarification - currently with your updated code my table becomes  ReadOnly, but if I below
try to export my RadDocument to string using HtmlFormatProvider - I got the StackOverflowExceptions
Table table = new Table(...);
 
//Already working code
this.richEditor.InsertTable(table);
 
List<Table> tables = this.richEditor.Document.EnumerateChildrenOfType<Table>().ToList();
 
//Try to find a table by some ID, and it is found
Table table = tables.SingleOrDefault(t => new Guid(t.Tag) == tableID);
 
DocumentPosition start = new DocumentPosition(this.richEditor.Document);
DocumentPosition end = new DocumentPosition(richEditor.Document);
start.MoveToInline((table.PreviousSibling as Paragraph).Inlines.First);
start.MoveToLastPositionInParagraph();
end.MoveToInline((table.NextSibling as Paragraph).Inlines.First);
end.MoveToFirstPositionInParagraph();
richEditor.Document.InsertReadOnlyRange(start, end);
 
//The Table has become a ReadOnly - OK
 
 
//Try to export RadDocument to html
HtmlFormatProvider _formatProvider = new HtmlFormatProvider();
_formatProvider.ExportSettings = new HtmlExportSettings();
_formatProvider.ExportSettings.DocumentExportLevel = DocumentExportLevel.Fragment;
_formatProvider.ExportSettings.StyleRepositoryExportMode = StyleRepositoryExportMode.DontExportStyles;
  
//StackOverFlowException occures!!!!!!!!!
string s = _formatProvider.Export(richEditor.Document);

I think we are very close to the right solution, thanks in advance.

Regards,
Alexander.
0
Petya
Telerik team
answered on 31 Jan 2013, 08:52 AM
Hi Alexander,

I was unable to reproduce the behavior you are observing. Please share some more details on your setup, such as what are the contents of your document, besides the read-only table - does the document contain other ranges, custom annotations, etc.? We would highly appreciate exact steps to reproduce.

Thank you in advance!
 
Kind regards,
Petya
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

Tags
RichTextBox
Asked by
Alexander
Top achievements
Rank 1
Answers by
Petya
Telerik team
Alexander
Top achievements
Rank 1
Share this question
or