Get Character Text Change - c#

How do I get the character before the position in RichEditControl
for example, A is before the caret, the return string should be A
and in text change I need to get the caret position

You can use the RichEditControl1.Document.CaretPosition property to get the current position then just use string.Substring(0, position.ToInt()) to get the string before the current position of the caret.
check the code snippet below:
private void simpleButton1_Click(object sender, EventArgs e)
{
DevExpress.XtraRichEdit.API.Native.DocumentPosition position = richEditControl1.Document.CaretPosition;
if (richEditControl1.Document.Text.Length > 0)
{
//Returns all previous text befor the caret
XtraMessageBox.Show(richEditControl1.Document.Text.Substring(0, position.ToInt()));
int intPosition = position.ToInt();
if (intPosition > 0 && intPosition < richEditControl1.Document.Length)
{
//It will return previous character
XtraMessageBox.Show(richEditControl1.Document.Text.Substring(intPosition - 1, 1));
}
}
}
References:
How to get RepositoryItemRichEdit caret position
How to get/set the caret position within the editor?
Hope this help.

Related

c# Xamarin UITextField setting the cursor position

I need to position the cursor of a UITextField in the exact same position as another previous text field. I get the position of the cursor in the first text field as nint index = txtToField.GetOffsetFromPosition(txtToField.BeginningOfDocument, txtToField.SelectedTextRange.Start);, which correctly gets the number of characters from the beginning of the textfield my cursor is currently in. After some research, and using the question below:
Setting cursor position of UITextField
I have tried to implement the question's solution to setting the cursor position in a textfield, using the index I previously got. This doesn't work, and after making the text field the first responder and running:
txtTo.BecomeFirstResponder();
UITextPosition positionSet = txtTo.GetPosition(txtTo.BeginningOfDocument, position);
txtTo.SelectedTextRange = txtTo.GetTextRange(positionSet, positionSet);
It automatically puts your cursor at the end of the UITextField. Further, I attempted to check if the SelectedTextRange method worked as expected, however when trying to set all of the text in the text field as selected:
txtTo.BecomeFirstResponder();
txtTo.SelectedTextRange = txtTo.GetTextRange(txtTo.BeginningOfDocument, txtTo.EndOfDocument);
It also automatically puts the cursor to the end of the UITextField, which is a standard behaviour for BecomeFirstResponder(). Does SelectedTextRange not work in this current version of Xamarin?
I am using version 7.6.10 (build 27) of Xamarin and Xamarin.iOS version 12.0.0.15.
Cause:
The cursor is at the end of the text in dafault.When you init a UITextField and set it as FirstResponder in the method ViewDidLoad.The view is still not finish init.
Solution:
You can call these method in the method EditingStarted .And don't forget set the delegate.
public partial clas xxxViewController:UIViewController,IUITextFieldDelegate
txtTo.WeakDelegate=this;
[Export("textFieldDidBeginEditing:")]
public void EditingStarted(UITextField textField)
{
NSRange range = new NSRange(index, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, range.Location);
UITextPosition end = textField.GetPosition(start, range.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
}
If you do want to call them in ViewDidLoad .You can set a delay (for example 0.1s).
//...
this.PerformSelector(new Selector("MoveCursorPosition:"),txtTo,0.1);
//...
[Export("MoveCursorPosition:")]
public void MoveCursorPosition(UITextField textField)
{
NSRange range = new NSRange(index, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, range.Location);
UITextPosition end = textField.GetPosition(start, range.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
}

Zoom/unzoom and points decimation

Situation:
I have one Chart and three ChartArea that are aligned in view, zoom, cursor through the AxisViewChanged method that act in this way:
if (e.Axis == ax1)
{
ax2.ScaleView.Size = ax1.ScaleView.Size;
ax2.ScaleView.Position = ax1.ScaleView.Position;
ax3.ScaleView.Size = ax1.ScaleView.Size;
ax3.ScaleView.Position = ax1.ScaleView.Position;
min = (int)ax1.ScaleView.ViewMinimum;
max = (int)ax1.ScaleView.ViewMaximum;
}
if (e.Axis == ax2)
{
....
And it works very well in both cases: when I zoom in/out or scroll.
Problem:
The problem is that my graph source is made by a lot of points, in the worst case we talk about 3'600'000 samples. With this amount of samples, when I move around points with cursor and try to show a tooltip with the values, the interaction quality collapse and becomes unusables (even having set Fast Line).
So I tried to implement a simple decimation algorithm to reducethe number of showed points:
void draw_graph(int start, int end)
{
double fract_value = 0;
int int_value = 0;
int num_saples_selected = end - start;
if(num_saples_selected <= MAX_GRAPH_NUM_SAMPLES)
fill_graphs_point(0, end, 1);
else
{
fract_value = ((double)num_saples_selected) / ((double)MAX_GRAPH_NUM_SAMPLES);
int_value = (int)fract_value;
if (fract_value > int_value)
int_value++;
fill_graphs_point(0, end, int_value);
}
}
void fill_graphs_point(int start, int end, int step)
{
int i = 0;
for (i = start; i < end; i=i+step)
{
dlChart.Series[SERIES_VOLTAGE].Points.AddXY(timestamps_array[i], voltage_array[i]);
dlChart.Series[SERIES_CURRENT].Points.AddXY(timestamps_array[i], current_array[i]);
dlChart.Series[SERIES_ENERGY].Points.AddXY(timestamps_array[i], energy_array[i]);
// I will use this to came back to real position of the initial array
decimation_positions.Add(i);
}
}
Assuminig I had a good idea with this method to reduce the points number, I do not know where to put the call to the function "draw_graph". If I put it in the AxisViewChanged method it will call my method also when I scroll (horizontally) my graph and this is not what I want. I want to call my method only on zoom and unzoom event.
Expected behavior: in the first view (without any zoom) the graph has to show an "idea" of the trend of the graph. Then for every selection/(un)zoom I want to call my function to check if the points number of selected portion will fit in my window size that is MAX_GRAPH_NUM_SAMPLES(=10000).
Hope someone can help me. Whatever kind of suggestion will be appreciated. Thanks in advance.
I forgot to say that strangely the problem appeared when I zoomed in more than one time. At some point also the PC fan started. I resolved disabling the library zoom and implement my self a sort of zoom (a little bit more simple). The solution is in this method and the method I write in the question:
private void dlChart_SelectionRangeChange(object sender, CursorEventArgs e)
{
double startSelection = e.NewSelectionStart;
double endSelection = e.NewSelectionEnd;
// Allow the selection to disappear
reset_selection();
try
{
// before convert point from "showed point" to "real point" I check the limits
if (
(startSelection >= 0) && (startSelection <= decimation_positions.Count()) &&
(endSelection >= 0) && (endSelection <= decimation_positions.Count()) &&
(endSelection != startSelection)
)
{
// convert
startSelection = decimation_positions[(int)startSelection];
endSelection = decimation_positions[(int)endSelection];
// check for reverse zoom (from right to left)
if (startSelection > endSelection)
{
double tmp = startSelection;
startSelection = endSelection;
endSelection = tmp;
}
// clean the series
this.reset_series();
// draw the selected range
draw_graph((int)startSelection, (int)endSelection);
}
}catch(ArgumentOutOfRangeException ex)
{
// todo
}
//System.Console.WriteLine("SelSTART = "+e.NewSelectionStart+" SelEND = "+e.NewSelectionEnd);
}

RichTextBox formatting and restoring cursor and scrollbar position

I have RichTextBox in which I format text, I have there multiple text selections and formats.
Because of that, after the formatting is done, the scrollbars positions of RichTextBox isn't the same.
How am I able to save and restore scrollbar position same (easy) way as I can save cursor position?
protected override void OnTextChanged(EventArgs e)
{
// Save cursor position
int cursor_position = this.SelectionStart;
// Format text
Highlight();
// Restore position
this.SelectionLength = 0;
this.SelectionStart = cursor_position;
}
I have seen many posts here that were solving this by handling scroll messages.
I have managed this simplier way, so if anyone have the same problem, you can use this way. It is not perfect (if there is a half of line displayed at the top, it will be scrolled), but is enough I think :).
protected override void OnTextChanged(EventArgs e)
{
// Get first and last displayed character
int start = this.GetCharIndexFromPosition(new Point(0, 0));
int end = this.GetCharIndexFromPosition(new Point(this.ClientSize.Width, this.ClientSize.Height));
// Save cursor position
int cursor_position = this.SelectionStart;
int cursor_lenght = this.SelectionLength;
// Your formatting
Highlight();
// Scroll to the last character and then to the first + line width
this.SelectionLength = 0;
this.SelectionStart = end;
this.ScrollToCaret();
this.SelectionStart = start + this.Lines[this.GetLineFromCharIndex(start)].Length+1;
this.ScrollToCaret();
// Finally, set cursor to original position
this.SelectionStart = cursor_position;
}

TextBox.Text Doesn't Right Justify

According to my understanding, the code below should right-justify the text if the text is longer than the textbox can show, otherwise it keeps it left-justified.
The problem is that it doesn't actually do this and it's acting really odd. Short strings end up right-justified sometimes and long strings are always left-justified.
What am I doing wrong?
private void textBoxCurrentConfig_TextChanged(object sender, EventArgs e)
{
SizeF stringSize = new SizeF();
stringSize = TextRenderer.MeasureText(textBoxCurrentConfig.Text, textBoxCurrentConfig.Font);
float currentTextWidth = stringSize.Width;
float allowedTextWidth = textBoxCurrentConfig.Size.Width - 10;
if (currentTextWidth >= allowedTextWidth) // if the text we want to display is larger than the textbox can hold, right justify it to show the filename
{
textBoxCurrentConfig.TextAlign = HorizontalAlignment.Right; // right justify
}
else // otherwise we can display the entire path
{
textBoxCurrentConfig.TextAlign = HorizontalAlignment.Left; // left justify
}
textBoxCurrentConfig.Refresh();
this.Refresh();
}
As from your comments, you want to move cursor position according to the text length. You can use TextBox.Select() method for this. Check MSDN for details.
So if you want to move cursor at the the start of text, you can use
textBoxCurrentConfig.Select(0, 0);
and if you want to move cursor at the end of text, you can use
textBoxCurrentConfig.Select(textBoxCurrentConfig.Text.Length, 0);
Try to remove
this.Refresh();
It's may cause the page to refresh and return the text box to the original align

Custom links in RichTextBox

Suppose I want every word starting with a # to generate an event on double click. For this I have implemented the following test code:
private bool IsChannel(Point position, out int start, out int end)
{
if (richTextBox1.Text.Length == 0)
{
start = end = -1;
return false;
}
int index = richTextBox1.GetCharIndexFromPosition(position);
int stop = index;
while (index >= 0 && richTextBox1.Text[index] != '#')
{
if (richTextBox1.Text[index] == ' ')
{
break;
}
--index;
}
if (index < 0 || richTextBox1.Text[index] != '#')
{
start = end = -1;
return false;
}
while (stop < richTextBox1.Text.Length && richTextBox1.Text[stop] != ' ')
{
++stop;
}
--stop;
start = index;
end = stop;
return true;
}
private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
{
textBox1.Text = richTextBox1.GetCharIndexFromPosition(new Point(e.X, e.Y)).ToString();
int d1, d2;
if (IsChannel(new Point(e.X, e.Y), out d1, out d2) == true)
{
if (richTextBox1.Cursor != Cursors.Hand)
{
richTextBox1.Cursor = Cursors.Hand;
}
}
else
{
richTextBox1.Cursor = Cursors.Arrow;
}
}
This handles detecting words that start with # and making the mouse cursor a hand when it hovers over them. However, I have the following two problems:
If I try to implement a double click event for richTextBox1, I can detect when a word is clicked, however that word is highlighted (selected), which I'd like to avoid. I can deselect it programmatically by selecting the end of the text, but that causes a flicker, which I would like to avoid. What ways are there to do this?
The GetCharIndexFromPosition method returns the index of the character that is closest to the cursor. This means that if the only thing my RichTextBox contains is a word starting with a # then the cursor will be a hand no matter where on the rich text control it is. How can I make it so that it is only a hand when it hovers over an actual word or character that is part of a word I'm interested in? The implemented URL detection also partially suffers from this problem. If I enable detection of URLs and only write www.test.com in the rich text editor, the cursor will be a hand as long as it is on or below the link. It will not be a hand if it's to the right of the link however. I'm fine even with this functionality if making the cursor a hand if and only if it's on the text proves to be too difficult.
I'm guessing I'll have to resort to some sort of Windows API calls, but I don't really know where to start.
I am using Visual Studio 2008 and I would like to implement this myself.
Update:
The flickering problem would be solved if I could make it so that no text is selectable through double clicking, only through dragging the mouse cursor and programmatically. Is this easier to achieve? Because I don't really care if one can select text or not by double clicking in this case.
On point (2) you could try:
After if (richTextBox1.Text.Length == 0){ ... }
//get the mouse point in client coordinates
Point clientPoint = richTextBox1.PointToClient(richTextBox1.PointToScreen(position));
int index = richTextBox1.GetCharIndexFromPosition(position);
//get the position of the closest char
Point charPoint = richTextBox1.GetPositionFromCharIndex(index);
bool notOnTheSameLine = ((clientPoint.Y < charPoint.Y) || (clientPoint.Y > charPoint.Y + richTextBox1.Font.Height));
bool passedTheWord = (clientPoint.X > charPoint.X + richTextBox1.Font.SizeInPoints);
if (notOnTheSameLine || passedTheWord)
{
start = end = -1;
return false;
}
For point (1) maybe have a different way of following the link than dbl-click? Maybe cntl-click would avoid the issues of the word becoming selected...

Categories