I've been searching and the solutions here work for getting the row and column position of the cursor in a WPF text box until the row number is greater than 16,311. After that, the column is a negative value.
private void SetTextFileCursorPosition()
{
var caretIndex = TextFile.CaretIndex;
var row = TextFile.GetLineIndexFromCharacterIndex(caretIndex);
var col = caretIndex - TextFile.GetCharacterIndexFromLineIndex(row);
CursorPosition = $"{col + 1}, {row + 1}";
}
Very strange behavior. Even pouring through the .NET source code, I couldn't quite figure out exactly why this was happening. I've spent some time writing up my research and have submitted it as a bug in the .NET framework.
Here is the link to the bug report: System.Windows.Controls.TextBox.GetCharacterIndexFromLineIndex returns increasingly incorrect values for larger line numbers
But I'll include a summary of what I found:
My experience was a little different than yours. In my tests, everything works fine until I get to line 8,512. Starting at that line GetCharacterIndexFromLineIndex
seems to start returning the starting index of the next line, instead of the one being requested. Meaning, instead of giving me the start of 8,512, it was giving me the start of 8,513.
Testing with larger numbers of lines, I found that at line 25,536, GetCharacterIndexFromLineIndex
starts skipping two lines, instead returning the start of line 25,538. The number of line skips increases to 3 at line 42,560 and then to 4 at line 59,584.
This reveals a pattern: every 17,024 lines, the number of skipped lines increases by 1. The pattern starts at line 8,512, because it is 17,024 / 2 (half).
I can't explain why this happens exaclty, but the above provides some good documentation on the behavior. And below, I've put together some code to work around the problem.
You can work around this to a drgree:
var caretIndex = TextFile.CaretIndex;
var line = TextFile.GetLineIndexFromCharacterIndex(caretIndex);
var colStart = TextFile.GetCharacterIndexFromLineIndex(line);
var pos = caretIndex - colStart;
int posAdj = pos;
int lineAdj = line;
while (posAdj < 0)
{
posAdj = TextFile.GetLineLength(lineAdj) + posAdj;
lineAdj--;
}
CursorPosition = $"{posAdj + 1}, {line + 1}"; //NOT lineAdj
The above adds on the length of previous lines until it reaches a positive value, effectively adding in the skipped lines. This should work no matter how long the text is, and should even keep working after they (hopefully) patch the bug (since then pos
should never be < 0
).