Or How to Store Semantic Information In Documents Through Custom Annotations

When we develop RadRichTextBox’s API, we always try to make it as extensible as possible. One of the most popular demands was the option to store “meta” information about parts of the document which is not directly visible by the user.

The technique that most developers attempted to implement was to extend the document model and use custom document elements (Spans, Paragraphs, etc.). This approach, however, is not quite reliable, because RadDocument controls the lifecycle of all document elements while editing the content in RadRichTextBox and the document structure is only concerned with formatting. For example, when using the features Bold, Italic, fore color, etc., Spans are added and removed, split and merged and the semantic information that they carry can be lost. Moreover, there are no certain rules that can be used to identify when this information should be preserved and when removed when the document element is edited or deleted. The behavior on rich-text copy/paste in terms of duplicating or ignoring the semantics is also undefined. 

We have addressed the demand for preserving meta-information in the document by implementing custom annotation ranges. They are specifically designed to store such semantic data and are fully customizable in terms of the behavior they take on selection and deletion.

We have created a demo on how custom annotation ranges can be used to store semantic information in the document. The example, which is available here, shows an editor for a semantically tagged document in the form of a recipe. To best show how that information can be used, we have implemented conversion between the hRecipe microformat and RadDocument with special annotations to mark the position of various hRecipe properties. To achieve this, we have used a combination of features: custom annotations, document protection and a custom format provider.

The blue regions (custom annotations) in the picture above indicate the areas that the user can edit (implemented using document protection). These parts of the document are then extracted by a custom format provider and exported to HTML.

Custom Annotations

There are basically two types of annotations in RadDocument – annotation markers and annotation ranges. The first type can be used by inheriting AnnotationMarkerBase and are meant to be used for single objects such as images. The second type can be used to mark parts of the document. The start and end of the range are marked by inline document elements inheriting from AnnotationRangeStart and AnnotationRangeEnd for the start/end respectively. Whichever you choose, there are some abstract methods that you will have to override, such as CreateNewElementInstance and CopyContentOverride.

By default all annotations are markup-only in the sense that they do not have any appearance. If you want to display a highlight, range brackets or anything else, you can use the UI layers feature of RadRichTextBox. The demo uses the built-in protection range decoration layer with a custom color.

Example custom inline range start

public class SemanticRangeStart : AnnotationRangeStart
{
    [XamlSerializable]

    public string Name { getset; } 

    public SemanticRangeStart()
    {
    } 

    public SemanticRangeStart(string name)
    {
        this.Name = name;
    } 

    public override bool SkipPositionBefore
    {
        get { return true; }
    } 

    protected override void CopyContentFromOverride(DocumentElement fromElement)
    {
        this.Name = ((SemanticRangeStart)fromElement).Name;
    } 

    protected override DocumentElement CreateNewElementInstance()
    {
        return new SemanticRangeStart();
    }
}

Here you can see a class that inherits from AnnotationRangeStart. The overridden methods and properties enable RadRichTextBox to treat the annotation range start as an inline. In order to customize the ranges more finely, you can also have your class derive from FieldRangeStart. In this way, you could specify the behavior when using the cursor to position the caret inside the custom range, deleting the range through backspace or delete, etc. The Name property is serialized in XAML, as seen by the XamlSerializable attribute.

Implementing annotation range end is analogical.

Serialization

Of the default document format providers, custom annotations are supported only in XAML. The other formats do not offer such extensibility. When triggering export XamlFormatProvider will generate prefixes for each custom annotation namespace (custom1, custom2, etc.) which ensures that they can be successfully imported afterwards.

In order to serialize the appropriate attributes, the following two attributes can be used: XamlSerializable – indicates that the property should be serialized as an inline property, and XamlCompositePropertySerializable – serialized as XAML composite property.

Custom Format Provider

The demo uses a custom format provider to export a semantically tagged RadDocuments to an hRecipe-tagged HTML document and vice-versa. The implementation is contained in the HRecipeFormatProvider class. It has two parts:

  • Export: the format provider first extracts the semantic regions from the document. For each part of the hRecipe specification it supports, it looks for SemanticRangeStart/SemanticRangeEnd pairs with the respective names and then creates a respective fragment. Then it proceeds to export these parts to HTML and fill them inside an HTML template prepared for the hRecipe content.
  • Import: the format provider scans the document for nodes tagged as hRecipe properties, imports them using HtmlFormatProvider and then fills in the previously-prepared placeholders.

Document Protection

In order to allow the user to edit only the content of the recipe and not the reserved spaces – labels and such, document protection is used. The document is in protected mode and the unprotect button has been removed from the ribbon. By default, when the document is protected, the ranges which the user has permission to edit are yellowish, however, for the purposes of this demo, it has been changed to blue using the EnforcedPermissionRangeBrush.


About the Author

Iva Toteva

is a software developer and works closely with clients to assist them in utilizing the RadControls they use for the purposes of their application. The controls in her domain include RadRichTextBox, RadSpreadsheet and RadPdfViewer.

Related Posts

Comments

Comments are disabled in preview mode.