【问题标题】:How to get the Current Line Index in WinUI UWP TextBox?如何在 WinUI UWP TextBox 中获取当前行索引?
【发布时间】:2021-10-13 18:06:28
【问题描述】:

我知道 WinUI UWP TextBoxSelectionStart 属性将返回 CaretIndex。但是,我想获得文本的确切列和行位置。在 WPF 中,GetLineFromCharacterIndex(CaretIndex)TextBox.Lines[LineIndex].Length 可分别用于查找当前 行索引列号。我怎样才能在 WinUI UWP Textbox 中达到同样的效果?

【问题讨论】:

    标签: c# .net uwp uwp-xaml winui-3


    【解决方案1】:

    试试这个方法:

    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);
        //...
    }
    

    【讨论】:

    • 谢谢。我试试看
    • 非常感谢!这个解决方案效果很好!
    • 我得到了currentLine的长度来得到CurrentColumnIndex。当在 TextBox 内按下 Enter/Space/BackSpace 时,它​​就像一个魅力。但是当按下箭头键时,行和列都不会更新。自 CaretIndex=SelectionStart 以来,我尝试处理 TextBox.Selection_Changed 事件。但是,当使用箭头键移动光标时,lineIndex 和 columnIndex 仍然没有更新。你能分享一些解决这个问题的方法吗?
    • 你能提供解决上述问题的方法吗?
    • @Kris:如果您还有其他问题,请提出新问题。请在发帖时附上minimal reproducible sample
    【解决方案2】:

    也许你可以这样做:

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

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

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

    【讨论】:

    • 您好,感谢您的建议。我已经在 UWP 中尝试过。由于某些未知原因,它无法正常工作:-(
    • 如果将变量设置为 Textbox.Text,则可以添加断点或监视并查看输出是什么(包括 \n 之类的字符),这样您就可以看到分隔行的内容,它可能是\r。
    • 我已经尝试过了,'\r' 成功了,我会编辑我的答案
    • Np,您可以将此答案设置为正确,以便其他人知道这是有效的
    • 只需使用 TextChanged 事件处理程序并查看新文本以查看更改的内容。如果您使用的是 MVVM,只需将该值与 setter 中的私有属性进行比较。
    【解决方案3】:

    此示例使用 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 代替值

    【讨论】:

    • 我正在使用 MVVM。我有多个文本框附加到 TabView 的 TabViewItems。我会尝试您的解决方案。感谢您的帮助:-)
    • 非常感谢!这个解决方案也有效!
    猜你喜欢
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 2019-07-07
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    • 2018-08-13
    • 2018-11-16
    相关资源
    最近更新 更多