ここでは、現在アクティブな(選択されている、フォーカスのある)コントロールを取得する方法と、指定したコントロールをアクティブにする(選択する、フォーカスを移動させる)方法について説明します。
現在アクティブなコントロールを取得するには、ContainerControl.ActiveControlプロパティを使用します。
フォームクラス内で、現在アクティブなコントロールを取得する例を示します。
'Imports System.Windows.Forms '現在アクティブなコントロールを取得する Dim c As Control = f.ActiveControl If Not (c Is Nothing) Then Console.WriteLine("現在アクティブなコントロールは、{0}です。", c.Name) Else Console.WriteLine("現在アクティブなコントロールはありません。") End If
//using System.Windows.Forms; //現在アクティブなコントロールを取得する Control c = f.ActiveControl; if (c != null) { Console.WriteLine("現在アクティブなコントロールは、{0}です。", c.Name); } else { Console.WriteLine("現在アクティブなコントロールはありません。"); }
MSDNの「ContainerControl.ActiveControlプロパティ」によると、「あるフォームから別のフォームの ActiveControl プロパティを呼び出すと、未定義の値が返されます。 この場合、このデータを受け渡すための独自のコミュニケーション機構をフォーム間に定義する必要があります。」とのことです。私が試した限りでは、別フォームのActiveControlプロパティも有効な値を返すように見えましたが、注意が必要です。
フォームにSplitContainerコントロールが配置されており、SplitContainer上にあるコントロールがアクティブな時、フォームのActiveControlプロパティはそのコントロールを返さずに、SplitContainerコントロールを返します。この時、正しいアクティブコントロールを取得するには、SplitContainerのActiveControlプロパティを使用します。
SplitContainerコントロール上にアクティブコントロールがあっても、SplitContainerではなく、そのコントロールを返すメソッドの例を示します。
'Imports System.Windows.Forms ''' <summary> ''' アクティブコントロールを取得する ''' </summary> ''' <param name="parentControl"> ''' アクティブコントロールを探す元のコンテナコントロール ''' </param> ''' <returns>アクティブコントロール</returns> ''' <example> ''' 自分自身のフォームのアクティブコントロールを取得する例 ''' <code> ''' Dim c As Control = GetRealActiveControl(Me) ''' </code> ''' </example> Public Shared Function GetRealActiveControl( _ parentControl As ContainerControl) As Control 'ActiveControlプロパティを取得 Dim ac As Control = parentControl.ActiveControl 'ActiveControlがNULLの時は、コンテナコントロールを返す If ac Is Nothing Then Return parentControl End If 'ActiveControlがコンテナコントロールの場合は、さらにActiveControlを取得 If TypeOf ac Is ContainerControl Then Return GetRealActiveControl(DirectCast(ac, ContainerControl)) End If Return ac End Function
//using System.Windows.Forms; /// <summary> /// アクティブコントロールを取得する /// </summary> /// <param name="parentControl"> /// アクティブコントロールを探す元のコンテナコントロール /// </param> /// <returns>アクティブコントロール</returns> /// <example> /// 自分自身のフォームのアクティブコントロールを取得する例 /// <code> /// Control c = GetRealActiveControl(this); /// </code> /// </example> public static Control GetRealActiveControl(ContainerControl parentControl) { //ActiveControlプロパティを取得 Control ac = parentControl.ActiveControl; //ActiveControlがNULLの時は、コンテナコントロールを返す if (ac == null) { return parentControl; } //ActiveControlがコンテナコントロールの場合は、さらにActiveControlを取得 if (ac is ContainerControl) { return GetRealActiveControl((ContainerControl)ac); } return ac; }
このような方法以外に、後述する、フォーム上のすべてのコントロールのFocusedプロパティを調べるという方法でも可能です。
あるコントロールがアクティブであるかは、Control.Focusedプロパティで調べることができます。
If TextBox1.Focused Then Console.WriteLine("TextBox1にフォーカスがあります。") Else Console.WriteLine("TextBox1にフォーカスがありません。") End If
if (TextBox1.Focused) Console.WriteLine("TextBox1にフォーカスがあります。"); else Console.WriteLine("TextBox1にフォーカスがありません。");
そのコントロールか、そのコントロール内にある子コントロールにフォーカスがあるかどうかは、Control.ContainsFocusプロパティで調べることができます。
以下に示すメソッドは、指定したコントロール内にあるすべてのコントロールを調べ、FocusedプロパティがTrueのコントロールを返しています。
'Imports System.Windows.Forms ''' <summary> ''' 指定されたコントロール内にあるコントロールで、 ''' FocusedプロパティがTrueのコントロールを返す ''' </summary> ''' <param name="parentControl">基になるコントロール</param> ''' <returns>FocusedプロパティがTrueのコントロール</returns> Public Shared Function GetForcusedControl( _ parentControl As Control) As Control 'コントロール内のコントロールを列挙する Dim c As Control For Each c In parentControl.Controls 'FocusedがTrueの時、そのコントロールを返す If c.Focused Then Return c End If '子コントロールにフォーカスがある時 If c.ContainsFocus Then 'さらにコントロール内のコントロールを調べる Dim fc As Control = GetForcusedControl(c) If Not (fc Is Nothing) Then Return fc End If End If Next '見つからなかった場合は、NULLを返す Return Nothing End Function
//using System.Windows.Forms; /// <summary> /// 指定されたコントロール内にあるコントロールで、 /// FocusedプロパティがTrueのコントロールを返す /// </summary> /// <param name="parentControl">基になるコントロール</param> /// <returns>FocusedプロパティがTrueのコントロール</returns> public static Control GetForcusedControl(Control parentControl) { //コントロール内のコントロールを列挙する foreach (Control c in parentControl.Controls) { //FocusedがTrueの時、そのコントロールを返す if (c.Focused) { return c; } //子コントロールにフォーカスがある時 if (c.ContainsFocus) { //さらにコントロール内のコントロールを調べる Control fc = GetForcusedControl(c); if (fc != null) { return fc; } } } //見つからなかった場合は、NULLを返す return null; }
指定したコントロールをアクティブにするための方法はいくつかあります。
最も基本的な方法は、Control.Selectメソッドを呼び出す方法です。例えば、TextBox1をアクティブにするには、次のようにします。
'TextBox1をアクティブにする
TextBox1.Select()
//TextBox1をアクティブにする
TextBox1.Select();
補足:コントロールには、アクティブにすることのできないコントロールもあります。アクティブにできないコントロールは、Panel、GroupBox、PictureBox、ProgressBar、、Splitter、Label、リンクが存在しないLinkLabelなどです。また、コントロール(または、親コントロール)のEnabledかVisibleプロパティがFalseになっている時もアクティブになりません。あるコントロールをアクティブにできるかを調べるには、Control.CanSelectプロパティを使用します。
また、アクティブにしたいコントロールをContainerControl.ActiveControlプロパティに設定するという方法もあります。
例えば、フォームにあるTextBox1をフォームクラスからアクティブにするには、次のようにします。
'TextBox1をアクティブにする Me.ActiveControl = TextBox1
//TextBox1をアクティブにする this.ActiveControl = TextBox1;
Control.Focusメソッドを使用してもほぼ同じことができます。しかし、MSDNによると、「Focus は、主にカスタム コントロールの作成者が使用するための下位メソッドです」とのことです。
'TextBox1をアクティブにする
TextBox1.Focus()
//TextBox1をアクティブにする
TextBox1.Focus();
補足:上記の方法でSplitContainerコントロールをアクティブにしようとした時、ActiveControlとFocusではSplitContainerコントロールの分割線が選択された状態になりますが、Selectは分割線が選択状態にならず、SplitContainerコントロール内のコントロールがアクティブになります。
次のタブオーダーのコントロールをアクティブにする方法は、「次のタブオーダーのコントロールをアクティブに(選択、フォーカスを移動)する」で説明しています。