New to Telerik UI for WinForms? Download free 30-day trial

Margins

As of R2 2021 SP1 RadSyntaxEditorElement exposes the Margins collection where you can add elements to predefined containers: Left, Top, Bottom, Right, and ScrollableLeft, ScrollableTop, ScrollableRight, ScrollableBottom. The allowed elements need to inherit the Telerik.WinControls.SyntaxEditor.UI.FrameworkElement.

Margin Panels

The following example demonstrates how you can add some custom elements around the RadSyntaxEditor and provides a visualization of the default locations for all panels. It also demonstrates the line numbers and folding tagger features, which are implemented with the help of the left scrollable margin.

Defining Simple Margins

this.radSyntaxEditor1.SyntaxEditorElement.Margins.Left.Add(new Telerik.WinControls.SyntaxEditor.UI.Rectangle() { Fill = Brushes.LightYellow, Width = 20 });
this.radSyntaxEditor1.SyntaxEditorElement.Margins.Right.Add(new Telerik.WinControls.SyntaxEditor.UI.Rectangle() { Fill = Brushes.LightGreen, Width = 20 });
this.radSyntaxEditor1.SyntaxEditorElement.Margins.Top.Add(new Telerik.WinControls.SyntaxEditor.UI.Rectangle() { Fill = Brushes.LightPink, Height = 20 });
this.radSyntaxEditor1.SyntaxEditorElement.Margins.Bottom.Add(new Telerik.WinControls.SyntaxEditor.UI.Rectangle() { Fill = Brushes.LightSkyBlue, Height = 20 });

this.radSyntaxEditor1.SyntaxEditorElement.Margins.ScrollableLeft.Add(new Telerik.WinControls.SyntaxEditor.UI.Rectangle() { Fill = Brushes.LightBlue, Width = 20 });
this.radSyntaxEditor1.SyntaxEditorElement.Margins.ScrollableRight.Add(new Telerik.WinControls.SyntaxEditor.UI.Rectangle() { Fill = Brushes.LightSeaGreen, Width = 20 });
this.radSyntaxEditor1.SyntaxEditorElement.Margins.ScrollableTop.Add(new Telerik.WinControls.SyntaxEditor.UI.Rectangle() { Fill = Brushes.LightCoral, Height = 20 });
this.radSyntaxEditor1.SyntaxEditorElement.Margins.ScrollableBottom.Add(new Telerik.WinControls.SyntaxEditor.UI.Rectangle() { Fill = Brushes.LightGray, Height = 20 });

Figure 1: Defining Simple Margins

WinForms RadSyntaxEditor Defining Simple Margins

Indicators Margin

You can add indicators to particular lines of the RadSyntaxEditor control by using the new IndicatorsMargin<T> class.

The generic type parameter T determines the type of the created object which must be a FrameworkElement. The class also exposes an UpdateIndicator method in which you can set the properties of the created indicator element. You can also conditionally style the element as the method also provides the line number corresponding to the line that the indicator is drawn on.

The class inherits from the abstract IndicatorsMarginBase class which defines the IndicatorBrush property used to control the background of the margin and the Indicators property which holds a collection of integers corresponding to the lines which include an indicator element.

Breakpoints Indicator

This example demonstrates how to create a margin which holds a collection of breakpoints.

Defining Breakpoints Margins

private void SetupBreakPoints()
{
    BreakpointsMargin breakpointsMargin = new BreakpointsMargin(this.radSyntaxEditor1.SyntaxEditorElement); 
    this.radSyntaxEditor1.SyntaxEditorElement.Margins.ScrollableLeft.Insert(0, breakpointsMargin);
}

/// <summary>
/// A margin holding a collection of breakpoints to highlight lines of the RadSyntaxEditor control.
/// </summary>
public class BreakpointsMargin : IndicatorsMargin<Ellipse>
{
    /// <summary>
    /// Initializes a new instance of the <see cref="BreakpointsMargin"/> class.
    /// </summary>
    /// <param name="syntaxEditor">The RadSyntaxEditor instance.</param>
    public BreakpointsMargin(RadSyntaxEditorElement syntaxEditor)
        : base(syntaxEditor)
    {
        this.IndicatorBrush = new SolidBrush(System.Drawing.Color.FromArgb(255, 210, 47, 47));
    }

    /// <summary>
    /// Called when an indicator needs to be updated. This can happen when the indicator is
    /// first created, when it is brought inside or outside of the viewport or when
    /// the EditorFontSize property of the RadSyntaxEditor or the IndicatorBrush property
    /// of the margin change.
    /// </summary>
    /// <param name="path">The Path to update.</param>
    /// <param name="lineNumber">The line number the indicator is placed on.</param>
    protected override void UpdateIndicator(Ellipse ellipse, int lineNumber)
    {
        if (ellipse.Width != this.Editor.EditorFontSize)
        {
            ellipse.Width = this.Editor.EditorFontSize;
        }

        if (ellipse.Height != this.Editor.EditorFontSize)
        {
            ellipse.Height = this.Editor.EditorFontSize;
        }

        if (ellipse.Background != this.IndicatorBrush)
        {
            ellipse.Background = this.IndicatorBrush;
        }
    }
}

Figure 2: Defining Breakpoint Margins

WinForms RadSyntaxEditor Defining Breakpoint Margins

You can add new breakpoints by clicking on the margin in the UI.

Bookmarks Indicator

This example demonstrates how to create a margin which holds a collection of bookmarks.

Defining Bookmarks Margins

private void SetupBookmarkMargins()
{
    BookmarksMargin bookmarksMargin = new BookmarksMargin(this.radSyntaxEditor1.SyntaxEditorElement);
    this.radSyntaxEditor1.SyntaxEditorElement.Margins.ScrollableLeft.Insert(0, bookmarksMargin);
}
public class BookmarksMargin : GlyphsMargin
{
    private const string BookmarksGlyph = "\uF02E";

    public BookmarksMargin(RadSyntaxEditorElement syntaxEditor)
        : base(syntaxEditor)
    {
        this.CustomFont = "Font Awesome 5 Free Solid";
    }

    protected override void UpdateIndicator(TextBlock element, int lineNumber)
    {
        base.UpdateIndicator(element, lineNumber);

        element.Margin = new System.Windows.Forms.Padding(2, 0, 0, 0);
    }

    public override string GetGlyph()
    {
        return BookmarksGlyph;
    }
}

public abstract class GlyphsMargin : IndicatorsMargin<TextBlock>
{
    public GlyphsMargin(RadSyntaxEditorElement syntaxEditor)
        : base(syntaxEditor)
    {
    }

    protected override void UpdateIndicator(TextBlock element, int lineNumber)
    {
        element.Width = this.Width;
        element.Height = this.Width;

        element.FontFamily = new FontFamily(this.CustomFont);
        element.Foreground = this.IndicatorBrush;
        element.Text = this.GetGlyph();
        element.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
    }

    public abstract string GetGlyph();
}

Figure 3: Defining Bookmarks Margins

WinForms RadSyntaxEditor Defining Bookmarks Margins

Stars Indicators

Using the GlyphsMargin implementation in the previous example, we can construct an indicator with any glyph, e.g. a star glyph:

Defining Stars Margins

private void SetupStarsMargins()
{
    StarsMargin starsMargin = new StarsMargin(this.radSyntaxEditor1.SyntaxEditorElement);
    this.radSyntaxEditor1.SyntaxEditorElement.Margins.ScrollableLeft.Insert(0, starsMargin);
}

public class StarsMargin : GlyphsMargin
{
    private const string StarGlyph = "\uF005";

    public StarsMargin(RadSyntaxEditorElement syntaxEditor)
        : base(syntaxEditor)
    {
        this.Background = new System.Drawing.SolidBrush(System.Drawing.Color.LightGray);

        this.CustomFont = "Font Awesome 5 Free Regular";
    }

    public override string GetGlyph()
    {
        return StarGlyph;
    }
}

Figure 4: Defining Stars Margins

WinForms RadSyntaxEditor Defining Stars Margins

SVG Indicators

It is possible to create an indicator with a vector image which is scaled properly when RadSyntaxEditor is zoomed.

Defining SvgsMargins

private void SetupSvgMargins()
{
    SvgsMargin svgsMargin = new SvgsMargin(this.radSyntaxEditor1.SyntaxEditorElement)
    {
        SvgImage = RadSvgImage.Deserialize(File.ReadAllText(@"..\..\Resources\insert merge field-01.svg"))
    };
    this.radSyntaxEditor1.SyntaxEditorElement.Margins.ScrollableRight.Insert(0, svgsMargin);
}

/// <summary>
/// A margin holding a collection of breakpoints to highlight lines of the RadSyntaxEditor control.
/// </summary>
public class SvgsMargin : IndicatorsMargin<RadSvgFrameworkElement>
{
    /// <summary>
    /// Initializes a new instance of the <see cref="BreakpointsMargin"/> class.
    /// </summary>
    /// <param name="syntaxEditor">The RadSyntaxEditor instance.</param>
    public SvgsMargin(RadSyntaxEditorElement syntaxEditor)
        : base(syntaxEditor)
    {
    }

    public RadSvgImage SvgImage { get; set; }

    protected override void UpdateIndicator(RadSvgFrameworkElement svgElement, int lineNumber)
    {
        svgElement.SvgImage = this.SvgImage;
        if (svgElement.Width != this.Editor.EditorFontSize)
        {
            svgElement.Width = this.Editor.EditorFontSize;
        }

        if (svgElement.Height != this.Editor.EditorFontSize)
        {
            svgElement.Height = this.Editor.EditorFontSize;
        }
    }
}

public class RadSvgFrameworkElement : FrameworkElement, IImageElement
{
    private ImagePrimitiveImpl imagePrimitiveImpl;

    private RadSvgImage svgImage;

    protected override void InitializeFields()
    {
        base.InitializeFields();

        this.imagePrimitiveImpl = new ImagePrimitiveImpl(this);
    }

    public RadSvgImage SvgImage
    {
        get
        {
            return this.svgImage;
        }
        set
        {
            this.svgImage = value;
        }
    }

    public System.Drawing.Image Image { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
    public int ImageIndex { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
    public string ImageKey { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }

    protected override void PaintElement(IGraphics graphics, float angle, System.Drawing.SizeF scale)
    {
        base.PaintElement(graphics, angle, scale);

        this.PaintImage(graphics, this.SvgImage);
    }

    private void PaintImage(IGraphics graphics, RadSvgImage image)
    {
        image.Width = this.Bounds.Width;
        image.Height = this.Bounds.Height;

        this.imagePrimitiveImpl.PaintImage(graphics, image, this.Bounds,
                                            ImageLayout.Center, ContentAlignment.MiddleCenter, 1f, false);
    }
}

Figure 5: Defining SVG Margins

WinForms RadSyntaxEditor Defining SVG Margins