フォームが非アクティブ化されたときにフォーカスを受け取るウィンドウを決定する方法を知っている人はいますか?
3 に答える
私は答えを見つけました。アクティブ化イベントと非アクティブ化イベントをサブスクライブする代わりに、WndProc で (アクティブ化と非アクティブ化の両方に使用される) WM_ACTIVATEメッセージを処理します。アクティブ化されているウィンドウのハンドルが報告されるため、そのハンドルをフォームのハンドルと比較して、フォーカスがそれらのいずれかに変化しているかどうかを判断できます。
const int WM_ACTIVATE = 0x0006;
const int WA_INACTIVE = 0;
const int WA_ACTIVE = 1;
const int WA_CLICKACTIVE = 2;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_ACTIVATE)
{
// When m.WParam is WA_INACTIVE, the window is being deactivated and
// m.LParam is the handle of the window that will be activated.
// When m.WParam is WA_ACTIVE or WA_CLICKACTIVE, the window is being
// activated and m.LParam is the handle of the window that has been
// deactivated.
}
base.WndProc(ref m);
}
編集:このメソッドは、適用されるウィンドウの外で使用できます (たとえば、ポップアップ ウィンドウの外)。
NativeWindow を使用して、ハンドルに基づいて任意のウィンドウにアタッチし、そのメッセージ ループを表示できます。以下のコード例を参照してください。
public class Popup : Form
{
const int WM_ACTIVATE = 0x0006;
const int WA_INACTIVE = 0;
private ParentWindowIntercept parentWindowIntercept;
public Popup(IntPtr hWndParent)
{
this.parentWindowIntercept = new ParentWindowIntercept(hWndParent);
}
private class ParentWindowIntercept : NativeWindow
{
public ParentWindowIntercept(IntPtr hWnd)
{
this.AssignHandle(hWnd);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_ACTIVATE)
{
if ((int)m.WParam == WA_INACTIVE)
{
IntPtr windowFocusGoingTo = m.LParam;
// Compare handles here
}
}
base.WndProc(ref m);
}
}
}
オートコンプリート ポップアップ ウィンドウを実装するときに同じ問題が発生します (VS の Intellisense ウィンドウに似ています)。
このアプローチの問題はWndProc
、ポップアップをホストするフォームにコードを追加する必要があることです。
別のアプローチは、タイマーを使用して、短い間隔で Form.ActiveControl をチェックすることです。このようにして、エディター コントロールまたはポップアップ フォーム内で、コードがより適切にカプセル化されます。
Form _txPopup;
// Subscribe whenever convenient
public void IntializeControlWithPopup(Form _hostForm)
{
_hostForm.Deactivate + OnHostFormDeactivate;
}
Timer _deactivateTimer;
Form _hostForm;
void OnHostFormDeactivate(object sender, EventArgs e)
{
if (_deactivateTimer == null)
{
_mainForm = sender as Form;
_deactivateTimer = new Timer();
_deactivateTimer.Interval = 10;
_deactivateTimer.Tick += DeactivateTimerTick;
}
_deactivateTimer.Start();
}
void DeactivateTimerTick(object sender, EventArgs e)
{
_deactivateTimer.Stop();
Form activeForm = Form.ActiveForm;
if (_txPopup != null &&
activeForm != _txPopup &&
activeForm != _mainForm)
{
_txPopup.Hide();
}
}
Form.ActiveForm
static プロパティを使用して、アクティブなフォームを特定できるはずです。