我有一个用 vb.net 编写的 .net MDI 应用程序。我正在尝试编写一个表单,该表单将允许用户选择一个特殊字符,例如°、µ、²、³、ɑ 等,并在他们启动表单之前将该字符插入到任何关注的控件中热键或 MDI 父级中的主菜单。
执行此操作的简单方法是确定在调用字符选择表单时哪个控件专注于哪个 MDI 子表单,但我找不到有关如何执行此操作的任何信息。
有任何想法吗?
看起来 WM_SETFOCUS 消息没有通过....我的错。我很确定他们会在Control.WndProc方法中通过。作为一种解决方法,我必须每次收到消息时都 p/invoke GetFocus并存储具有焦点的控件的句柄。
第一个代码段是过滤器类,第二个代码段是测试代码。
public class LastFocusedControlFilter : IMessageFilter
{
[DllImport("user32")]
private static extern IntPtr GetFocus();
private IntPtr? _lastCtrl;
private readonly Control _ctrlToIgnore;
public LastFocusedControlFilter(Control controlToIgnore)
{
_ctrlToIgnore = controlToIgnore;
}
public bool PreFilterMessage(ref Message m)
{
if (!_ctrlToIgnore.IsHandleCreated || _ctrlToIgnore.Disposing || _ctrlToIgnore.IsDisposed)
{
return false;
}
IntPtr handle = GetFocus();
if (handle != _ctrlToIgnore.Handle)
{
_lastCtrl = handle;
}
return false;
}
public Control GetLastFocusedControl()
{
return _lastCtrl.HasValue ? Control.FromHandle(_lastCtrl.Value) : null;
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (Form form = new Form())
{
Action resetBackColor = null;
for (int i = 0; i < 10; i++)
{
TextBox textBox = new TextBox();
resetBackColor += delegate { textBox.BackColor = Color.White; };
textBox.Text = ((char)('a' + i)).ToString();
textBox.Location = new Point(0, textBox.Height * i);
form.Controls.Add(textBox);
}
Button showTextButton = new Button();
LastFocusedControlFilter msgFilter = new LastFocusedControlFilter(showTextButton);
showTextButton.Dock = DockStyle.Bottom;
showTextButton.Text = "Show text of last selected control";
showTextButton.Click += delegate(object sender, EventArgs e)
{
resetBackColor();
Control lastControl = msgFilter.GetLastFocusedControl();
if (lastControl == null)
{
MessageBox.Show("No control previous had focus.");
}
else
{
lastControl.BackColor = Color.Red;
MessageBox.Show(string.Format("Control of type {0} had focus with text '{1}'.", lastControl.GetType(), lastControl.Text));
}
};
form.Controls.Add(showTextButton);
Application.AddMessageFilter(msgFilter);
Application.Run(form);
}
}
}
添加IMessageFilter并监视 Windows 消息,例如WM_SETFOCUS或WM_ACTIVATE。您可以使用Control.FromHandle将 IntPtrs 转换为 .NET 控件。
找到了一个更简单的方法 -
[Parent Form].ActiveMdiChild.ActiveControl
您可以将这样的类添加到您的项目中:
public class FocusWatcher
{
private static System.Windows.Forms.Control _focusedControl;
public static System.Windows.Forms.Control FocusedControl
{
get
{
return _focusedControl;
}
}
public static void GotFocus(object sender, EventArgs e)
{
_focusedControl = (System.Windows.Forms.Control)sender;
}
}
然后,对于您希望成为“最近关注的控件”候选者的任何表单上的任何控件,您可以执行以下操作:
textBox1.GotFocus += FocusWatcher.GotFocus;
然后访问FocusWatcher.FocusedControl
以获取最近关注的控件。监视消息将起作用,但您必须忽略不需要的消息(例如 Mdi 表单中的 WM_ACTIVATE)。
您可以遍历每个窗体上的所有控件并为 GotFocus 事件添加此处理程序,但肯定有您不希望使用此处理程序的控件(例如按钮)。您可以改为迭代并仅添加 TextBoxes 的处理程序。