custom span indicator

SyntaxEditor for Windows Forms Forum

Posted 10 years ago by Nassim Farhat
Version: 4.0.0284
Avatar
I created my custom span indicator that draws a glyph of a yellow arrow in the margin for step-by-step debugging.

I want to be able to draw a yellow arrow on line 1 even if there is no text inside the line.

So I add span indicator in the following way:

SpanIndicatorLayer layer = syntaxEditor.Document.SpanIndicatorLayers[layerKey];
layer.Add(indicator, textRange);

but if the absoluteLength of the TextRange = 0 an exepction will be thrown.

How can i draw a glypth in the margin even if there is no characters on the line.

Regards

Comments (7)

Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Nassim,

By default span indicators require at least one character in the range. You can override the SpanIndicator.AllowZeroLength property to return true and that will likely get you going.


Actipro Software Support

Posted 10 years ago by Nassim Farhat
Avatar
Here i my version of SpanIndicator class, I placed the overwrite inside for AllowZeroLength to return true as you said. Now my application does not crash anymore when i try to add a span indicator layor with textRange.AbsoluteLength = 0 as such:

layer.Add(indicator, textRange);

I still have a problem because my yellow arrow is not displayed!!!! There is a weird behaviour though, I found that even if i systematicaly create a new STYellowArrowSpanIndicator, when i use it in an empty document and want to assign it in the margin of line 1, the ArrowPolygone keeps the old value that was assigned to it.... the one where a textrange.absolutelength was not equal to 0??? It is good to note at this point that I am using many instances of the SyntaxEditor as i have many documents in my application. But the thing is that, ArrowPolygone field is not static!!! it is systematically set to null on creation..... but yet, it remembers the value of teh gypth from the 1st document????

Have you ever seen some similar behaviour?

    /// <summary>
    /// Represents a custom span indicator.  You can use a custom span indicator to draw anything.
    /// </summary>
    internal class STYellowArrowSpanIndicator : SpanIndicator
    {
        private Color color;
        private bool rotate90;
        private PointF[] ArrowPolygone = null;

        /// <summary>
        /// Initializes a new instance of the <c>CustomSpanIndicator</c> class.
        /// </summary>
        public STYellowArrowSpanIndicator()
            : this(Color.Red, false)
        {
            
        }

        /// <summary>
        /// Initializes a new instance of the <c>CustomSpanIndicator</c> class.
        /// </summary>
        /// <param name="color">The border color.</param>
        /// <param name="rotate">Rotate 90 degrees if true</param>
        public STYellowArrowSpanIndicator(Color color, bool rotate)
            : base(STConstants.YELLOW_ARROW_KEY)
        {
            this.color = color;
            this.rotate90 = rotate;
        }

        /// <summary>
        /// Applies the adornments of the span indicator to the specified <see cref="HighlightingStyleResolver"/>.
        /// </summary>
        /// <param name="resolver">The <see cref="HighlightingStyleResolver"/> to modify.</param>
        protected override void ApplyHighlightingStyleAdornments(HighlightingStyleResolver resolver)
        {
            resolver.ApplyBorder(color, HighlightingStyleLineStyle.Dot, HighlightingStyleBorderCornerStyle.Square);
        }

        /// <summary>
        /// Applies the foreground and background colors of the span indicator to the specified <see cref="HighlightingStyleResolver"/>.
        /// </summary>
        /// <param name="resolver">The <see cref="HighlightingStyleResolver"/> to modify.</param>
        protected override void ApplyHighlightingStyleColors(HighlightingStyleResolver resolver)
        {
            resolver.SetBackColor(Color.FromArgb(200, Color.Thistle));
            resolver.SetForeColor(Color.DarkMagenta);
        }

        /// <summary>
        /// Applies the font changes of the span indicator to the specified <see cref="HighlightingStyleResolver"/>.
        /// </summary>
        /// <param name="resolver">The <see cref="HighlightingStyleResolver"/> to modify.</param>
        protected override void ApplyHighlightingStyleFont(HighlightingStyleResolver resolver)
        {
            //resolver.SetFontFamilyName("Arial");
            //resolver.SetFontSize(10f);
        }

        /// <summary>
        /// Draws the glyph associated with the indicator.
        /// </summary>
        /// <param name="e">A <see cref="PaintEventArgs"/> that contains the event data.</param>
        /// <param name="bounds">A <c>Rectangle</c> specifying the bounds in which to draw.</param>
        /// <remarks>
        /// This method should be implemented by indicators that have a glyph.
        /// Ensure that the indicator's <see cref="HasGlyph"/> property returns <c>true</c> if this method is implemented.
        /// </remarks>
        public override void DrawGlyph(PaintEventArgs e, Rectangle bounds)
        {
            if (ArrowPolygone == null)
            {
                int TopBarNominator = 7;
                int BottomBarNominator = 13;
                int Denominator = 20;
                int SideOffset = 0;


                //Create points that define Arrow polygon.
                PointF point1 = new PointF(bounds.X + SideOffset, bounds.Y + (TopBarNominator * bounds.Height) / Denominator);
                PointF point2 = new PointF(bounds.Width / 2, bounds.Y + (TopBarNominator * bounds.Height) / Denominator);
                PointF point3 = new PointF(bounds.Width / 2, bounds.Y + SideOffset);
                PointF point4 = new PointF(bounds.Width - SideOffset, bounds.Y + bounds.Height / 2);
                PointF point5 = new PointF(bounds.Width / 2, bounds.Y + bounds.Height - SideOffset);
                PointF point6 = new PointF(bounds.Width / 2, bounds.Y + (BottomBarNominator * bounds.Height) / Denominator);
                PointF point7 = new PointF(bounds.X + SideOffset, bounds.Y + (BottomBarNominator * bounds.Height) / Denominator);
                ArrowPolygone = new PointF[7];
                ArrowPolygone.SetValue(point1, 0);
                ArrowPolygone.SetValue(point2, 1);
                ArrowPolygone.SetValue(point3, 2);
                ArrowPolygone.SetValue(point4, 3);
                ArrowPolygone.SetValue(point5, 4);
                ArrowPolygone.SetValue(point6, 5);
                ArrowPolygone.SetValue(point7, 6);

                if (rotate90)
                {
                    var rotationPoint = new PointF(point2.X, (point2.Y + point6.Y) / 2);
                    Rotate(-900, rotationPoint, ArrowPolygone);
                }
            }

            //draw Polygone.
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            e.Graphics.DrawPolygon(new Pen(new SolidBrush(Color.Black), 1), ArrowPolygone);
            e.Graphics.FillPolygon(Brushes.Yellow, ArrowPolygone);
        }

        protected void Rotate(int angle, PointF ptCenter, PointF[] ptControl)
        {
            // If the angle is 0, there's nothing to do
            if (angle == 0)
                return;

            // The angle is in tenths of a degree. Convert to radians
            double fAngle = (angle / 10.0) / 57.29578;

            // Calculate the sine of the angle
            double fSine = Math.Sin(fAngle);

            // Calculate the cosing of the angle
            double fCosine = Math.Cos(fAngle);

            // Translate the center point so it can be the center of rotation
            double fRotateX = ptCenter.X - ptCenter.X * fCosine - ptCenter.Y * fSine;
            double fRotateY = ptCenter.Y + ptCenter.X * fSine - ptCenter.Y * fCosine;
            for (int x = 0; x < ptControl.Length; ++x)
            {
                // Rotate the control point and add the translated center point
                double fNewX = ptControl[x].X * fCosine + ptControl[x].Y * fSine + fRotateX;
                double fNewY = -ptControl[x].X * fSine + ptControl[x].Y * fCosine + fRotateY;

                // Put the new values in the control point
                ptControl[x].X = (float)fNewX;
                ptControl[x].Y = (float)fNewY;
            }
        }
  

        /// <summary>
        /// Gets whether the span indicator contains a font-related change.
        /// </summary>
        /// <value>
        /// <c>true</c> if the span indicator contains a font-related change; otherwise, <c>false</c>.
        /// </value>
        /// <remarks>
        /// This property lets <see cref="SyntaxEditor"/> know whether display lines need to be recalculated
        /// when the span indicator is added.
        /// </remarks>
        public override bool HasFontChange
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        /// Gets whether the indicator has a glyph that appears in the indicator margin.
        /// </summary>
        /// <value>
        /// <c>true</c> if the indicator has a glyph that appears in the indicator margin; otherwise, <c>false</c>.
        /// </value>
        public override bool HasGlyph
        {
            get
            {
                return true;
            }
        }

        protected override bool AllowZeroLength
        {
            get
            {
                return true;
            }
        }
Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Nassim,

It's hard to help with forum post code. If you'd like us to look into it more, please make a simple sample project that just has an editor and repros the issue. ZIP it up (without any .exe files) and send it to us so we can debug it. Thanks.


Actipro Software Support

Posted 10 years ago by Nassim Farhat
Avatar
Sorry... I tried to look for the attachement tool.... could not find it!


Anyways...this is very very simple to reproduce. If you oculd bare with me 2 min, i will chow you how i did it using your samples.

Use the C# test Application samples you gave us with SyntaxEditor WinForm product.
In there you will have the example Form IndicatorsForms. Change the CustomSpanIndicator to overwrite the AllowZeroLengthproperty:

protected override bool AllowZeroLength
        {
            get
            {
                return true;
            }
        }
Add the following condition in the AddSpanIndicator Event:
// Ensure there is a selection
            if (textRange.AbsoluteLength == 0 && indicator.Name != "Custom") {
                MessageBox.Show("Please make a selection first.");
                return;
            }
start the application...

Try to add a custom span indicator in the margin of an empty line.... You will see that nothing appears in teh margin even though in the code you add the layer!!

For simplicity.... I have givin the code of the IndicatorsForms.cs below so that you could copy paste directly into the sample:


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using ActiproSoftware.SyntaxEditor;

namespace TestApplication.QuickStart {

    /// <summary>
    /// A form for testing indicators.
    /// </summary>
    public class IndicatorsForm : System.Windows.Forms.Form {
        private ActiproSoftware.SyntaxEditor.SyntaxEditor editor;
        private System.Windows.Forms.Label editor2Label;
        private ColorButton selectionBackColorColorButton;
        private Label label1;
        private Label label2;
        private ColorButton selectionBorderColorColorButton;
        private GroupBox groupBox1;
        private GroupBox groupBox2;
        private CheckBox selectionSemiTransparentCheckBox;
        private GroupBox groupBox3;
        private Label label8;
        private ImageList imageList;
        private Button bookmarkToggleButton;
        private Button bookmarkClearButton;
        private Button bookmarkNextButton;
        private Button bookmarkPreviousButton;
        private Button bookmarkEnableButton;
        private Label label3;
        private Button addErrorIndicatorButton;
        private ColorButton errorIndicatorColorColorButton;
        private Button addCustomIndicatorButton;
        private Button clearIndicatorsButton;
        private Button addBreakpointIndicatorButton;
        private Button enableDisableBreakpointIndicatorButton;
        private Label label4;
        private ColorButton selectionForeColorColorButton;
        private LinkLabel helpLinkLabel;
        private IContainer components;

        public IndicatorsForm() {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            // Load a language
            editor.Document.LoadLanguageFromXml(Program.DynamicLexersPath + "ActiproSoftware.CSharp.xml", 0);

            // Update the controls
            editor.Document.LineIndicators.Add(new BookmarkLineIndicator(), 1);
            BookmarkLineIndicator bookmark = new BookmarkLineIndicator();
            bookmark.CanNavigateTo = false;
            editor.Document.LineIndicators.Add(bookmark, 10);
            editor.Document.LineIndicators.Add(new BookmarkLineIndicator(), 16);
            this.AddSpanIndicator(SpanIndicatorLayer.SyntaxErrorKey, SpanIndicatorLayer.SyntaxErrorDisplayPriority, 
                new WaveLineSpanIndicator(Color.Red), new TextRange(268, 277));
            this.AddSpanIndicator(SpanIndicatorLayer.BreakpointKey, SpanIndicatorLayer.BreakpointDisplayPriority, 
                new BreakpointSpanIndicator(), new TextRange(454, 464));
            this.AddSpanIndicator("Custom", 1000, new CustomSpanIndicator(Color.Red), new TextRange(484, 504));
            editor.SelectedView.Selection.TextRange = new TextRange(443, 459);
            selectionBackColorColorButton.Color = editor.RendererResolved.SelectionFocusedBackColor;
            selectionBorderColorColorButton.Color = Color.Navy;
            selectionForeColorColorButton.Color = editor.RendererResolved.SelectionFocusedForeColor;
            selectionSemiTransparentCheckBox.Checked = true;
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing) {
            if (disposing) {
                if (components != null) 
                    components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(IndicatorsForm));
            ActiproSoftware.SyntaxEditor.Document document1 = new ActiproSoftware.SyntaxEditor.Document();
            this.editor2Label = new System.Windows.Forms.Label();
            this.label1 = new System.Windows.Forms.Label();
            this.label2 = new System.Windows.Forms.Label();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.label4 = new System.Windows.Forms.Label();
            this.selectionForeColorColorButton = new TestApplication.ColorButton();
            this.selectionSemiTransparentCheckBox = new System.Windows.Forms.CheckBox();
            this.selectionBackColorColorButton = new TestApplication.ColorButton();
            this.selectionBorderColorColorButton = new TestApplication.ColorButton();
            this.groupBox2 = new System.Windows.Forms.GroupBox();
            this.bookmarkClearButton = new System.Windows.Forms.Button();
            this.imageList = new System.Windows.Forms.ImageList(this.components);
            this.bookmarkNextButton = new System.Windows.Forms.Button();
            this.bookmarkPreviousButton = new System.Windows.Forms.Button();
            this.bookmarkEnableButton = new System.Windows.Forms.Button();
            this.bookmarkToggleButton = new System.Windows.Forms.Button();
            this.label8 = new System.Windows.Forms.Label();
            this.groupBox3 = new System.Windows.Forms.GroupBox();
            this.enableDisableBreakpointIndicatorButton = new System.Windows.Forms.Button();
            this.addCustomIndicatorButton = new System.Windows.Forms.Button();
            this.clearIndicatorsButton = new System.Windows.Forms.Button();
            this.addBreakpointIndicatorButton = new System.Windows.Forms.Button();
            this.addErrorIndicatorButton = new System.Windows.Forms.Button();
            this.errorIndicatorColorColorButton = new TestApplication.ColorButton();
            this.label3 = new System.Windows.Forms.Label();
            this.editor = new ActiproSoftware.SyntaxEditor.SyntaxEditor();
            this.helpLinkLabel = new System.Windows.Forms.LinkLabel();
            this.groupBox1.SuspendLayout();
            this.groupBox2.SuspendLayout();
            this.groupBox3.SuspendLayout();
            this.SuspendLayout();
            // 
            // editor2Label
            // 
            this.editor2Label.AutoSize = true;
            this.editor2Label.Location = new System.Drawing.Point(9, 14);
            this.editor2Label.Name = "editor2Label";
            this.editor2Label.Size = new System.Drawing.Size(465, 13);
            this.editor2Label.TabIndex = 5;
            this.editor2Label.Text = "Change the options to see some of SyntaxEditor\'s indicator features and set the s" +
                "election colors...";
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(18, 20);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(58, 13);
            this.label1.TabIndex = 9;
            this.label1.Text = "Back color";
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(12, 47);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(64, 13);
            this.label2.TabIndex = 11;
            this.label2.Text = "Border color";
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.Add(this.label4);
            this.groupBox1.Controls.Add(this.selectionForeColorColorButton);
            this.groupBox1.Controls.Add(this.selectionSemiTransparentCheckBox);
            this.groupBox1.Controls.Add(this.selectionBackColorColorButton);
            this.groupBox1.Controls.Add(this.label2);
            this.groupBox1.Controls.Add(this.selectionBorderColorColorButton);
            this.groupBox1.Controls.Add(this.label1);
            this.groupBox1.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.groupBox1.Location = new System.Drawing.Point(577, 33);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(208, 155);
            this.groupBox1.TabIndex = 12;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Selection Colors";
            // 
            // label4
            // 
            this.label4.AutoSize = true;
            this.label4.Location = new System.Drawing.Point(22, 75);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size(54, 13);
            this.label4.TabIndex = 18;
            this.label4.Text = "Fore color";
            // 
            // selectionForeColorColorButton
            // 
            this.selectionForeColorColorButton.BackColor = System.Drawing.SystemColors.Window;
            this.selectionForeColorColorButton.Color = System.Drawing.Color.Red;
            this.selectionForeColorColorButton.Location = new System.Drawing.Point(82, 71);
            this.selectionForeColorColorButton.Name = "selectionForeColorColorButton";
            this.selectionForeColorColorButton.Size = new System.Drawing.Size(112, 21);
            this.selectionForeColorColorButton.TabIndex = 17;
            this.selectionForeColorColorButton.Text = "button1";
            this.selectionForeColorColorButton.ColorChanged += new System.EventHandler(this.selectionForeColorColorButton_ColorChanged);
            // 
            // selectionSemiTransparentCheckBox
            // 
            this.selectionSemiTransparentCheckBox.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.selectionSemiTransparentCheckBox.Location = new System.Drawing.Point(17, 98);
            this.selectionSemiTransparentCheckBox.Name = "selectionSemiTransparentCheckBox";
            this.selectionSemiTransparentCheckBox.Size = new System.Drawing.Size(163, 18);
            this.selectionSemiTransparentCheckBox.TabIndex = 18;
            this.selectionSemiTransparentCheckBox.Text = "Back color semi-transparent";
            this.selectionSemiTransparentCheckBox.CheckedChanged += new System.EventHandler(this.selectionSemiTransparentCheckBox_CheckedChanged);
            // 
            // selectionBackColorColorButton
            // 
            this.selectionBackColorColorButton.BackColor = System.Drawing.SystemColors.Window;
            this.selectionBackColorColorButton.Color = System.Drawing.Color.Red;
            this.selectionBackColorColorButton.Location = new System.Drawing.Point(82, 17);
            this.selectionBackColorColorButton.Name = "selectionBackColorColorButton";
            this.selectionBackColorColorButton.Size = new System.Drawing.Size(112, 21);
            this.selectionBackColorColorButton.TabIndex = 15;
            this.selectionBackColorColorButton.Text = "button1";
            this.selectionBackColorColorButton.ColorChanged += new System.EventHandler(this.selectionBackColorColorButton_ColorChanged);
            // 
            // selectionBorderColorColorButton
            // 
            this.selectionBorderColorColorButton.BackColor = System.Drawing.SystemColors.Window;
            this.selectionBorderColorColorButton.Color = System.Drawing.Color.Red;
            this.selectionBorderColorColorButton.Location = new System.Drawing.Point(82, 44);
            this.selectionBorderColorColorButton.Name = "selectionBorderColorColorButton";
            this.selectionBorderColorColorButton.Size = new System.Drawing.Size(112, 21);
            this.selectionBorderColorColorButton.TabIndex = 16;
            this.selectionBorderColorColorButton.Text = "button1";
            this.selectionBorderColorColorButton.ColorChanged += new System.EventHandler(this.selectionBorderColorColorButton_ColorChanged);
            // 
            // groupBox2
            // 
            this.groupBox2.Controls.Add(this.bookmarkClearButton);
            this.groupBox2.Controls.Add(this.bookmarkNextButton);
            this.groupBox2.Controls.Add(this.bookmarkPreviousButton);
            this.groupBox2.Controls.Add(this.bookmarkEnableButton);
            this.groupBox2.Controls.Add(this.bookmarkToggleButton);
            this.groupBox2.Controls.Add(this.label8);
            this.groupBox2.Location = new System.Drawing.Point(26, 33);
            this.groupBox2.Name = "groupBox2";
            this.groupBox2.Size = new System.Drawing.Size(159, 155);
            this.groupBox2.TabIndex = 13;
            this.groupBox2.TabStop = false;
            this.groupBox2.Text = "Line Indicators";
            // 
            // bookmarkClearButton
            // 
            this.bookmarkClearButton.ImageIndex = 4;
            this.bookmarkClearButton.ImageList = this.imageList;
            this.bookmarkClearButton.Location = new System.Drawing.Point(116, 123);
            this.bookmarkClearButton.Name = "bookmarkClearButton";
            this.bookmarkClearButton.Size = new System.Drawing.Size(26, 23);
            this.bookmarkClearButton.TabIndex = 8;
            this.bookmarkClearButton.Click += new System.EventHandler(this.bookmarkClearButton_Click);
            // 
            // imageList
            // 
            this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream")));
            this.imageList.TransparentColor = System.Drawing.Color.Transparent;
            // 
            // bookmarkNextButton
            // 
            this.bookmarkNextButton.ImageIndex = 3;
            this.bookmarkNextButton.ImageList = this.imageList;
            this.bookmarkNextButton.Location = new System.Drawing.Point(91, 123);
            this.bookmarkNextButton.Name = "bookmarkNextButton";
            this.bookmarkNextButton.Size = new System.Drawing.Size(26, 23);
            this.bookmarkNextButton.TabIndex = 7;
            this.bookmarkNextButton.Click += new System.EventHandler(this.bookmarkNextButton_Click);
            // 
            // bookmarkPreviousButton
            // 
            this.bookmarkPreviousButton.ImageIndex = 2;
            this.bookmarkPreviousButton.ImageList = this.imageList;
            this.bookmarkPreviousButton.Location = new System.Drawing.Point(66, 123);
            this.bookmarkPreviousButton.Name = "bookmarkPreviousButton";
            this.bookmarkPreviousButton.Size = new System.Drawing.Size(26, 23);
            this.bookmarkPreviousButton.TabIndex = 6;
            this.bookmarkPreviousButton.Click += new System.EventHandler(this.bookmarkPreviousButton_Click);
            // 
            // bookmarkEnableButton
            // 
            this.bookmarkEnableButton.ImageIndex = 1;
            this.bookmarkEnableButton.ImageList = this.imageList;
            this.bookmarkEnableButton.Location = new System.Drawing.Point(41, 123);
            this.bookmarkEnableButton.Name = "bookmarkEnableButton";
            this.bookmarkEnableButton.Size = new System.Drawing.Size(26, 23);
            this.bookmarkEnableButton.TabIndex = 5;
            this.bookmarkEnableButton.Click += new System.EventHandler(this.bookmarkEnableButton_Click);
            // 
            // bookmarkToggleButton
            // 
            this.bookmarkToggleButton.ImageIndex = 0;
            this.bookmarkToggleButton.ImageList = this.imageList;
            this.bookmarkToggleButton.Location = new System.Drawing.Point(16, 123);
            this.bookmarkToggleButton.Name = "bookmarkToggleButton";
            this.bookmarkToggleButton.Size = new System.Drawing.Size(26, 23);
            this.bookmarkToggleButton.TabIndex = 4;
            this.bookmarkToggleButton.Click += new System.EventHandler(this.bookmarkToggleButton_Click);
            // 
            // label8
            // 
            this.label8.Location = new System.Drawing.Point(13, 20);
            this.label8.Name = "label8";
            this.label8.Size = new System.Drawing.Size(129, 100);
            this.label8.TabIndex = 20;
            this.label8.Text = "Line indicators are placed on document lines.  A common example of line indicator" +
                "s is a bookmark.  Use these buttons to add bookmarks and then navigate to them.";
            // 
            // groupBox3
            // 
            this.groupBox3.Controls.Add(this.enableDisableBreakpointIndicatorButton);
            this.groupBox3.Controls.Add(this.addCustomIndicatorButton);
            this.groupBox3.Controls.Add(this.clearIndicatorsButton);
            this.groupBox3.Controls.Add(this.addBreakpointIndicatorButton);
            this.groupBox3.Controls.Add(this.addErrorIndicatorButton);
            this.groupBox3.Controls.Add(this.errorIndicatorColorColorButton);
            this.groupBox3.Controls.Add(this.label3);
            this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.groupBox3.Location = new System.Drawing.Point(191, 33);
            this.groupBox3.Name = "groupBox3";
            this.groupBox3.Size = new System.Drawing.Size(380, 155);
            this.groupBox3.TabIndex = 14;
            this.groupBox3.TabStop = false;
            this.groupBox3.Text = "Span Indicators";
            // 
            // enableDisableBreakpointIndicatorButton
            // 
            this.enableDisableBreakpointIndicatorButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.enableDisableBreakpointIndicatorButton.Location = new System.Drawing.Point(135, 123);
            this.enableDisableBreakpointIndicatorButton.Name = "enableDisableBreakpointIndicatorButton";
            this.enableDisableBreakpointIndicatorButton.Size = new System.Drawing.Size(112, 23);
            this.enableDisableBreakpointIndicatorButton.TabIndex = 13;
            this.enableDisableBreakpointIndicatorButton.Text = "Enable/Disable Brkpt";
            this.enableDisableBreakpointIndicatorButton.Click += new System.EventHandler(this.enableDisableBreakpointIndicatorButton_Click);
            // 
            // addCustomIndicatorButton
            // 
            this.addCustomIndicatorButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.addCustomIndicatorButton.Location = new System.Drawing.Point(253, 95);
            this.addCustomIndicatorButton.Name = "addCustomIndicatorButton";
            this.addCustomIndicatorButton.Size = new System.Drawing.Size(112, 23);
            this.addCustomIndicatorButton.TabIndex = 11;
            this.addCustomIndicatorButton.Text = "Add Custom Indicator";
            this.addCustomIndicatorButton.Click += new System.EventHandler(this.addCustomIndicatorButton_Click);
            // 
            // clearIndicatorsButton
            // 
            this.clearIndicatorsButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.clearIndicatorsButton.Location = new System.Drawing.Point(253, 123);
            this.clearIndicatorsButton.Name = "clearIndicatorsButton";
            this.clearIndicatorsButton.Size = new System.Drawing.Size(112, 23);
            this.clearIndicatorsButton.TabIndex = 14;
            this.clearIndicatorsButton.Text = "Clear Indicators";
            this.clearIndicatorsButton.Click += new System.EventHandler(this.clearIndicatorsButton_Click);
            // 
            // addBreakpointIndicatorButton
            // 
            this.addBreakpointIndicatorButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.addBreakpointIndicatorButton.Location = new System.Drawing.Point(18, 123);
            this.addBreakpointIndicatorButton.Name = "addBreakpointIndicatorButton";
            this.addBreakpointIndicatorButton.Size = new System.Drawing.Size(112, 23);
            this.addBreakpointIndicatorButton.TabIndex = 12;
            this.addBreakpointIndicatorButton.Text = "Add Breakpoint";
            this.addBreakpointIndicatorButton.Click += new System.EventHandler(this.addBreakpointIndicatorButton_Click);
            // 
            // addErrorIndicatorButton
            // 
            this.addErrorIndicatorButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.addErrorIndicatorButton.Location = new System.Drawing.Point(135, 95);
            this.addErrorIndicatorButton.Name = "addErrorIndicatorButton";
            this.addErrorIndicatorButton.Size = new System.Drawing.Size(112, 23);
            this.addErrorIndicatorButton.TabIndex = 10;
            this.addErrorIndicatorButton.Text = "Add Error Wavy Line";
            this.addErrorIndicatorButton.Click += new System.EventHandler(this.addErrorIndicatorButton_Click);
            // 
            // errorIndicatorColorColorButton
            // 
            this.errorIndicatorColorColorButton.BackColor = System.Drawing.SystemColors.Window;
            this.errorIndicatorColorColorButton.Color = System.Drawing.Color.Red;
            this.errorIndicatorColorColorButton.Location = new System.Drawing.Point(17, 97);
            this.errorIndicatorColorColorButton.Name = "errorIndicatorColorColorButton";
            this.errorIndicatorColorColorButton.Size = new System.Drawing.Size(112, 21);
            this.errorIndicatorColorColorButton.TabIndex = 9;
            this.errorIndicatorColorColorButton.Text = "button1";
            // 
            // label3
            // 
            this.label3.Location = new System.Drawing.Point(15, 20);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(344, 86);
            this.label3.TabIndex = 21;
            this.label3.Text = resources.GetString("label3.Text");
            // 
            // editor
            // 
            this.editor.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            document1.Text = resources.GetString("document1.Text");
            this.editor.Document = document1;
            this.editor.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.editor.Location = new System.Drawing.Point(12, 203);
            this.editor.Name = "editor";
            this.editor.SelectionMarginWidth = 6;
            this.editor.Size = new System.Drawing.Size(786, 368);
            this.editor.TabIndex = 0;
            this.editor.UseDisabledRenderingForReadOnlyMode = true;
            this.editor.ViewMouseHover += new ActiproSoftware.SyntaxEditor.EditorViewMouseEventHandler(this.editor_ViewMouseHover);
            this.editor.ViewMouseDown += new ActiproSoftware.SyntaxEditor.EditorViewMouseEventHandler(this.editor_ViewMouseDown);
            // 
            // helpLinkLabel
            // 
            this.helpLinkLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.helpLinkLabel.AutoSize = true;
            this.helpLinkLabel.Location = new System.Drawing.Point(658, 14);
            this.helpLinkLabel.Name = "helpLinkLabel";
            this.helpLinkLabel.Size = new System.Drawing.Size(140, 13);
            this.helpLinkLabel.TabIndex = 105;
            this.helpLinkLabel.TabStop = true;
            this.helpLinkLabel.Text = "View help on this QuickStart";
            this.helpLinkLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.helpLinkLabel_LinkClicked);
            // 
            // IndicatorsForm
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(810, 583);
            this.Controls.Add(this.helpLinkLabel);
            this.Controls.Add(this.groupBox3);
            this.Controls.Add(this.groupBox2);
            this.Controls.Add(this.groupBox1);
            this.Controls.Add(this.editor);
            this.Controls.Add(this.editor2Label);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "IndicatorsForm";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
            this.Text = "Line and Span Indicators";
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            this.groupBox2.ResumeLayout(false);
            this.groupBox3.ResumeLayout(false);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion
        
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // EVENT HANDLERS
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        
        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void addBreakpointIndicatorButton_Click(object sender, EventArgs e) {
            this.AddSpanIndicator(SpanIndicatorLayer.BreakpointKey, SpanIndicatorLayer.BreakpointDisplayPriority, 
                new BreakpointSpanIndicator(), editor.SelectedView.Selection.TextRange);
            editor.Focus();
        }

        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void addCustomIndicatorButton_Click(object sender, EventArgs e) {
            // NOTE: The source code for the custom indicator is defined below
            this.AddSpanIndicator("Custom", 1000, new CustomSpanIndicator(errorIndicatorColorColorButton.Color), editor.SelectedView.Selection.TextRange);
            editor.Focus();
        }

        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void addErrorIndicatorButton_Click(object sender, EventArgs e) {
            this.AddSpanIndicator(SpanIndicatorLayer.SyntaxErrorKey, SpanIndicatorLayer.SyntaxErrorDisplayPriority, 
                new WaveLineSpanIndicator(errorIndicatorColorColorButton.Color), editor.SelectedView.Selection.TextRange);
            editor.Focus();
        }

        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void bookmarkClearButton_Click(object sender, EventArgs e) {
            editor.Document.LineIndicators.Clear(BookmarkLineIndicator.DefaultName);
            editor.Focus();
        }

        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void bookmarkEnableButton_Click(object sender, EventArgs e) {
            // Toggle the enabled state of the bookmark
            int index = editor.SelectedView.CurrentDocumentLine.LineIndicators.IndexOf(BookmarkLineIndicator.DefaultName);
            if (index != -1) {
                ((BookmarkLineIndicator)editor.SelectedView.CurrentDocumentLine.LineIndicators[index]).CanNavigateTo = 
                    !((BookmarkLineIndicator)editor.SelectedView.CurrentDocumentLine.LineIndicators[index]).CanNavigateTo;
                editor.Invalidate();
            }
            editor.Focus();
        }

        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void bookmarkNextButton_Click(object sender, EventArgs e) {
            // Move to the next bookmark
            editor.SelectedView.GotoNextLineIndicator(BookmarkLineIndicator.DefaultName);
            editor.Focus();
        }
        
        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void bookmarkPreviousButton_Click(object sender, EventArgs e) {
            // Move to the previous bookmark
            editor.SelectedView.GotoPreviousLineIndicator(BookmarkLineIndicator.DefaultName);
            editor.Focus();
        }

        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void bookmarkToggleButton_Click(object sender, EventArgs e) {
            // Toggle the bookmark at the current line
            if (editor.SelectedView.CurrentDocumentLine.LineIndicators.Contains(BookmarkLineIndicator.DefaultName)) {
                // A bookmark is already on the line... remove all bookmarks from the line
                editor.SelectedView.CurrentDocumentLine.LineIndicators.Clear(BookmarkLineIndicator.DefaultName);
            }
            else {
                // Add a bookmark to the line
                editor.Document.LineIndicators.Add(new BookmarkLineIndicator(), editor.Caret.DocumentPosition.Line);
            }
            editor.Focus();
        }
        
        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void clearIndicatorsButton_Click(object sender, EventArgs e) {
            editor.Document.SpanIndicatorLayers.Clear();
        }
        
        /// <summary>
        /// Occurs when the mouse is clicked over a view.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        void editor_ViewMouseDown(object sender, EditorViewMouseEventArgs e) {
            if (e.Clicks == 2) {
                switch (e.HitTestResult.Target) {
                    case SyntaxEditorHitTestTarget.IndicatorMargin:
                        // Show a messagebox if double-clicking on an indicator glyph
                        if (e.HitTestResult.DisplayLine.IsFirstForDocumentLine) {
                            Indicator[] indicators = e.HitTestResult.DocumentLine.GetAllVisibleIndicators();
                            for (int index = indicators.Length - 1; index >= 0; index--) {
                                Indicator indicator = indicators[index];
                                if (indicator.HasGlyph) {
                                    MessageBox.Show(String.Format("You double-clicked a '{0}' indicator glyph.", indicator.Name));
                                    break;
                                }
                            }
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// Occurs when the mouse is hovered over a view.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void editor_ViewMouseHover(object sender, EditorViewMouseEventArgs e) {
            switch (e.HitTestResult.Target) {
                case SyntaxEditorHitTestTarget.IndicatorMargin:
                    // Set the tooltip text for an indicator in the indicator margin if there is one
                    if (e.HitTestResult.DisplayLine.IsFirstForDocumentLine) {
                        Indicator[] indicators = e.HitTestResult.DocumentLine.GetAllVisibleIndicators();
                        for (int index = indicators.Length - 1; index >= 0; index--) {
                            Indicator indicator = indicators[index];
                            if (indicator.HasGlyph) {
                                e.ToolTipText = String.Format("A <b>{0}</b> indicator is under the mouse.", indicator.Name);
                                break;
                            }
                        }
                    }
                    break;
                case SyntaxEditorHitTestTarget.TextArea:
                    // Set the tooltip text for a span indicator in the text area if there is one
                    if (e.HitTestResult.Offset != -1) {
                        SpanIndicator[] indicators = editor.Document.SpanIndicatorLayers.GetIndicatorsForTextRange(new TextRange(e.HitTestResult.Offset), true);
                        if ((indicators != null) && (indicators.Length > 0))
                            e.ToolTipText = String.Format("A <b>{0}</b> span indicator is under the mouse with the range <b>{1}</b>.", 
                                indicators[indicators.Length - 1].Name, indicators[indicators.Length - 1].TextRange);
                    }
                    break;
            }
        }

        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void enableDisableBreakpointIndicatorButton_Click(object sender, EventArgs e) {
            SpanIndicatorLayer layer = editor.Document.SpanIndicatorLayers[SpanIndicatorLayer.BreakpointKey];
            if (layer != null) {
                SpanIndicator[] indicators = layer.GetIndicatorsForTextRange(new TextRange(editor.Caret.Offset));
                if (indicators != null) {
                    foreach (BreakpointSpanIndicator indicator in indicators)
                        indicator.Enabled = !indicator.Enabled;
                    editor.Invalidate();
                }
            }
            editor.Focus();
        }
        
        /// <summary>
        /// Occurs when the link is clicked.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void helpLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {
            Program.ShowDocumentationTopic("QuickStartIndicators");
        }

        /// <summary>
        /// Occurs when the color of the <see cref="ColorButton"/> is changed.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void selectionBackColorColorButton_ColorChanged(object sender, EventArgs e) {
            int alpha = (selectionSemiTransparentCheckBox.Checked ? 200 : 255);
            editor.RendererResolved.SelectionFocusedBackColor = Color.FromArgb(alpha, selectionBackColorColorButton.Color);
            editor.Focus();
        }
        
        /// <summary>
        /// Occurs when the color of the <see cref="ColorButton"/> is changed.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void selectionBorderColorColorButton_ColorChanged(object sender, EventArgs e) {
            editor.RendererResolved.SelectionFocusedBorderColor = selectionBorderColorColorButton.Color;
            editor.Focus();
        }
        
        /// <summary>
        /// Occurs when the color of the <see cref="ColorButton"/> is changed.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void selectionForeColorColorButton_ColorChanged(object sender, EventArgs e) {
            editor.RendererResolved.SelectionFocusedForeColor = selectionForeColorColorButton.Color;
            editor.Focus();
        }

        /// <summary>
        /// Occurs when the checked state is changed.
        /// </summary>
        /// <param name="sender">Sender of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void selectionSemiTransparentCheckBox_CheckedChanged(object sender, EventArgs e) {
            selectionBackColorColorButton_ColorChanged(sender, e);
        }
        
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // NON-PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        
        /// <summary>
        /// Adds a span indicator.
        /// </summary>
        /// <param name="layerKey">The key of the layer that will add the span indicator.</param>
        /// <param name="layerDisplayPriority">The display priority of the layer.</param>
        /// <param name="indicator">The <see cref="SpanIndicator"/> to add.</param>
        /// <param name="textRange">The text range over which to add the indicator.</param>
        private void AddSpanIndicator(string layerKey, int layerDisplayPriority, SpanIndicator indicator, TextRange textRange) {
            // Ensure there is a selection
            if (textRange.AbsoluteLength == 0 && indicator.Name != "Custom") {
                MessageBox.Show("Please make a selection first.");
                return;
            }

            // Ensure that a syntax error layer is created...
            SpanIndicatorLayer layer = editor.Document.SpanIndicatorLayers[layerKey];
            if (layer == null) {
                layer = new SpanIndicatorLayer(layerKey, layerDisplayPriority);
                editor.Document.SpanIndicatorLayers.Add(layer);
            }

            // Don't allow the indicator to overlap another one
            if (layer.OverlapsWith(textRange)) {
                MessageBox.Show("Span indicators within the same layer may not overlap.");
                return;
            }

            // Add the indicator
            layer.Add(indicator, textRange);
        }


    }

    /// <summary>
    /// Represents a custom span indicator.  You can use a custom span indicator to draw anything.
    /// </summary>
    public class CustomSpanIndicator : SpanIndicator {

        private Color    color;
        
        /// <summary>
        /// Initializes a new instance of the <c>CustomSpanIndicator</c> class.
        /// </summary>
        public CustomSpanIndicator() : this(Color.Red) {}
        
        /// <summary>
        /// Initializes a new instance of the <c>CustomSpanIndicator</c> class.
        /// </summary>
        /// <param name="color">The border color.</param>
        public CustomSpanIndicator(Color color) : base("Custom") {
            this.color = color;
        }
        
        /// <summary>
        /// Applies the adornments of the span indicator to the specified <see cref="HighlightingStyleResolver"/>.
        /// </summary>
        /// <param name="resolver">The <see cref="HighlightingStyleResolver"/> to modify.</param>
        protected override void ApplyHighlightingStyleAdornments(HighlightingStyleResolver resolver) {
            resolver.ApplyBorder(color, HighlightingStyleLineStyle.Dot, HighlightingStyleBorderCornerStyle.Square);
        }

        /// <summary>
        /// Applies the foreground and background colors of the span indicator to the specified <see cref="HighlightingStyleResolver"/>.
        /// </summary>
        /// <param name="resolver">The <see cref="HighlightingStyleResolver"/> to modify.</param>
        protected override void ApplyHighlightingStyleColors(HighlightingStyleResolver resolver) {
            resolver.SetBackColor(Color.FromArgb(200, Color.Thistle));
            resolver.SetForeColor(Color.DarkMagenta);
        }
        
        /// <summary>
        /// Applies the font changes of the span indicator to the specified <see cref="HighlightingStyleResolver"/>.
        /// </summary>
        /// <param name="resolver">The <see cref="HighlightingStyleResolver"/> to modify.</param>
        protected override void ApplyHighlightingStyleFont(HighlightingStyleResolver resolver) {
            resolver.SetFontFamilyName("Arial");
            resolver.SetFontSize(10f);
        }
        
        /// <summary>
        /// Draws the glyph associated with the indicator.
        /// </summary>
        /// <param name="e">A <see cref="PaintEventArgs"/> that contains the event data.</param>
        /// <param name="bounds">A <c>Rectangle</c> specifying the bounds in which to draw.</param>
        /// <remarks>
        /// This method should be implemented by indicators that have a glyph.
        /// Ensure that the indicator's <see cref="HasGlyph"/> property returns <c>true</c> if this method is implemented.
        /// </remarks>
        public override void DrawGlyph(PaintEventArgs e, Rectangle bounds) {
            bounds.Inflate(-1, -1);
            e.Graphics.FillEllipse(Brushes.Yellow, bounds);
            e.Graphics.DrawEllipse(Pens.Black, bounds);
            bounds.Inflate(-3, -3);
            e.Graphics.DrawArc(Pens.Black, bounds, 0f, 180f);
            bounds.Inflate(-2, -2);
            e.Graphics.DrawLine(Pens.Black, bounds.Left, bounds.Top, bounds.Left, bounds.Top + 1);
            e.Graphics.DrawLine(Pens.Black, bounds.Right, bounds.Top, bounds.Right, bounds.Top + 1);
        }
        
        /// <summary>
        /// Gets whether the span indicator contains a font-related change.
        /// </summary>
        /// <value>
        /// <c>true</c> if the span indicator contains a font-related change; otherwise, <c>false</c>.
        /// </value>
        /// <remarks>
        /// This property lets <see cref="SyntaxEditor"/> know whether display lines need to be recalculated
        /// when the span indicator is added.
        /// </remarks>
        public override bool HasFontChange { 
            get {
                return true;
            }
        }
        
        /// <summary>
        /// Gets whether the indicator has a glyph that appears in the indicator margin.
        /// </summary>
        /// <value>
        /// <c>true</c> if the indicator has a glyph that appears in the indicator margin; otherwise, <c>false</c>.
        /// </value>
        public override bool HasGlyph { 
            get {
                return true;
            }
        }


        protected override bool AllowZeroLength
        {
            get
            {
                return true;
            }
        }
    }

}


Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Nassim,

Thanks for the sample code. Right now, the glyph isn't rendering if the zero-length span indicator starts at the end of the line. We've fixed this for the next build.


Actipro Software Support

Posted 10 years ago by Nassim Farhat
Avatar
Is this fix complete? should i upgrade my version in order to obtain it (presently at 4.0.0276) and where may i do that?

Thank you
Nassim
Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
We haven't yet deployed the maintenance release. We are trying to get our Silverlight controls deployed first, then will do the WinForms controls maintenance release. Please note that in the forum you can see what the latest build is and when it was released.

After it is released you can get the latest from your Organization Purchases page.


Actipro Software Support

The latest build of this product (v2020.1 build 0400) was released 5 days ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.