UWP / WinRT:如何使Tab键在TextBox中正常运行?

时间:2015-08-09 18:41:21

标签: textbox windows-runtime c++-cx uwp

默认情况下,文本框不会插入制表符。当您按Tab键时,它会将焦点移动到下一个元素。按Ctrl-Tab时,它会插入制表符。

如何修复此行为,就像人们通常希望文本框的行为一样,这样Tab键会使用制表符插入缩进?此外,如何将Ctrl-Tab重新映射到替代函数?

对于插入制表符的第一个问题,我可以附加到TextBox的KeyDown事件,如果按下的键是Tab,则将事件标记为处理以防止TextBox失去焦点,但怎么能我插入Tab字符?

当我附加到文本框的KeyDown事件时,如果已按住Ctrl键,则按Tab键永远不会触发侦听器。如果我附加到TextBox的KeyUp事件,则按Tab键确实会被拾取,但只有在它已经将一个选项卡插入TextBox之后。如何在没有这种不良行为的情况下重新映射Ctrl-Tab?

我在C ++ / CX工作。

1 个答案:

答案 0 :(得分:1)

如果其他人处于相同的情况,这是我最终开发的解决方案。在我看来,问题是多么简单,而且相当不令人满意。如果有人有更好的解决方案,我很乐意听到它。

一般的想法是覆盖Tab的KeyDown事件以插入' \ t'字符。能够覆盖Ctrl + Tab的KeyDown事件也很棒,但这似乎不可能,因为TextBox上的某种硬编码吞噬了Ctrl + Tab KeyDown事件,它甚至都不会触发。因此,将覆盖Ctrl + Tab的KeyUp事件。

KeyDown(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e)
{
    if (e->Key == VirtualKey::Control) m_CtrlKeyPressed = true;
    else if (e->Key == VirtualKey::Tab) {
        // There is no need to test for if Ctrl is pressed here, since Ctrl-Tab appears to
        // be hardcoded into TextBox.
        // When Ctrl is pressed, a KeyDown event for Tab is never fired by TextBox.

        // Normally TextBox will try to give up focus when Tab is pressed - this prevents
        // that.
        e->Handled = true;

        // Platform::Strings support almost no operations, so we will need to cast the
        // TextBox's text into a wstring to insert.
        TextBox^ textBox = static_cast<TextBox^>(sender);
        std::wstring modifiedString(textBox->Text->Data());

        // SelectionStart works as current cursor position even when no text is selected.
        int cursorPosition = textBox->SelectionStart;

        // Unfortunately, casting into a wstring reveals Windows line-endings as \r\n,
        // which count as two characters now.
        // Therefore, every time we run into a line-ending our cursorPosition will become
        // off by one, so we need to compensate.
        int offsetDueToLineEndings = 0;
        for (int i = 0; i < cursorPosition + offsetDueToLineEndings; i++)
        {
            if (modifiedString[i] == '\r') offsetDueToLineEndings++;
        }
        modifiedString.insert(cursorPosition + offsetDueToLineEndings, 1, '\t');

        // Unfortunately, this text replacement wipes TextBox's built-in undo data.
        textBox->Text = ref new String(modifiedString.c_str());
        textBox->SelectionStart = cursorPosition + 1;
    }
}


KeyUp(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e)
{   
    if (e->Key == VirtualKey::Control) m_CtrlKeyPressed = false;
    else if (m_CtrlKeyPressed)
    {
        if (e->Key == VirtualKey::Tab) {
            // See KeyDown for Tab for comments on this code.
            TextBox^ textBox = static_cast<TextBox^>(sender);
            std::wstring modifiedString(textBox->Text->Data());

            int cursorPosition = textBox->SelectionStart;

            int offsetDueToLineEndings = 0;
            for (int i = 0; i < cursorPosition + offsetDueToLineEndings; i++)
            {
                if (modifiedString[i] == '\r') offsetDueToLineEndings++;
            }
            modifiedString.erase(cursorPosition + offsetDueToLineEndings - 1, 1);

            textBox->Text = ref new String(modifiedString.c_str());
            textBox->SelectionStart = cursorPosition - 1;

            // Do something with Ctrl+Tab
        }
    }
}

此实施存在许多严重问题。

对于简单的Tab按:

  • 插入Tab会导致删除TextBox的撤消数据。

对于Ctrl + Tab,请按:

  • 如果用户按住Ctrl + Tab,则会插入多个标签,直到他发布标签。

  • 触发时,分割时刻可以看到正在创建和删除的标签,看起来很粗制。

  • 使用Ctrl + Tab会导致删除TextBox的撤消数据。

缺点可能意味着此解决方案无法使用。再说一次,如果有更好的解决方案,我很乐意听到它。至少,也许看到我的方法的结果可以拯救别人自己实现和发现所有这些问题的麻烦。