如何获取 WinUI UWP TextBox 中的当前行索引?

How to get the Current Line Index in WinUI UWP TextBox?

我知道 SelectionStart 属性 的 WinUI UWP TextBox 将 return CaretIndex。但是,我想获得文本的确切列和行位置。在 WPF 中,GetLineFromCharacterIndex(CaretIndex)TextBox.Lines[LineIndex].Length 可用于查找当前 行索引 列数字 分别。我怎样才能在 WinUI UWP Textbox 中实现相同的目标?

也许你可以这样做:

var text = Textbox.Text;
var lines = text.Split('\r');
...

这在过去使用 WPF 对我有用,但我从未尝试过 UWP。

这似乎也是一种解决方法,因此可能会有更好、更实用的解决方案。

试试这个方法:

public static int GetCurrentLineIndex(TextBox textBox)
{
    int caretIndex = textBox.SelectionStart;
    if (caretIndex == 0)
        return 0;

    string[] lines = textBox.Text?.Split('\r') ?? Array.Empty<string>();
    int offset = 0;
    for (int i = 0; i < lines.Length; i++)
    {
        string line = lines[i];
        offset += line.Length;
        if (caretIndex <= offset)
            return i;
        offset++;
    }

    return 0;
}

它可能需要稍作改进,但它应该能让您了解如何确定光标的当前行。

你可以在任何你想获取索引的地方调用它,例如:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    int index = GetCurrentLineIndex(sender as TextBox);
    //...
}

此示例使用 MVVM 结构,但您可以将相同的概念应用于存储先前值的临时变量。

<TextBox Height="600" Width="600" 
         Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
         TextWrapping="Wrap" AcceptsReturn="True"/>

然后我将其添加到构造函数中:

this.DataContext = this;

这不是最佳实践,如果您使用的是 MVVM,您将设置一个 ViewModel 并使用它(我这样做是为了测试目的)。

然后我创建了这样的属性:

    private int _line;

public int Line
{
    get { return _line; }
    set
    {
        _line = value;
        tb1.Text = value.ToString();
    }
}

private int _column;

public int Column
{
    get { return _column; }
    set
    {
        _column = value;
        tb2.Text = value.ToString();
    }
}

private string _text;

public string Text
{
    get { return _text; }
    set
    {
        if (_text + '\r' != value)
        {
            Line = GetLine(_text, value);
            Column = GetColumn(_text, value, Line);
        }
        else
        {
            Line++;
            Column = 0;
        }

        _text = value;
    }
}

然后添加我的功能:

public int GetLine(string original, string newText)
{
    var oLines = GenArray(original);
    var nLines = GenArray(newText);

    //set this to -1 if you want 0-based indexing
    int count = 0;
    foreach (var line in nLines)
    {
        count++;
        if (oLines.Length < count || line != oLines[count - 1])
        {
            break;
        }
    }

    return count;
}

public int GetColumn(string original, string newText, int lineChanged)
{
    var oLine = GenArray(original)[lineChanged - 1];
    var nLine = GenArray(newText)[lineChanged - 1];

    //set this to -1 if you want 0-based indexing
    int count = 0;
    foreach (var c in nLine)
    {
        count++;
        if (oLine.Length < count || c != oLine[count - 1])
        {

        }
    }

    return count;
}

private string[] GenArray(string text)
{
    string[] lines;
    if (text == null)
    {
        lines = new string[1] { "" };
    }
    else if (text.Contains('\r'))
    {
        lines = text.Split('\r');
    }
    else
    {
        lines = new string[1] { text };
    }

    return lines;
}

如果您不使用 MVVM,只需执行此操作:

public string[] TempLines { get; set; }
...
//after the calculation code has finished
TempLines = TextBox.Split('\r');

然后你可以用 TempLines 代替 value