Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多行WPF文本框中的键盘插入符号导航_C#_Wpf - Fatal编程技术网

C# 多行WPF文本框中的键盘插入符号导航

C# 多行WPF文本框中的键盘插入符号导航,c#,wpf,C#,Wpf,我有一个使用多行文本框作为数据模板的列表视图 默认情况下,在多行文本框中,启用上下箭头导航。如果您的文本框有两行,则插入符号位于第一行,您按下向下箭头,它会将插入符号置于第二行相同的相对位置 我还在ListView中的文本框之间添加了光标导航。如果您位于文本框的第一行并按向上箭头,则会将焦点设置为ListView中的上一个文本框。类似地,如果您在最后一行并按下,它将转到下一个文本框。但是因为这必须手动完成,所以我必须编写自己的逻辑来维护相对位置。但它很复杂,也有一些问题 private void

我有一个使用多行文本框作为数据模板的列表视图

默认情况下,在多行文本框中,启用上下箭头导航。如果您的文本框有两行,则插入符号位于第一行,您按下向下箭头,它会将插入符号置于第二行相同的相对位置

我还在ListView中的文本框之间添加了光标导航。如果您位于文本框的第一行并按向上箭头,则会将焦点设置为ListView中的上一个文本框。类似地,如果您在最后一行并按下,它将转到下一个文本框。但是因为这必须手动完成,所以我必须编写自己的逻辑来维护相对位置。但它很复杂,也有一些问题

private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    var tb = (sender as TextBox);
    var textBeforeCursor = tb.Text.Substring(0, tb.SelectionStart);
    var textAfterCursor = tb.Text.Substring(tb.SelectionStart);

    if (e.Key == Key.Up && !textBeforeCursor.Contains("\r\n"))
    {
        var caretIndex = GetTextBoxCaretIndex();
        listView.SelectedIndex--;

        var lastLineRegex = new Regex("(.*)(\r\n.*$)", RegexOptions.Singleline);
        var previousString = listView.SelectedItem as string;
        var lines = lastLineRegex.Match(previousString);
        var offset = lines.Groups[1].Length;

        FocusTextBox(caretIndex + offset + 2);
    }
    if (e.Key == Key.Down && !textAfterCursor.Contains("\r\n"))
    {
        var caretIndex = GetTextBoxCaretIndex();
        var lastLineRegex = new Regex("(.*)(\r\n.*$)", RegexOptions.Singleline);
        var previousString = listView.SelectedItem as string;
        var lines = lastLineRegex.Match(previousString);
        var offset = lines.Groups[1].Length;
        listView.SelectedIndex++;

        Console.WriteLine($"CaretIndex: {caretIndex}, Offset: {offset}");
        FocusTextBox(caretIndex - offset - 2);
    }
}

private int GetTextBoxCaretIndex()
{
    var item = listView.ItemContainerGenerator.ContainerFromItem(listView.SelectedItem) as ListViewItem;
    var textBox = GetVisualChildOfType<TextBox>(item);
    return textBox.CaretIndex;
}
private void FocusTextBox(int caretIndex = 0)
{
    var item = listView.ItemContainerGenerator.ContainerFromItem(listView.SelectedItem) as ListViewItem;
    var textBox = GetVisualChildOfType<TextBox>(item);

    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
    {
        textBox.CaretIndex = Math.Min(caretIndex, textBox.Text.Length);
        textBox.SelectionStart = textBox.CaretIndex;
        textBox.Focus();
    }));
}
private void TextBox\u PreviewKeyDown(对象发送方,KeyEventArgs e)
{
var tb=(发送方作为文本框);
var textBeforeCursor=tb.Text.Substring(0,tb.SelectionStart);
var Text aftercursor=tb.Text.Substring(tb.SelectionStart);
如果(e.Key==Key.Up&!textforecursor.Contains(“\r\n”))
{
var caretIndex=GetTextBoxCaretIndex();
listView.SelectedIndex--;
var lastLineRegex=new Regex((.*)(\r\n.*)”,RegexOptions.Singleline);
var previousString=listView.SelectedItem作为字符串;
var lines=lastLineRegex.Match(previousString);
变量偏移量=行。组[1]。长度;
FocusTextBox(caretIndex+偏移量+2);
}
如果(e.Key==Key.Down&!textAfterCursor.Contains(“\r\n”))
{
var caretIndex=GetTextBoxCaretIndex();
var lastLineRegex=new Regex((.*)(\r\n.*)”,RegexOptions.Singleline);
var previousString=listView.SelectedItem作为字符串;
var lines=lastLineRegex.Match(previousString);
变量偏移量=行。组[1]。长度;
listView.SelectedIndex++;
WriteLine($“CaretIndex:{CaretIndex},Offset:{Offset}”);
FocusTextBox(caretIndex-偏移量-2);
}
}
private int GetTextBoxCaretIndex()
{
var item=listView.ItemContainerGenerator.ContainerFromItem(listView.SelectedItem)作为ListViewItem;
var textBox=GetVisualChildOfType(项目);
返回textBox.CaretIndex;
}
专用void FocusTextBox(int-caretIndex=0)
{
var item=listView.ItemContainerGenerator.ContainerFromItem(listView.SelectedItem)作为ListViewItem;
var textBox=GetVisualChildOfType(项目);
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,新操作(()=>
{
textBox.CaretIndex=Math.Min(CaretIndex,textBox.Text.Length);
textBox.SelectionStart=textBox.CaretIndex;
textBox.Focus();
}));
}
这种逻辑可以正常工作,但在某些情况下会中断行之间的默认插入符号导航

插入符号位于顶部文本框的底部,超过8个字符。我按下,它进入第二个文本框,插入符号在第一行,超过8个字符;预期的行为

然后我再次按下,它进入第二行,但在第一个字符,而不是第八个字符。我的代码在这种情况下不执行,所以默认逻辑出现了一些异常情况

我甚至不知道从哪里开始。通过测试,似乎文本框在每行上都有一些关于插入符号位置的内部状态,但是通过查看文本框文档,我没有看到任何与此相关的属性

您可以查看简化的示例项目和演示该问题的完整代码


任何有关默认插入符号导航工作方式的帮助或信息都会有所帮助。谢谢你的时间。

我能看出你的沮丧。当我试着这样做时,我发现插入符号有一些奇怪的行为。当您编辑插入符号位置时,默认行为似乎被删除(为什么会转到行的开头)。所以我假设你必须控制插入符号的位置。因此,我在您的
Key\u Up
Key\u Down
检查中添加了
else
子句。我重复了您的逻辑,但使插入符号位置在文本框中显式控制

     //...if (e.Key == Key.Up && !textBeforeCursor.Contains("\r\n")){...}
     else if (e.Key == Key.Up)
     {
        var caretIndex = GetTextBoxCaretIndex();

        var lastLineRegex = new Regex("(.*)(\r\n.*$)", RegexOptions.Singleline);
        var previousString = listView.SelectedItem as string;
        var lines = lastLineRegex.Match(previousString);
        var offset = lines.Groups[1].Length;

        FocusTextBox(caretIndex - offset - 2);
     }
    //...if (e.Key == Key.Down && !textAfterCursor.Contains("\r\n")){...}
    else if(e.Key ==  Key.Down)
    {
        var caretIndex = GetTextBoxCaretIndex();
        var lastLineRegex = new Regex("(.*)(\r\n.*$)", RegexOptions.Singleline);
        var previousString = listView.SelectedItem as string;
        var lines = lastLineRegex.Match(previousString);
        var offset = lines.Groups[1].Length;
        FocusTextBox(caretIndex + offset + 2);
    }

代码绝对可以被清除。我保持原样,因为它允许在每个阶段进行调试。因此,我将让您自行决定如何进行重构。您还必须在
previousString
上添加
null
检查

解决方案最终是在所有情况下手动控制光标,但需要单独的逻辑。其思想是,获取相对于当前行开头的插入符号位置,并将其新位置设置为下一行的第一个字符加上相对位置,以说明下一行是否小于当前行

if (e.Key == Key.Up)
{
    if (!textBeforeCursor.Contains("\r\n"))
    {
        var caretIndex = GetTextBoxCaretIndex();
        listView.SelectedIndex--;

        var lastLineRegex = new Regex("(.*)(\r\n.*$)", RegexOptions.Singleline);
        var previousString = listView.SelectedItem as string;
        var lines = lastLineRegex.Match(previousString);
        var offset = lines.Groups[1].Length;

        FocusTextBox(caretIndex + offset + 2);
    }
    else
    {
        var item = listView.ItemContainerGenerator.ContainerFromItem(listView.SelectedItem) as ListViewItem;
        var textBox = GetVisualChildOfType<TextBox>(item);
        var currentLineIndex = textBox.GetLineIndexFromCharacterIndex(textBox.CaretIndex);
        var positionOnCurrentLine = textBox.CaretIndex - textBox.GetCharacterIndexFromLineIndex(currentLineIndex);

        var nextLineIndex = currentLineIndex - 1;
        var lineStartIndex = textBox.GetCharacterIndexFromLineIndex(nextLineIndex);
        Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
        {
            var modifier = textBox.GetLineText(nextLineIndex).Contains("\r\n") ? 2 : 0;
            textBox.CaretIndex = Math.Min(
                lineStartIndex + positionOnCurrentLine,
                lineStartIndex + textBox.GetLineLength(nextLineIndex) - modifier);
        }));
    }
}
if(e.Key==Key.Up)
{
如果(!textBeforeCursor.Contains(“\r\n”))
{
var caretIndex=GetTextBoxCaretIndex();
listView.SelectedIndex--;
var lastLineRegex=new Regex((.*)(\r\n.*)”,RegexOptions.Singleline);
var previousString=listView.SelectedItem作为字符串;
var lines=lastLineRegex.Match(previousString);
变量偏移量=行。组[1]。长度;
FocusTextBox(caretIndex+偏移量+2);
}
其他的
{
var item=listView.ItemContainerGenerator.ContainerFromItem(listView.SelectedItem)作为ListViewItem;
var textBox=GetVisualChildOfType(项目);
var currentLineIndex=textBox.GetLineIndexFromCharacterIndex(textBox.CaretIndex);
var positionOnCurrentLine=textBox.CaretIndex-textBox.GetCharacterIndexFromLineIndex(currentLineIndex);
var nextLineIndex=currentLineIndex-1;
var lineStartIndex=textBox.GetCharacterIndexFromLineIndex(nextLineIndex);
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,新操作(()=>
{
var modifier=textBox.GetLineText(nextLineIndex)。包含(“\r\n”)?2:0;
文本框.插入符号