ごまなつ Blog

楽しく働ける世界を目指して

【C#】ListViewのアイテム選択が外れる

ListViewを使っており、ContextMenustripを使っていました。選択されているItemが空白の場合と空白でない場合でContextMenustripの内容を変更していました。

アイテム選択が外れる場合

ListViewは、最終番号の下に空白が存在します。スクロールバーを表示するほどのアイテム数だったとしても、狭い範囲ですが空白が存在し、ここをクリックするとListViewのアイテムを何も選択しない状態になります。また、横にListViewを広げたときなど、アイテムの内容が存在しない部分をクリックしてもListViewのアイテムを何も選択しない状態になります。

MouseUpではイベントハンドラが発生するが、MouseClickでは発生しない

このアイテム選択が外れる領域では、クリックしてもListView.MouseClickは発生しません。しかし、MouseDown、MouseUpは発生します。今回の場合は、クリックした後のマウスの座標で処理したかったため、MouseUpを用います。

クリックした場所に一番近いアイテムを選択する

listView.InsertionMark.NearestIndex()では、指定したポイントに最も近い項目のインデックスを取得します。ポイントは、座標です。クリックした座標に最も近いListViewのインデックスを取得できるので、そこを選択状態にします。

private void listView_MouseUp(object sender, MouseEventArgs e)
        {
            // Retrieve the index of the item closest to the mouse pointer.
            int targetIndex = listView.InsertionMark.NearestIndex(new Point(e.X, e.Y));
            if (listView.SelectedItems.Count < 1)
            {
                listView.Items[targetIndex].Selected = true;
                listView.Items[targetIndex].Focused = true;
            }

こうすることで、下の空白をクリックすると最終番号が選択され、横の空白部分をクリックするとその場所に一番近いアイテムが選択されます。

座標系で注意すること

C#での座標系には以下の2種類があります。

  • ディスプレイの左上端が(0,0)
  • コントロールの左上端が(0,0)

使用しているライブラリがどちらの座標を用いているか確認しましょう。思っている座標とずれます。今回の場合は、コントロールの左上端が(0,0)なのでイベントハンドラが取得したクリックした座標をそのまま代入しています。ディスプレイの左上端が(0,0)の場合は、

Point targetPoint =  ListView.PointToClient(new Point(e.X, e.Y));

としてコントロールの左上端が(0,0)の座標に変換してください。