很难弄清楚控件为什么会失去焦点

本文关键字:失去 焦点 为什么 弄清楚 控件 很难 | 更新日期: 2023-09-27 17:58:48

我创建了一个自定义网格控件,每个单元格中都有可编辑的文本块。编辑由双击触发,如下所示:

void TextBlock_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    if (e.ClickCount == 2) Edit();
}
public void Edit()
{
    TextBox.Text = TextBlock.Text;
    TextBlock.Visibility = System.Windows.Visibility.Collapsed;
    TextBox.Visibility = System.Windows.Visibility.Visible;
    Dispatcher.BeginInvoke((ThreadStart)delegate
    {
        TextBox.Focus();
        TextBox.SelectAll();
    });
}

这部分工作符合预期。

我想让用户能够通过按下tab键前进或移动tab键返回来切换到下一个单元格。我添加了一个像这样触发的事件:

void TextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
    if (e.Key == System.Windows.Input.Key.Tab)
    {
        e.Handled = true;
        OnTab(System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.LeftShift) || System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.RightShift));
    }
}

外部网格处理此事件,并在下一个或上一个可编辑单元格上调用Edit()方法。只要我没有在文本框中键入,这几乎可以像预期的那样工作。出于某种原因,如果我键入了任何内容,LostFocus事件不仅会为当前单元格(在文本框上Edit()调用Focus()之后会触发),还会为下一个单元格触发。这是LostFocus事件的代码。(尽管我很确定这与此无关。)

void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    bool TextChanged = TextBox.Text != TextBlock.Text;
    TextBlock.Text = TextBox.Text;
    TextBlock.Visibility = System.Windows.Visibility.Visible;
    TextBox.Visibility = System.Windows.Visibility.Collapsed;
    if (TextChanged) OnTextChanged();
}

我可以创建某种奇特的门,让文本框忽略这个事件,但我更好奇的是,它为什么会启动,或者至少我该如何找到答案。

谢谢。

编辑:

所以很明显,即使有一些门控,我仍然被冲洗。我添加了一个名为Editing的布尔值,并修改了Edit()方法,使其工作方式如下:

public void Edit()
{
    TextBox.Text = TextBlock.Text;
    TextBlock.Visibility = System.Windows.Visibility.Collapsed;
    TextBox.Visibility = System.Windows.Visibility.Visible;
    Thread Task = new Thread(() =>
    {
        Editing = true;
        Dispatcher.BeginInvoke((ThreadStart)delegate
        {
            System.Windows.Input.Keyboard.Focus(TextBox);
            TextBox.SelectAll();
            EditGate.Set();
        });
        EditGate.WaitOne();
        Editing = false;
    });
    Task.Start();
}

然后更改了LostFocus处理程序:

void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    if (Editing) return;
    // ... Some more code.
}

不幸的是,这也不起作用。事情最终是这样的:

  1. 当前单元格:编辑开始为false
  2. 当前单元格:选项卡事件激发
  3. 下一个单元格:调用了Edit()
  4. 下一个单元格:编辑设置为True
  5. 下一个单元格:调用了EditGate.WetOne()
  6. 下一个单元格:Keyboard.Focus()调用
  7. 当前单元格:焦点丢失(编辑仍然是错误的)
  8. 下一个单元格:调用了Textbox.SelectAll()
  9. 下一个单元格:调用了EditGate.Set()
  10. 下一个单元格:编辑设置为False
  11. 下一个单元格:焦点丢失(编辑现在为假)

我不知道为什么LostFocus事件在其他所有事件之后触发。它几乎知道我要做什么。:P

很难弄清楚控件为什么会失去焦点

我认为这可能是由于KeyboardFocus,在WPF中你可以设置"逻辑"焦点,KeyboardFocus只是猜测,但当你在TextBox中键入时,会获得KeyBoardFocus,这可能会改变逻辑焦点的状态。

这对我来说有点难测试,但试着在Edit()方法中设置键盘焦点,看看会发生什么。

public void Edit()
{
    TextBox.Text = TextBlock.Text;
    TextBlock.Visibility = System.Windows.Visibility.Collapsed;
    TextBox.Visibility = System.Windows.Visibility.Visible;
    Dispatcher.BeginInvoke((ThreadStart)delegate
    {
        Keyboard.Focus(TextBox);
        TextBox.SelectAll();
    });
}

我一直在从代码后面操作WPF焦点时遇到问题,我想这是因为它的设计不是这样的,最好使用Xaml触发器对焦点进行排序(如果可能的话)

也许FocusManager类可能会有所帮助,在这里您可以添加或删除当前/下一个项目的焦点处理程序

 FocusManager.RemoveLostFocusHandler(TextBox, TextBox_LostFocus);
 FocusManager.AddLostFocusHandler(TextBox, TextBox_LostFocus);