DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

ListViewのアイテムがポイントで選択、シングルクリックでアクティブにできるようにする

エクスプローラの「フォルダオプション」では「ポイントして選択し、シングルクリックで開く」という設定があります。これと同じことをListViewで行えるようにしてみましょう。

ポイントで選択できるようにするには、ListViewのHoverSelectionプロパティをTrueにします。また、シングルクリックで開くという動作を実現するためには、ActivationプロパティをItemActivation.OneClickとし、「開く」という処理をItemActivateイベントハンドラで行うようにします。

次の例では、リストビューコントロールListView1のアイテムがポイントで選択でき、シングルクリックによりそのアイテムの名前が表示されるようにしています。

VB.NET
コードを隠すコードを選択
'フォームのLoadイベントハンドラ
Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) _
                       Handles MyBase.Load
    'ポイントで選択できるようにする
    ListView1.HoverSelection = True
    'シングルクリックでアクティブにできるようにする
    ListView1.Activation = ItemActivation.OneClick
End Sub

'アイテムがアクティブになった時
Private Sub ListView1_ItemActivate(ByVal sender As Object, _
                                   ByVal e As EventArgs) _
                                   Handles ListView1.ItemActivate
    Dim lv As ListView = DirectCast(sender, ListView)
    'フォーカスのあるアイテムのTextを表示する
    MessageBox.Show(lv.FocusedItem.Text)
End Sub
C#
コードを隠すコードを選択
//フォームのLoadイベントハンドラ
private void Form1_Load(object sender, System.EventArgs e)
{
    //ポイントで選択できるようにする
    ListView1.HoverSelection = true;
    //シングルクリックでアクティブにできるようにする
    ListView1.Activation = ItemActivation.OneClick;

    //ItemActivateイベントハンドラの追加
    ListView1.ItemActivate += new EventHandler(ListView1_ItemActivate);
}

//アイテムがアクティブになった時
private void ListView1_ItemActivate(object sender, EventArgs e)
{
    ListView lv = (ListView) sender;
    //フォーカスのあるアイテムのTextを表示する
    MessageBox.Show(lv.FocusedItem.Text);
}

ブラウザのように、アイコンタイトルに下線を付ける

エクスプローラにはさらに「ブラウザのように、アイコンタイトルに下線を付ける」というオプションがありますが、これと同じようなことをできないものでしょうか?これは、MouseMoveイベントでポイントされているアイテムを調べ、そのアイテムのフォントを下線付きにすれば何とかなりそうです。次にそのMouseMoveイベントハンドラでのコード例を示します。

VB.NET
コードを隠すコードを選択
'前回ポイントしたListViewItem
Private pointedListViewItem As ListViewItem = Nothing

'MouseMoveイベントハンドラ
Private Sub ListView1_MouseMove(ByVal sender As Object, _
                                ByVal e As MouseEventArgs) _
                                Handles ListView1.MouseMove
    Dim lv As ListView = DirectCast(sender, ListView)
    'ポイントしているListViewItemを取得
    Dim lvi As ListViewItem = lv.GetItemAt(e.X, e.Y)
    If Not pointedListViewItem Is lvi Then
        'ポイントされているアイテムに下線を付ける
        If Not lvi Is Nothing AndAlso Not lvi.Font.Underline Then
            Dim old As Font = lvi.Font
            'サブアイテムのフォントは変更しない
            If lvi.UseItemStyleForSubItems Then
                lvi.UseItemStyleForSubItems = False
            End If
            'フォントスタイルにUnderlineを追加する
            Dim fs As FontStyle = old.Style Or FontStyle.Underline
            Dim fnt As New Font(old.FontFamily, old.Size, fs)
            lvi.Font = fnt
        End If
        '前回ポイントされていたアイテムの下線を取る
        If Not pointedListViewItem Is Nothing AndAlso _
                pointedListViewItem.Font.Underline Then
            Dim old As Font = pointedListViewItem.Font
            'フォントスタイルのUnderlineを削除する
            Dim fs As FontStyle = old.Style Xor FontStyle.Underline
            Dim fnt As New Font(old.FontFamily, old.Size, fs)
            pointedListViewItem.Font = fnt
        End If
        'ポイントされているアイテムを記憶する
        pointedListViewItem = lvi
    End If
End Sub
C#
コードを隠すコードを選択
//前回ポイントしたListViewItem
private ListViewItem pointedListViewItem = null;

//MouseMoveイベントハンドラ
private void ListView1_MouseMove(object sender, MouseEventArgs e)
{
    ListView lv = (ListView) sender;
    //ポイントしているListViewItemを取得
    ListViewItem lvi = lv.GetItemAt(e.X, e.Y);
    if (pointedListViewItem != lvi)
    {
        //ポイントされているアイテムに下線を付ける
        if (lvi != null && !lvi.Font.Underline)
        {
            Font old = lvi.Font;
            //サブアイテムのフォントは変更しない
            if (lvi.UseItemStyleForSubItems)
                lvi.UseItemStyleForSubItems = false;
            //フォントスタイルにUnderlineを追加する
            FontStyle fs = old.Style | FontStyle.Underline;
            Font fnt = new Font(old.FontFamily, old.Size, fs);
            lvi.Font = fnt;
        }
        //前回ポイントされていたアイテムの下線を取る
        if (pointedListViewItem != null && 
            pointedListViewItem.Font.Underline)
        {
            Font old = pointedListViewItem.Font;
            //フォントスタイルのUnderlineを削除する
            FontStyle fs = old.Style ^ FontStyle.Underline;
            Font fnt = new Font(old.FontFamily, old.Size, fs);
            pointedListViewItem.Font = fnt;
        }
        //ポイントされているアイテムを記憶する
        pointedListViewItem = lvi;
    }
}

上記のコードを試してみると、かなりちらつきます。ちらつきを抑える方法は、「The Code Project - Flicker-free ListView in .NET - Part 2」等で紹介されています。

  • 履歴:
  • 2010/9/8 VB.NETのコードを修正。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。