如果用户在表单其他地方点击,如何取消选择文本框?

6

我的应用程序目前无法取消选择文本框。唯一的方法是选择另一个文本框。我和我的用户都认为,在表单的任何其他地方单击应该取消选择当前的文本框。我尝试在许多控件上覆盖MouseDown并将焦点设置为随机标签,但对于像MenuStrip或滚动条之类的控件,它不起作用。有什么想法吗?


2
这个要求的理由是什么?这对用户有什么好处? - cdhowie
你使用的是哪个平台?WinForms、ASP.NET 还是 WPF? - Kevin Kalitowski
1
@cdhowie: 因为表格上还有NumericUpDown控件,使用鼠标滚轮可以递增/递减该值。用户希望能够单击面板并使用滚轮来浏览它。然而,NumericUpDown仍然是被选中的,并且滚动该值。我不希望仅对于NumericUpDown控件具有这种行为,因为这会让用户感到困惑。 - John Smith
然后,点击面板应该将焦点分配给其滚动条。 - cdhowie
1
@cdhowie--我理解他为什么想要这样做--网页的行为就是这样。点击一个大文本区域,你的鼠标滚轮将滚动内部文本窗口。在文本区域之外的任何地方单击,你的鼠标滚轮将滚动页面。我认为他希望他的WinForms也能以同样的方式运作。 - RLH
换另一个文本框,但不要显示它,并在面板被点击时选中它。启用该文本框,但不可见,这样可以吗? - Jon Raynor
5个回答

2

我最近遇到了类似的问题。我的界面非常复杂,有很多面板和选项卡页面,所以我找到的简单答案都不起作用。

我的解决方案是在我的窗体中为每个无法聚焦的控件编写一个鼠标点击处理程序,该处理程序将尝试聚焦表单上的任何标签。当在不同的选项卡页面上时,聚焦特定标签是行不通的,因此我最终通过循环并聚焦所有标签来解决了这个问题。

实现代码如下:

    private void HookControl(Control controlToHook)
    {
        // Add any extra "unfocusable" control types as needed
        if (controlToHook.GetType() == typeof(Panel)
            || controlToHook.GetType() == typeof(GroupBox)
            || controlToHook.GetType() == typeof(Label)
            || controlToHook.GetType() == typeof(TableLayoutPanel)
            || controlToHook.GetType() == typeof(FlowLayoutPanel)
            || controlToHook.GetType() == typeof(TabControl)
            || controlToHook.GetType() == typeof(TabPage)
            || controlToHook.GetType() == typeof(PictureBox))
        {
            controlToHook.MouseClick += AllControlsMouseClick;
        }
        foreach (Control ctl in controlToHook.Controls)
        {
            HookControl(ctl);
        }
    }
    void AllControlsMouseClick(object sender, MouseEventArgs e)
    {
        FocusLabels(this);
    }
    private void FocusLabels(Control control)
    {
        if (control.GetType() == typeof(Label))
        {
            control.Focus();
        }
        foreach (Control ctl in control.Controls)
        {
            FocusLabels(ctl);
        }
    }

然后将以下内容添加到您的Form_Load事件中:
HookControl(this);

2
假设你的论坛没有其他控件,请尝试添加一个可以接收焦点的面板控件。
将面板控件上的TabIndex设置为小于你的TextBox或NumericUpDown控件的值。
现在,当你的主窗体获得焦点时,面板应该会取代文本框区域获得焦点。 ScreenShot

这并不能解决我的问题。我不想让它们变为启用或禁用,只是让它们在用户单击其他地方时失去焦点。此外,这仅检测表单点击而不是对表单上的控件的点击。 - John Smith
如果控件被禁用,它将不会接收到鼠标消息,也不会接收焦点。 - Joe White
是的,但它只在用户单击表单上的空白区域时禁用它(这不是我想要的)。 - John Smith
你的表单上还有其他控件可以获得焦点吗?(我猜没有了) - user153923
就像 CKoenig 所说的那样,您可以添加另一个控件。基本的面板会起作用,您可以将其设置在 TextBox 控件上,并给予 Panel 焦点。这个想法是将焦点发送到其他地方,因为您的 TextBox 控件的 Tab Index 目前是最低的,这迫使它在 Form 获得焦点时总是获取焦点。 - user153923

1

由于您可能在Winform上有一个标签或其他控件,我建议使用此处推荐的解决方案,并在单击表单时将焦点放在标签上。

最坏的情况是,您甚至可以添加一个位于-100,-100位置的标签,将其设置为选项卡顺序中的第一个,并在单击表单时将其Focus()。


0

这是通用答案:为了在用户单击表单的任何其他地方时取消选择文本框,首先使控件失去焦点。为此,请订阅表单的 Click 事件:

private void Form1_Click(object sender, EventArgs e)
{
    this.ActiveControl = null;
}

接下来订阅您的文本框到焦点离开事件,并将SelectionLength设置为0(取消选择文本,尽管文本框失去焦点时不显示选择):

private void textBoxes_Leave(object sender, EventArgs e)
{
    TextBox txbox = sender as TextBox;
    txbox.SelectionLength = 0;
}

如果您的TexBoxes嵌套在自定义用户控件中,则必须以类似的方式在该用户控件内添加事件。希望这对其他人有所帮助。

0
我有一种“变通方法”可以为您提供。只需在后台添加另一个控件(可以获取焦点)。我已经测试了这个方法适用于GridView(它会将您的控件绘制成灰色) - 但是您应该能够使用自定义控件来设置所需颜色或者仅设置GridView的背景颜色(当然)。 这样,每次用户单击背景时,此背景控件将获得焦点。

这也不起作用。它只是将所有控件的容器从窗体更改为面板。同样的问题仍然存在。 - John Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接