2008年10月7日火曜日

C#でListViewをOwnerDrawで描画するときの注意事項(たぶんMSバグ)

ListView.HideSelection = False にして「他のコントロールにフォーカスが移ってもListView上の選択項目を強調表示のままにしておきたい」ことはよくありますが、このケースでOwnerDrawを実装しようとすると問題があります。ListView.OwnerDraw = Falseにして各イベントハンドラを作成しても、選択行/非選択行の背景色の描画が意図どおりにいかない方は読み進んでみてください。

OwnerDrawで背景色の描画を行う場合、DrawItemイベント及びDrawSubItemイベントの引数DrawListViewItemEventArgsStateプロパティに"Selected"フラグが付いているか否かを判別して選択行/非選択行の描画を行います(多くのサンプルソースはそうしていました)。しかし、ListView.HideSelection = False の場合、なぜかすべての行が選択行であるかのようにイベントハンドラの引数DrawListViewItemEventArgs.Stateプロパティに"Selected"フラグが付いているという現象です。ListView.HideSelectionプロパティをデフォルトのTrueに戻したところ現象が解消されたので間違いないと思います。

他にスマートでいい回避策があるのかもしれませんが、私の場合は ListViewの SelectedIndexChangedイベントで選択行をクラス変数などに保持しておき、DrawItemイベント及び DrawSubItemイベントハンドラの中で DrawListViewItemEventArgs.ItemIndexと同一の場合に選択行と判別するようにしました。

ネットで検索してもなかなかいい情報が出てこずに困っていたので、同様のお悩みを抱えている方のためにもメモ書きとして残しておきます。(というより自分用でもあるけど。)

なお、.NET Framework は 2.0 です。

2 件のコメント:

Unknown さんのコメント...

初めまして。
私も同様の問題に遭遇し、どうすればよいのかさっぱりわかりませんでした。
しかしこの記事を参考にして試してみたところ、理想としていた動作を実現できました。
しかも「マウスオーバーで選択が解除される」という問題も回避でき、一石二鳥という結果に。
すべてこの記事のお陰です。ありがとうございました!

うるふー さんのコメント...

初めまして。
私の場合は、e.Item.Selectedをみることで対応しました。
HideSelectionが関係しているとは思いもよらなかったので、大変参考になりました。