难以弄清楚为什么控制失去焦点

时间:2013-02-12 02:36:01

标签: c# wpf focus

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

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键前进或切换选项卡即可切换到下一个单元格。我添加了一个像这样触发的事件:

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. 当前单元格:编辑开始为假
  2. 当前单元格:标签事件触发
  3. 下一个单元格:编辑()名为
  4. 下一个单元格:编辑设置为True
  5. Next Cell:EditGate.WaitOne()名为
  6. Next Cell:Keyboard.Focus()名为
  7. 当前单元格:焦点丢失(编辑仍为假)
  8. Next Cell:Textbox.SelectAll()名为
  9. Next Cell:EditGate.Set()名为
  10. 下一个单元格:编辑设置为False
  11. Next Cell:Focus Lost(编辑现在为假)
  12. 我不确定为什么LostFocus事件在之后发射。这几乎就像它知道我正在做什么。 :P

1 个答案:

答案 0 :(得分:1)

我认为这可能是由于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);