代表步骤:
- 创建示例 .NET 表单应用程序
- 在窗体上放置一个文本框
- 将函数连接到文本框的 Enter 事件
运行此应用程序时,当焦点首次转到文本框时,将触发 Control.Enter 事件。 但是,如果单击另一个应用程序,然后单击返回到测试应用程序,则不会再次触发该事件。
因此,在应用程序之间移动不会触发进入/离开。
是否有另一个可以使用的替代控件级事件,该事件将在此方案中触发?
通常,我会使用 Form.Active。 不幸的是,这很麻烦,因为我的组件由停靠系统托管,该系统可以在不通知我的情况下将我的组件取消停靠到新表单中。
Enter 事件中做什么?
我找不到在您的示例程序中触发的另一个控件级事件,但是当我的测试应用确实重新获得焦点时,上次具有焦点的控件仍然具有该焦点。
有趣的问题,但它需要更多的背景。
如果我尝试您的示例并在另一个窗口、桌面等上的控件外部单击,我可以触发 Got 和 Lost Focus 事件,但是如果您只尝试在只有一个控件的窗体或控件内单击,则永远不会触发这些事件,因为它是唯一需要关注的事情。 输入或离开都不会,除非您更改动态或重载控件,否则您无法发生这种情况
在您的示例中,我认为您需要另一个控件。 原因是第一个控件 (tabIndex 0) 是具有焦点的控件。 如果没有其他控件可以切换焦点,则此控件将始终处于焦点状态,因此永远无法进入。 切换到另一个应用程序或窗体不会更改此窗体中的焦点或活动控件,因此当您返回时,您仍然不会触发事件。
添加控件后,输入控件应该可以正常工作。 如果这是您唯一的控件,为什么不在窗体获得焦点时调用 formLoad 或 TextChange 上的事件?
谢谢,我会给出一些背景。
我的控件是包含网格和工具栏的用户控件。 用户通常会启动其中的几个控件来查看系统数据的不同切片。
有几个键盘快捷键可以从当前网格中的选定行启动操作。 但是,要求这些键盘快捷键不仅应应用于当前聚焦的网格。 如果用户当前专注于应用程序的许多其他区域之一,则此键盘快捷方式仍应有效,并且应路由到最后一个焦点网格。
所以我将一个函数连接到我的UserControl的Control.Enter事件,基本上说LastFocusedGrid = this。
它会起作用,除了对接和取消对接...
请参阅,这些控件托管在具有停靠功能的应用程序内,有点类似于 Visual Studio。
默认情况下,控件作为应用程序主工作区内的选项卡启动,类似于源文件在 Visual Studio 中打开的方式。
但是,用户可以通过抓取选项卡标题并将其拖出主应用程序来"撕掉"选项卡。 此时,应用程序创建一个新的"浮点窗体"来承载控件。 在主应用程序和此浮动窗体之间切换与在应用程序之间切换相同,以便用于 Control.Enter 和 Form.Activated 事件。
此时,我们有了使用原始帖子中描述的示例应用程序模拟的"表单中的一个控件"场景。
现在,有一些方法可以解决这个问题。 我可以利用 Form.Activated 事件,该事件在窗体之间切换时会触发。 如果将测试应用程序中的事件添加到窗体的已激活事件,您将看到它工作得很好。
问题是我的 UserControl 与其父窗体的关系是流动的,这使得解决方案有些复杂。 我试着连接到"这个。ParentForm.Active",工作正常。 问题是你什么时候称呼这个? 当您断开停靠/重新停靠时会发生什么? 我最终得到了一堆令人讨厌的代码,其中包含"previousParentForm"之类的东西,以便我可以从旧表单中解脱出来,然后我仍然面临对接系统在我的父表单被更改时不通知我的问题,所以我将不得不在那里进行一堆更改, 太。
这些问题并非无法解决,但如果有一个更简单的控件级"父窗体已激活"事件,那么这将更加优雅。
这相当长,但我希望它能澄清情况。
那么在创建网格时,您不能设置按键或 KeyUp 等事件吗? 如果是这样,则所有网格都可以使用相同的事件处理程序。 只需确保在进入事件处理程序时执行以下操作:
Grid currentGrid = (Grid)sender;
然后,您应该能够将该代码块应用于发送的任何网格,而不必担心跟踪。
由于所有事件处理程序都是,因此它的位置实际上是一个静音点,只要执行它所需的所有内容都是可访问的。
Frye,问题是无论用户在应用程序中的哪个位置,键盘快捷键都应该工作。 它们是全局命令,在顶层处理,然后路由到"最后一个聚焦网格"。
因此,在网格级别处理击键将无济于事。
更具体地说,假设用户启动网格 A、B 和 C。 但他也启动了其他与我的代码无关的控件 X、Y 和 Z。
用户单击A,然后单击C。 然后他点击Y,然后点击Z。 专注于Z,他点击了我的键盘快捷键。 在这种情况下,网格 C 应该响应,因为它是用户关注的最后一个网格。
听起来您遇到的问题与 Enter 事件没有直接关系,更重要的是,如果您有"与您的代码无关"的控件,那么您真的没有查看控件级别事件。
猜我不清楚。
我的控件位于容器应用程序中。 其他团队的其他不相关的控件也是如此。 把它想象成Visual Studio - 我的控件是代码编辑选项卡,但也有挂起的更改列表和属性窗口,它们与源文件共存,但没有直接关系。
键盘快捷方式由容器应用程序处理。 然后,它应该路由到用户关注的最后一个控件。
维护这个"LastFocusedGrid"引用是我在 Enter 事件中所做的。
如果你想在Visual Studio中看到类似的功能,请尝试以下操作:
- 打开几个源文件
- 导航到"起始页"选项卡。
- 按 Ctrl-F 并在"当前文档"中搜索一些字符串
- 请注意,serach 功能会自动导航到"最后焦点"源文件以执行搜索。
因此,即使您没有聚焦于源文件,ctrl-F 命令也会由 Visual Studio 处理并路由到最后一个聚焦的源文件选项卡。
现在用 Ctrl-G 尝试同样的事情。 除非您直接专注于源文件,否则它不起作用。
我的键盘命令需要像 Ctrl-F 一样工作,而不是像 Ctrl-G。 这就是为什么我不只是直接在我的控件中捕获键盘事件。
这是否澄清或使事情变得更糟?
您是否尝试过一个简单的 Control.GotFocus?
示例中,如果您在单击文本框之间切换,则 Enter 或 Get 焦点都不会按预期执行,但是,如果您单击子窗体,则两者都将按预期运行。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace EnterBrokenExample
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form Form1 = new Form();
Form c1 = new Form();
Form c2 = new Form();
Form1.IsMdiContainer = true;
c1.MdiParent = Form1;
c2.MdiParent = Form1;
c1.Show();
c2.Show();
TextBox tb1 = new TextBox();
c1.Controls.Add(tb1);
tb1.Enter += ontbenter;
tb1.Text = "Some Text";
tb1.GotFocus += ongotfocus;
TextBox tb2 = new TextBox();
c2.Controls.Add(tb2);
tb2.Enter += ontbenter;
tb2.Text = "some other text";
tb2.GotFocus += ongotfocus;
Application.Run(Form1);
}
static void ontbenter(object sender, EventArgs args)
{
if (!(sender is TextBox))
return;
TextBox s = (TextBox)sender;
s.SelectAll();
}
static void ongotfocus(object sender, EventArgs args)
{
if (!(sender is TextBox))
return;
TextBox s = (TextBox)sender;
s.SelectAll();
}
}
}