Hello, sorry, maybe I am too new to Telerik, but I was wondering how to do basic tasks with SyntaxEditor. I wanted to replace classic TextBox with SyntaxEditor and I thought it would be straightforward, but I got stuck on very basic tasks. Can you please help me, or navigate me?
1. How to get text from SyntaxEditor? I know how to set text by setting new document, but how to get text? I read whole SyntaxEditor part of documentation, but haven't found this, how is it possible? I was trying to find this out for about hour, but without success. I am wondering if am too new to Telerik or how it's possible I couldn't find this, I think this basic thing must be like "look and see".
2. Classic WinForms TextBox has Modified property indicating the text was changed. Is it also somewhere here? Also, TextBox has Lines property, is it somewhere here?
3. I tried the Cut/Copy/Paste commands, they are working, but I was wondering why CanExecute methods return always true. For example, I expect if there is no selection, CanExecute for Cut and Copy has to return false. Also, if there is no text in clipboard, Paste command has to return false, etc.
10 Answers, 1 is accepted
Hello, I have more questions. I'm trying to make Comment lines function, similar to VisualStudio. I will paste my code below questions.
1. How to position caret to the end of selection as in regular TextBox? If I programatically change selection, caret stays in original position, expected behavior is to change its position to selection end. I tried to call CaretPosition.MoveToPosition, but it resets selection.
2. How to scroll to caret position? Something like ScrollToCaret() in regular TextBox.
3. How to replace selected text? I did it somehow, but is there any better way? I have problem with that code related to next question. In regular TextBox, I can simply change selected text by txtSource.SelectedText = selText.
4. Why SyntaxEditor handles new lines as CR and not CRLF? We are on Windows, .NET, WinForms, I expected standard Windows new lines. I changed my CommentLines method to split lines by CR character only, but when I prepare new text by StringBuilder.AppendLine, it adds CRLF to string of course, and when I try to set new selection by new Span created by old selection start and my string length, it selects more characters (if I select 3 lines, it appends 3 more LFs and then string.Length is longer than real span in SyntaxEditor).
So, how to handle selection replacement correctly? This is my code:
var editor = radSyntaxEditor1.SyntaxEditorElement;
// if empty selection, set selection to caret position
if (editor.Selection.IsEmpty)
editor.Selection.Select(editor.CaretPosition, editor.CaretPosition);
// extend selection start
editor.Selection.StartPosition.MoveToLineStart();
// extend selection end - extend last line if empty or not on first char
if (editor.Selection.IsEmpty || editor.Selection.EndPosition.ColumnNumber != 0)
editor.Selection.EndPosition.MoveToLineEnd();
// extend to start of next line if not on last line
if (editor.Selection.EndPosition.LineNumber + 1 < editor.Document.CurrentSnapshot.LineCount)
{
editor.Selection.EndPosition.MoveLineDown();
editor.Selection.EndPosition.MoveToLineStart();
}
// set caret to selection end
//editor.CaretPosition.MoveToPosition(editor.Selection.EndPosition);
// comment lines
string selText = editor.Selection.GetSelectedText();
string commentedText = CommentLines(selText);
// if modified, replace selection
bool modified = selText != commentedText;
if (modified)
{
var span = editor.Selection.SelectedSpans.First();
editor.Document.Replace(span, commentedText);
editor.Selection.Select(new Span(span.Start, commentedText.Length));
}
radSyntaxEditor1.Refresh();
My colleague, Dinko, is out of office this today so I will be assisting you with this case.
1.The SyntaxEditorElement.CaretPosition offers a convenient API for moving the caret wherever you need through the document. However, indeed, moving the caret position is expected to clear the selection. That is why if you want to make a selection and place the caret at the end of the selection, you can execute the following steps:
- Select the desired text and store the start/end selection position
- Move the caret to the selection's end. As a result the selection will be cleared. However, you will have stored the start/end selection
- Select again the desired portion of the text.
The below code snippet shows what I mean which result is illustrated in the gif file:
private void radButton1_Click(object sender, EventArgs e)
{
var editor = radSyntaxEditor1.SyntaxEditorElement;
// if empty selection, set selection to caret position
if (editor.Selection.IsEmpty)
editor.Selection.Select(editor.CaretPosition, editor.CaretPosition);
// extend selection start
editor.Selection.StartPosition.MoveToLineStart();
// extend selection end - extend last line if empty or not on first char
if (editor.Selection.IsEmpty || editor.Selection.EndPosition.ColumnNumber != 0)
editor.Selection.EndPosition.MoveToLineEnd();
// extend to start of next line if not on last line
if (editor.Selection.EndPosition.LineNumber + 1 < editor.Document.CurrentSnapshot.LineCount)
{
editor.Selection.EndPosition.MoveLineDown();
editor.Selection.EndPosition.MoveToLineStart();
}
CaretPosition start =new CaretPosition( this.radSyntaxEditor1.SyntaxEditorElement.Selection.StartPosition);
CaretPosition end =new CaretPosition( this.radSyntaxEditor1.SyntaxEditorElement.Selection.EndPosition);
this.radSyntaxEditor1.SyntaxEditorElement.CaretPosition.MoveToPosition(this.radSyntaxEditor1.SyntaxEditorElement.Selection.EndPosition);
this.radSyntaxEditor1.SyntaxEditorElement.Selection.Select(start,end);
this.radSyntaxEditor1.Focus();
}
2. When the caret position is moved, RadSyntaxEditor automatically scrolls to the caret position. Hence, if you use the above approach from 1. the view will be scrolled to the desired location.
3. Using the selection, you can replace it with any text you need:
string selText = editor.Selection.GetSelectedText();
string commentedText = selText.ToUpper();
var span = editor.Selection.SelectedSpans.First();
editor.Document.Replace(span, commentedText);
editor.Selection.Select(new Span(span.Start, commentedText.Length));
4. I am not sure what is the exact implementation of the CommentLines method that you have. Could you please elaborate? I believe that the approach for replacing the selection in 3. would fit your requirements. Please give it a try and see whether you have any further questions regarding 4. In case you are still experiencing any further difficulties, it would be greatly appreciated if you can provide more details about the exact goal that you are trying to achieve. Thus, we would get better understanding of the precise case and provide further assistance.
I hope this information helps.
Regards,
Dess | Tech Support Engineer, Principal
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.
Hello, thanks for answers.
1. Ok, I can do it this way, it's not a problem. I asked only if there is a better solution. Because in regular TextBox setting selection also moves a caret, also if you select text by mouse it changes caret position.
2. Thanks, I haven't tried this.
3. Yes, I was just asking if there is better or more straightforward solution than this. Also my code was working after fixing CR/CRLF problem.
4. That was just question why you use only CR character for new line when we are on Windows, where CRLF is standard. I fixed it easily by replacing CRLF to CR before replacing back to SyntaxEditor. But personally I don't like converting CR/CRLF in each text interaction with SyntaxEditor. It's not a problem, but it doesn't look nice.
EDIT: Sorry, not CR only for new line, but LF only.
I am implementing "Comment lines" function as in VisualStudio, which comments or uncomments all selected lines:
CommentLines method just splits text to lines, adding // to each non-empty line. I fixed the problem by replacing CRLF to CR at the end of method. After this walkaround selecting new text works ok - editor.Selection.Select(new Span(span.Start, commentedText.Length)). Before, the problem was that commentedText.Length was longer than real text in SyntaxEditor, because SyntaxEditor discards LF character in CRLF.
private string CommentLines(string text)
{
string[] lines = text.Split(new string[] { "\n" }, StringSplitOptions.None);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i];
if (line.Trim().Length > 0)
{
sb.Append("//");
sb.Append(line);
}
if (i < lines.Length - 1)
sb.AppendLine();
}
sb.Replace("\r\n", "\r");
return sb.ToString();
}
And, now I have a working sample and I think I have all to upgrade my editor to SyntaxEditor.
Hello, I have found next few issues.
1. When zooming, something strange happens with row numbers and its margins, see animation:
2. When user make doubleclick, expected behavior is to select whole word behing cursor as in regular TextBox. Is this missing in SyntaxEditor?
3. Scrolling by mouse wheel, it scrolls too many lines per mouse wheel step. I have found solution here in forum, but it was on other hand too few, so I multiplied that step by 3. But the best would be if you can modify SyntaxEditor to either make it settable or change it to standard way (3 lines per mouse wheel step). Also that small step doesn't seem to be exactly one line, is it related to changed font size?
4. Replace all function replaces it in whole file, not just in selection.
Hello Marian,
Let me go straight to your questions.
1. I have tested this behavior but wasn't able to reproduce it on my side. I have used the First Look example in our demos. May I ask you to share if you have specified different font for the RadSyntaxEditor? If yes, which one? If not, could it be possible to share a sample project which demonstrates this so that I can debug this on my side?
2. By default when a user double-clicked a word, it will be selected and other equal words will be marked with a border. This is also not reproducible on my end. You can include this in the sample project.
3. You are in the right direction with the mentioned link. The control does not provide out of the box way to manipulate the scroll step. You can use the approach suggested in the forum. The font size will reflect the custom value used for the step. You will need to create additional calculations to scroll 3 rows regardless of the zoom/font size.
4. This is not supported by RadSyntaxEditor, so I have logged a Feature Request in our Feedback Portal to implement such improvement. I have updated your Telerik Points for bringing this to our attention.
Regards,
Dinko
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.
Hello, I have attached my program.
1. I have custom font, maybe it will be related to this.
2. I couldn't reproduce it too, so sorry, maybe it were not correct doubleclicks, or, I don't know. I tried it in test program and editor, and it works normally, so I don't know what was the problem.
3. Ok. So, that small scrollbar step is one row of standard font, and if I have custom font size, should I calculate also ratio between my font and standard? Btw. what units does SyntaxEditorElement.EditorFontSize use? I expected standard font size in points as in standard WinForms controls.
4. Thanks.
I will repeat question from comments - regular TextBox has CanUndo property, which indicates Undo command is possible and I have used that property for enabling Undo button on toolbar. Is it also somewhere here?
As I wrote in last comment, I successfully migrated my editor to SyntaxEditor, and now it looks much better with coloring, folding, completions etc.
Hi Marian,
Thank you for the provided project. I have tested it on my side but could not observe this behavior. I haven't made any changes to the project except for changing the target framework to 4.8. Here is the result on my side. Can you share which version of our controls are you using?
The EditorFontSize is set to a custom element RadTextBlock create for the purpose of the control. In your case, the logic for the custom scroll needs to consider the zoom and the fontsize. When the control is zoomed the elements inside are scaled. You can control this by using the ScaleFactor property. Keep in mind that zooming will not change the fontsize.
As for your last question. The Document.History objects expose such property which I think will work for you. Check the following code snippet which demonstrates how to access it.
radSyntaxEditor1.SyntaxEditorElement.Document.History.CanUndo
Regards,
Dinko
Progress Telerik
Coming to you live from Progress360 in-person or on your own time, DevReach for all. Register Today.
Hello Dinko,
I use 2022.6.622.40 version. I tried it also in .NET 4.8, behavior is the same. I am sending that project once again, but also with binaries. I compressed it with rar with solid archive option and deleted some unnecessary files from lib directory.
Custom scrolling, I finally solved it. Zoom factor has no effect to scrolling, but line spacing is important. I don't know if it's adjustable, so maybe this code with constants (13 for default font size and 3 for line spacing) isn't generally correct, but it works for my project. Following code is working:
protected override void OnMouseWheel(MouseEventArgs e)
{
System.Reflection.PropertyInfo pi = typeof(SyntaxEditorPresenter).GetProperty("VerticalScrollOffset", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
int defaultFontSize = 13;
int delta = (int)(3 * (EditorFontSize + 3.0) / (defaultFontSize + 3.0) * this.SyntaxEditorElement.VerticalScrollBar.SmallChange);
if (e.Delta < 0)
{
this.SyntaxEditorElement.VerticalScrollBar.Value += delta;
pi.SetValue(this.SyntaxEditorElement.EditorPresenter, this.SyntaxEditorElement.VerticalScrollBar.Value);
}
else
{
this.SyntaxEditorElement.VerticalScrollBar.Value -= delta;
pi.SetValue(this.SyntaxEditorElement.EditorPresenter, this.SyntaxEditorElement.VerticalScrollBar.Value);
}
this.SyntaxEditorElement.EditorPresenter.InvalidateLayout(false);
// base.OnMouseWheel(e);
}
Hello Marian,
I am happy to hear that you were able to create the algorithm for the custom scrolling and thank you for sharing the solution. This way the community can take advantage of it.
As for the zoom behavior. We don't make any progress here. I still wasn't able to reproduce it. If the same project demonstrates is working at your end and not on mine, this leads me to think that we need to focus on the DPI. Can you share the scaling and the resolution of the monitors which you are using? Just for the test can you run the SyntaxEditor First Look demo inside our Telerik UI for WinForms Demo application to check if this behavior is related to the project or if it is global for your machine.
Regards,
Dinko
Progress Telerik
Coming to you live from Progress360 in-person or on your own time, DevReach for all. Register Today.
Hello,
yes. But the best would be, if you can change scroll behavior to this standard behavior in some newer version. This solution works, but it's very dependent on current implementation, if you will change line spacing, make it customizable etc, this will not work correctly anymore.
Zoom... Behavior is the same also in your demo.
I have 1920x1200 resolution with standard DPI, standard fonts, I haven't change anything to something special. I think it was the same also on the production machine, but I am not sure. This is not so problem for me, I think that zoom will be not used often, but if you want to test something, I can do it for solving this problem generally.
Hi Marian,
Thank you for the details.
We are making some progress here. So far we can confirm that it is not related to the custom project. This visual behavior could come from the set-up of the OS. Can you share which windows version is installed on your machine? Also, you can share the culture configuration set on your machine.
Regards,
Dinko
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.
Hello, I have Win10, 21H2, build 19044.1766, english language, Slovak region settings.
Hi, Marian,
My colleague, Dinko, is out of office this week so I will be assisting with this case.
I have the same OS version locally:
I have also changed the regional settings as yours. However, I am still unable to replicate the issue on our side. Please refer to the attached gif file. Would it be possible for you to test the behavior on another machine and check whether it is a device specific issue?
Now I have figured out the first question, it's accessible through radSyntaxEditor1.Document.CurrentSnapshot.GetText(), or lines are accessible through radSyntaxEditor1.Document.CurrentSnapshot.Lines[]. I tried to google it without winforms keyword and has found it in similar question to WPF version of SyntaxEditor.
And, if my questions would seem little bit upset, I'm sorry, I think when I will manage upgrade to SyntaxEditor, I think it will be great enhancement of our editor, it's great control. I started with playing with coloring, folding, completions etc, I was excited about the features I can use, and after two days of playing with control got to implementation and I was surprised I couldn't find it.
Thank you for your kind words. We appreciate it. Regarding your questions, I will do my best to help you to migrate your TextBox controls to RadSyntaxEditor. I see that you have found the GetText() method to get the content of the control. You can check the lines from the radSyntaxEditor1.Document.CurrentSnapshot.Lines as you have already found. Now the control does not expose such Modified property. However, you could subscribe to the DocumentContentChanged event and raise a flag when it is called. This event will be called when the application starts and after the user has changed the content of the control.
As for the commands, the CanExecute by default returns true. No logic checks whether the text is selected or the clipboard contains a text. You can cancel the commands in the mySyntaxEditor.SyntaxEditorElement.CommandExecuting event handler.
If you have any other questions feel free to ask.
Ok, so I have to do Modified flag myself, it's not problem. Also it's no problem to do logic for checking if text is selected, clipboard contains text etc, but if CanExecute simply returns true, what's the meaning of this method? I thought I will just use CanExecute to enable / disable toolbar buttons. Of course, I can simply do it myself.
I have used more properties / methods of TextBox in this editor, like SelectionStart, End, GetLineFromCharIndex, ScrollToCaret, for example for expanding selection to whole lines and commenting/uncommenting lines, but I have found some similar methods of selections and caret positions in SyntaxEditor, so I think I will solve it after some time of playing. I was trying some tests and this tasks seems to be easier in SyntaxEditor, so maybe my methods for this will be simplified.
If I will have more questions, I will ask later.
The CanExecute method comes from the SyntaxEditorCommandBase abstract class which the commands of the RadSyntaxEditor derive from. This is an inherited property and that is why is visible in the mentioned commands. It was created for internal use. While developing the control it was decided to create a global event that will catch all commands before executing. This way you won't need to subscribe to each command. As mentioned above, you can cancel a command in the mySyntaxEditor.SyntaxEditorElement.CommandExecuting event handler.