RetrieveVirtualItemイベントを起こすには

タグの編集
投稿者 RCB  (その他) 投稿日時 2020/7/23 16:48:33
質問させて下さい

派生ListViewを仮想モードでオーナードローしています

選択時の処理をMouseUpイベントでしているのですが、選択状態のアイテムはRetrieveVirtualItemイベントが起きて描画されるのですが、非選択状態になったアイテムのRetrieveVirtualItemイベントが起きないため選択解除の描画が行われません
(MultiSelect=Falseです)

マウスオーバーすればRetrieveVirtualItemが呼ばれて再描画されるのですがそれでは意味がないのでMouseUpイベントの中から両方の描画を行いたいのです

何とかこのイベントを起こす方法は無いものでしょうか?…
投稿者 るきお  (社会人) 投稿日時 2020/7/23 18:19:27
RCBさんが、どのようなプログラムをされているのかわからないので想像を交えて回答します。

選択状態と非選択状態の描画はDrawItemなどのオーナードロー用のイベントで行うのが普通で、通常RetrieveVirtualItemイベントは関係しないと思います。このあたり、何か通常ではない作り込みをされているのかもしれませんが、どのような作り込みになっているのまでは想像できませんでした。

次のプログラムでは選択されている項目は赤い文字で描画し、選択されていない項目は黒文字で描画します。
項目の上でMouseUpすると「選択時の処理」を含むメッセージボックスを表示します。

このプログラムでは選択を解除すると赤い文字ではなく黒文字で描画されます。

RCBさんが質問されているようなRetrieveVirtualItemイベントを起こす方法の回答ではないのですが、これでやりたいことは実現できますでしょうか?


Public Class Form1
    Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown

        ListView1.Dock = DockStyle.Fill 'ListViewをフォームいっぱいに広げます。 
        ListView1.Columns.Add("MainItem").Width = 500   '幅500のMainItem列を追加します。 
        ListView1.OwnerDraw = True  'オーナードローを有効にします。 
        ListView1.VirtualMode = True    '仮想モードを有効にします。 
        ListView1.VirtualListSize = 1000    '仮想項目数を1000にします。 
        ListView1.View = View.Details   '詳細モードにします。 

    End Sub

    Private Sub ListView1_RetrieveVirtualItem(sender As Object, e As RetrieveVirtualItemEventArgs) Handles ListView1.RetrieveVirtualItem

        '表示される項目のセット(毎回項目を新規作成しています。) 
        Dim item1 As New ListViewItem("Main" & e.ItemIndex)
        e.Item = item1

    End Sub

    Private Sub ListView1_DrawItem(sender As Object, e As DrawListViewItemEventArgs) Handles ListView1.DrawItem

        '▼背景の描画 
        Dim isEven As Boolean = (e.ItemIndex Mod 2 = 0)

        If isEven Then
            '偶数インデックスの項目は背景をベージュにします。 
            e.Graphics.FillRectangle(Brushes.Beige, e.Bounds)
        End If

        '▼文字の描画 
        Dim isSelected As Boolean = ListView1.SelectedIndices.Contains(e.ItemIndex)

        If isSelected Then
            '選択されている項目は赤い字で描画します。 
            e.Graphics.DrawString(e.Item.Text, ListView1.Font, Brushes.Red, e.Bounds)
        Else
            '選択されていない項目は既定の描画を行います。 
            e.DrawText()
        End If


    End Sub

    Private Sub ListView1_MouseUp(sender As Object, e As MouseEventArgs) Handles ListView1.MouseUp

        Dim mousedItem As ListViewItem = ListView1.GetItemAt(e.X, e.Y)
        If mousedItem Is Nothing Then
            Return
        End If

        MsgBox(mousedItem.Text & " 選択時の処理")

    End Sub

End Class
投稿者 RCB  (社会人) 投稿日時 2020/7/23 19:35:37
るきお様、回答ありがとうございます
説明が足りなくてすみませんでした

まず、モードはラージアイコンです

MultiSelectの処理が特殊なため(Trueで修飾キー無しで複数選択出来るように)MouseUpで処理しています
でFalseの時は選択すると同時に直前の選択を解除しないといけない訳です
(なので選択/解除はSelectedIndeciesではなく完全に自前で管理しています)

その選択/解除の描画はDrawItemイベントで行っているのですがそのDrawItemイベントはRetrieveVirtualItemイベントがおきないと呼ばれません

そのRetrieveVirtualItemイベントがマウスクリック時に「クリック(選択)したアイテムの分しか」発生しません
ここで「選択解除したアイテムの分も」イベントが起こって欲しいわけです
(でないとDrawItemイベントが起きません)

DrawItemイベントが呼び出されさえすれば描画は出来ております
要はどうやってその余分なDrawItemを呼び出すか、なのです
直接呼び出せればいいんですけどねえ…(でもBoundsどうするの?って…)
投稿者 るきお  (社会人) 投稿日時 2020/7/23 20:25:44
要するに描画したいんですよね?
Invalidateメソッドを使うとDrawItemを呼び出すことはできますが、これでは解決しませんか?
投稿者 RCB  (社会人) 投稿日時 2020/7/23 21:39:12
すみませんでした
Invalidateでいけました
途中で一度試していたのですがチラつくので止めたのを忘れていました
お騒がせして申し訳ありませんでした