DOBON.NET DOBON.NETプログラミング掲示板過去ログ

ComboBoxのDropDownListを一回目のClickで開かなくするには?

環境/言語:[Windows7 32bit C# .NetFrameWork4.0]
分類:[.NET]

お世話になります。

ComboBoxの設定でDropDownListを選択しています。

ComboBoxをClickをした際、List一覧が開かれるのを防ぐ良い方法はないでしょうか?

理想の動きとしては1回目のClickで2回ComboBoxをClickした後の状態(List一覧が開かず、フォーカスが当てられている状態)にしたいと考えております。(2回目以降のClickでは通常通りList一覧を表示したい)

上手く説明ができなくて申し訳ありませんが、どうぞよろしくお願いします。


【開発環境】
Windows7 32bit
VisualStudio2010
C#
.NET Framework4.0
■No32700に返信(れあさんの記事)

DropDownStyleを既定でDropDownにしておいて
EnterイベントでDropDownListに変更して
LeaveイベントでDropDownに戻す

というのはどうでしょう?
shu様
御回答ありがとうございます。

大変申し訳ないのですが、最初に書くべき情報を書き忘れておりました。。。

DropDownStyleにてDropDownListを選択している理由として、
DrawItemイベントでリストに図を描いております。

御回答していただいた方法を試したところ、図が描画されませんでした。

今一度ご助力願えませんでしょうか。
追記:

イメージとしては
DropDownイベントでe.Cancelのような動作ができればと考えております。

ですがDropDownにdelegateとしてCancelEventHandlerを追加することもできず、、、


Listが開く前に起きるイベントですので「Listを開く」イベントをキャンセルできてもおかしくないと思うのですが、「Listを開く」ことは決定事項としてその前に何かしらの記述をするためのイベントだから途中でキャンセルできないといった仕様なのでしょうか。。。?
■No32704に返信(れあさんの記事)
> ですがDropDownにdelegateとしてCancelEventHandlerを追加することもできず、、、

DropDown イベントは EventHandler 型と実装されています。
互換のある CancelEventHandler を追加することもできますが、ComboBox は EventHandler 以上の役割を果たしません。

http://msdn.microsoft.com/ja-jp/library/system.windows.forms.combobox.dropdown(v=vs.110).aspx

> Listが開く前に起きるイベントですので「Listを開く」イベントをキャンセルできてもおかしくないと思うのですが、「Listを開く」ことは決定事項としてその前に何かしらの記述をするためのイベントだから途中でキャンセルできないといった仕様なのでしょうか。。。?

.NET Framework のイベントにおいて、キャンセル可能な場合は Cancel を渡せるイベントハンドラ型で公開しつつ、現在進行形である 〜ing という命名がされていることが多いです。
DropDown イベントはそのどちらも満たしませんし、ドキュメントにもキャンセルについて言及していませんので、キャンセルできないと考えるのが自然です。



ところで、一般的な ComboBox とかけ離れていくわけですが、他の Windows アプリとの操作性の一貫性は無視してよいものなのでしょうか。
そうだとすると、既存の振る舞いを排除しなければならず、最悪、自作コントロールという路線になる可能性があります。
(メッセージを横取りするとか無理矢理すればできる可能性は否定しませんが、かなり作り込みが難しいことと、Windows のバージョンのよって動きが変わる恐れがあるため、安定的ではありません)
■No32700に返信(れあさんの記事)
> 1回目のClickで2回ComboBoxをClickした後の状態(List一覧が開かず、フォーカスが当てられている状態)にしたいと考えております。
> (2回目以降のClickでは通常通りList一覧を表示したい)

これでどうでしょう。

public class DropDownBox : ComboBox
{
    const uint WM_MOUSEACTIVATE = 0x21;
    const uint MA_ACTIVATE = 1;
    const uint MA_ACTIVATEANDEAT = 2;

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == WM_MOUSEACTIVATE)
        {
            if(Focused)
            {
                m.Result = (IntPtr)MA_ACTIVATE;
            }
            else
            {
                Focus();
                Select();
                m.Result = (IntPtr)MA_ACTIVATEANDEAT;
            }
        }
    }
}
Azulean様

>.NET Framework のイベントにおいて、キャンセル可能な場合は Cancel を渡せるイベントハンドラ型で公開しつつ、現在進行形である 〜ing という命名

なるほど。。。現在進行形のイベントはまだ「完了」していないため、キャンセル可能になっているんですね。
またイベント名から見分けることができることがわかり大変勉強になりました。ありがとうございます。


>一般的な ComboBox とかけ離れていくわけですが、他の Windows アプリとの操作性の一貫性は無視してよいものなのでしょうか。

ここに関しては私も少々引っかかっておりました。やはり通常動作から逸脱した動きというものは、いくらその場において利便性が高くても導入するべきか微妙な点ですよね。
今一度動きについて検討しようと思います。




魔界の仮面弁士様

わざわざコードを提示していただき大変恐縮です。ありがとうございます。
お見受けするにやはり自作のコントロールを作成するしか私の求めているDropDownListの動きは実現が難しいようですね。。。

今回はAzulean様の御回答にもあったよう、今一度この仕様について検討をし直したいと思います。(わざわざコードを記述していただいたのに大変申し訳ありませんん。。。)


色々と疑問に思っていた点を解消でき、かつ的確な道標をしていただき大変うれしく存じます。
これからもお世話になると思いますが、どうぞよろしくお願いします。
解決済み!
■No32711に返信(れあさんの記事)
> やはり自作のコントロールを作成するしか私の求めているDropDownListの動きは実現が難しいようですね。。。

ComboBox を継承したコントロールを作りたくないのであれば、
NativeWindow クラスの WndProc メソッドに同じことを書いておき、
NativeWindow.AssignHandle で割り当てれば OK です。


> 今一度この仕様について検討をし直したいと思います。

その方が良いでしょうね。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板