如果其他人处于同样的情况,这是我最终开发的解决方案。在我看来,这个问题的简单程度令人震惊,而且也相当不令人满意。如果有人有更好的解决方案,我很想听听。
总体思路是重写 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,则会插入多个选项卡,直到他释放 Tab。
触发时,有一段时间可以看到选项卡正在创建和删除,看起来很粗制滥造。
使用 Ctrl+Tab 会导致 TextBox 的撤消数据被擦除。
缺点可能意味着该解决方案无法使用。同样,如果有更好的解决方案,我很想听听。至少,也许看到我的方法的结果可以避免其他人自己实施和发现所有这些问题的麻烦。