关于c#:如何在单击Winform应用程序中的按钮后将焦点返回到上次使用的控件?

How do you return the focus to the last used control after clicking a button in a winform app?

我正在Windows窗体应用程序(C#)上工作,在该窗体中,用户正在窗体中输入数据。在编辑表单中的数据时,用户可以随时单击表单上的按钮之一以执行某些操作。默认情况下,焦点会移到单击的按钮上,因此用户必须重新单击要编辑的控件才能继续修改表单上的数据。我需要做的是在处理完按钮单击事件后,将焦点返回到上次编辑的控件。这是一个示例屏幕截图,说明了我在说什么:

Sample App Screen Shot

用户可以在textbox1,textbox2,textbox3等中输入数据,然后单击按钮。我需要按钮才能将焦点返回到单击该按钮之前最近拥有焦点的控件。

我想知道是否有人能实现比我提出的更好的功能。这是我现在正在做的事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   public partial class Form1 : Form
    {
        Control _lastEnteredControl;

        private void textBox_Enter(object sender, EventArgs e)
        {
            _lastEnteredControl = (Control)sender;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Do something here");
            _lastEnteredControl.Focus();
        }


    }

因此,基本上,我们在这里有一个指向最后输入的控件的类变量。窗体上的每个文本框都已设置,因此当控件获得焦点时将触发textBox_Enter方法。然后,当单击按钮时,焦点将返回到单击按钮之前具有焦点的控件。有人对此有更好的解决方案吗?


对于"简单性"可以尝试一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public Form1()
    {
        InitializeComponent();

        foreach (Control ctrl in Controls)
        {
            if (ctrl is TextBox)
            {
                ctrl.Enter += delegate(object sender, EventArgs e)
                              {
                                  _lastEnteredControl = (Control)sender;
                              };
            }
        }
    }

那么您不必担心手动装饰每个文本框(也不必担心一个)。


您可以执行以下操作

将按钮更改为标签,使其看起来像按钮。标签将永远不会成为焦点,您不必执行所有额外的编码。


您的方法看起来不错。如果您希望避免在添加的每个控件中添加事件处理程序,则可以创建一个递归例程,以将GotFocus侦听器添加到表单中的每个控件。这将适用于表单中的任何类型的控件,但是您可以对其进行调整以满足您的需求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void Form_OnLoad(object obj, EventArgs e)
{
    AddGotFocusListener(this);
}

private void AddGotFocusListener(Control ctrl)
{
    foreach(Control c in ctrl.Controls)
    {
        c.GotFocus += new EventHandler(Control_GotFocus);
        if(c.Controls.Count > 0)
        {
            AddGotFocusListener(c);
        }
    }
}

private void Control_GotFocus(object obj, EventArgs e)
{
    // Set focused control here
}

我想你在做什么很好。我唯一想改进的就是将每个控件在访问时存储到堆栈中。这将为您提供访问内容的完整时间表。


创建一个名为CustomTextBox的类,该类继承自TextBox。它有一个称为栈的静态变量。当文本框失去焦点时,将其推入堆栈。当您要查找最后一个集中控制时,只需从堆栈中弹出第一项即可。确保清除静态Stack变量。


是的,我承认这个要求有点不寻常。用户将进入此应用程序的某些信息存在于对旧文档的扫描中,这些文档位于几个不同的存储库中。这些按钮有助于查找和打开这些旧文档。当用户决定拉出包含更多信息以输入表单的文档时,很难预测用户在表单上的位置。尽管存在这些时髦的情况,但目的是使UI顺利进行。


您的实现看起来足够好-我想知道的是为什么您首先要这样做?将焦点循环回到第一个条目是否可取?最后一个文本框中的数据是否具有延展性,一旦他们单击该按钮就可以"记住"该数据?还是您具有按钮对特定文本框数据进行的某种操作-在那种情况下,焦点不应该转到后续控件上吗?

我有兴趣了解您为什么首先要这样做。


推荐阅读