Top / .NET備忘録 / 00.コントロール共通 / 02.フォーカスインジケータ

次のような画面を作ってフォーカスをボタンに移動してみます。

FocusIndicator1.gif

Tab で移動した場合

FocusIndicator2.gif

マウスでクリックして移動した場合(起動直後)

FocusIndicator3.gif

マウスでクリックした場合は、破線が描画されていません。

この現象は、フォームが表示されてから Tab を入力するまで続きます。

ButtonBase を継承したコントロールがあると、WM_CHANGEUISTATE がフォームに送信され UISF_HIDEFOCUS フラグが立ち、Tab キーを入力すると、フラグがリセットされるようです。

非常に謎な仕様ですが、何か理由があるのかな?*1

困ったことに、これがボタンだけでなく、フォームに配置されたコントロールすべてに適用されてしまうので、たとえば TabControl の TabItem をクリックしてフォーカスが当たると、どこにフォーカスがあるのかわからなくなってしまいます。

フォーム側で WM_CHANGEUISTATE をキャッチし、UISF_HIDEFOCUS フラグが立ったらクリアするようにしてもいいかもしれませんが なんだか無限ループに陥りそうで怖いので、次のようなコードを Enter イベントに仕込みました。

    Form parentForm = this.FindForm();
    if (parentForm != null)
    {
        HandleRef parentRef = new HandleRef(parentForm, parentForm.Handle);
        int current = unchecked((int)(long)NativeMethods.SendMessage(
                                                            parentRef,
                                                            NativeMethods.WM_QUERYUISTATE,
                                                            IntPtr.Zero,
                                                            IntPtr.Zero));
        if ((current & NativeMethods.UISF_HIDEFOCUS) != 0)
        {
            NativeMethods.SendMessage(
                                    parentRef,
                                    NativeMethods.WM_CHANGEUISTATE,
                                    (IntPtr)NativeMethods.MAKEDWORD(NativeMethods.UISF_HIDEFOCUS, NativeMethods.UIS_CLEAR),
                                    IntPtr.Zero
                                    );
        }
    }

後日談

ButtonBase に関しては、ShowFocusCues プロパティをオーバーライドして、True を返すと、常にフォーカスインジケータが表示されます。

 protected override bool ShowFocusCues
 {
     get { return true; }
 }

ですが、タブコントロールではうまくいきませんでした。



*1 弁士殿からの情報によると OS の仕様らしいです。そういえばメニューの下線も表示されてないですね。

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   最終更新のRSS
Last-modified: 2013-12-19 (木) 03:07:30 (1336d)