VB2008.NETのListViewにおけるItemSelectionChangedイベントで質問です。


ShiftキーやCtrl+Aで複数のitemをまとめて選択した場合、
まとめて選択される過程の一つ一つでItemSelectionChangedイベントが発生しています。
現在発生しているItemSelectionChangedイベントが、この過程のうち
「最後の一つかどうかを認識する方法」をご存知の方、アドバイスをいただければ幸いです。

といいますのは、選択内容にあわせたHTMLファイル書き出しを行う処理をしているのですが
出力させたいのは「選択された内容にあわせて」であって「選択過程の内容にあわせて」では
ないにもかかわらず、この方法がわからないので処理が重くなって悩んでいるからです。

よろしくお願いいたします。

回答の条件
  • URL必須
  • 1人2回まで
  • 13歳以上
  • 登録:2010/04/26 14:06:47
  • 終了:2010/04/26 21:05:18

ベストアンサー

id:khazad-Lefty No.2

khazad-Lefty回答回数181ベストアンサー獲得回数272010/04/26 20:32:02

ポイント52pt

まず、

ListView.SelectedIndices プロパティ (System.Windows.Forms)

から考えると、このイベントで「最後の一つかどうか」を判断することはできないと考えられます。

(そのような情報を判断するフラグなどの記述がない)

>選択内容にあわせたHTMLファイル書き出しを行う処理をしているのですが

これって、選択内容が変更されるたびにその都度書き出しを行う必要があるのでしょうか?

「最後の一つかどうか」を認識できたとしても、

たとえば、Ctrlキーで複数選択した場合や、Shift+下矢印などで、は、

結局行をクリックして選択範囲を増やす度に書き出しが行われるわけで、

選択途中の意図しないHTML出力が行われるのは避けられないのですが、

それは問題ないのでしょうか?

素直に考えると、選択とは別に「HTML書き出し」のボタンを用意して、

その時に、ListView.SelectedIndices を参照して、選択列を取得するのが自然じゃないかと思うのですが。

(スペックにもよりますが、その方が使用者のストレスは少なくなる気もします)

「最後の一つかどうか」を判断できないというのは、それが必要な状況が考えにくいからということでもあると思います。


で、どうしても書出しボタンは用意できないというのであれば、

たとえば「最後の選択変更から0.2秒後に書出し処理を行う」という形で、

Timerコントロール(System.Windows.Timer)を利用する方法が考えられます。

Timer クラス (System.Windows.Forms)

マルチスレッドとか考えなくても良さそうだし。

Private Sub ListView1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListView1.SelectedIndexChanged
  timer1.stop()
  timer1.Interval=200  '<-この行はなくてもいいかも
  timer1.start()
End Sub

private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1_Tick
	timer1.stop()
	'(やりたい処理)
end sub

これなら選択する度にタイマーにリセットがかかるので、

処理は軽くなるんじゃないかと思います。

id:halohalolin

khazad-Leftyさん、コメントでタイマーを指摘してくださったtakntさんありがとうございます。

教えて頂いた方法でかなり高速化になりました。ありがとうございます。

ファイルの書き換え処理は、webbrowserコンポーネントで表示する画面の書き換えで使いたかったのですが

自分で書き換え部分をbackgroundコンポーネントでスレッド化したときに、webbrowserコンポーネントに関連する

例外が多発して挫折した経験がありました。

その為Timerクラスを折角提示していただいても、てっきり形を変えたスレッド処理だと

思いこんでいたのですが、食わず嫌いはいけないですねorz

本当にありがとうございました!

2010/04/26 21:04:58

その他の回答(1件)

id:HALSPECIAL No.1

HALSPECIAL回答回数407ベストアンサー獲得回数862010/04/26 17:34:06

ポイント18pt

ListView.SelectedIndexChanged イベント


上記リンクのVBサンプル中のSelectedIndexChangedイベントの記述にある通り、選択された複数行をコレクションとして取得可能な様です。

Private Sub ListView1_SelectedIndexChanged_UsingItems _
    (ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles ListView1.SelectedIndexChanged

    Dim breakfast As ListView.SelectedListViewItemCollection = _
        Me.ListView1.SelectedItems
    Dim item As ListViewItem
    Dim price As Double = 0.0
    For Each item In breakfast
        price += Double.Parse(item.SubItems(1).Text)
    Next

    ' Output the price to TextBox1.
    TextBox1.Text = CType(price, String)
End Sub



内容は確かではありませんが、こんな感じでしょうか。

順番が期待通りでなければ、SORTの処理を入れることになります。

Private Sub ListView1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListView1.SelectedIndexChanged

    Dim myitems As ListView.SelectedListViewItemCollection = Me.ListView1.SelectedItems
    If myitems.Count = 0 Then Exit Sub

    Dim strMakerComment() As String = New String(myitems.Count) {}
    Dim i As Integer

    i = 0
    For Each datItem As ListViewItem In myitems
        strMakerComment(i) = "X = " & datItem.SubItems(enmListView1.X).Text & " Y = " & datItem.SubItems(enmListView1.X).Text & vbCrLf
        i += 1
    Next
    Array.Resize(strMakerComment, i + 1)

    If strMakerComment.Length > 0 Then
        vidFileReflesh(strMakerComment) ' ここでファイル書き出し
    End If

End Sub

id:halohalolin

HALSPECIALさん、毎度ありがとうございます。

ご提案して頂いたコードでは、ListView1の中身を10件選択した場合、私がコメントで提示したプログラムと同様に

vidFileReflesh(strMakerComment)が10回呼び出されないでしょうか?

私は「選択された内容にあわせて」vidFileReflesh(strMakerComment)が1回のみ書き出し処理を

行うようにできれば、今回の件は大幅にスピードアップするのではないかと考えています。

しかし、その方法が今のところわからないので質問しています。

質問文がわかりづらくてお手数をお掛けしていますが、よろしくお願いいたします。

2010/04/26 17:53:00
id:khazad-Lefty No.2

khazad-Lefty回答回数181ベストアンサー獲得回数272010/04/26 20:32:02ここでベストアンサー

ポイント52pt

まず、

ListView.SelectedIndices プロパティ (System.Windows.Forms)

から考えると、このイベントで「最後の一つかどうか」を判断することはできないと考えられます。

(そのような情報を判断するフラグなどの記述がない)

>選択内容にあわせたHTMLファイル書き出しを行う処理をしているのですが

これって、選択内容が変更されるたびにその都度書き出しを行う必要があるのでしょうか?

「最後の一つかどうか」を認識できたとしても、

たとえば、Ctrlキーで複数選択した場合や、Shift+下矢印などで、は、

結局行をクリックして選択範囲を増やす度に書き出しが行われるわけで、

選択途中の意図しないHTML出力が行われるのは避けられないのですが、

それは問題ないのでしょうか?

素直に考えると、選択とは別に「HTML書き出し」のボタンを用意して、

その時に、ListView.SelectedIndices を参照して、選択列を取得するのが自然じゃないかと思うのですが。

(スペックにもよりますが、その方が使用者のストレスは少なくなる気もします)

「最後の一つかどうか」を判断できないというのは、それが必要な状況が考えにくいからということでもあると思います。


で、どうしても書出しボタンは用意できないというのであれば、

たとえば「最後の選択変更から0.2秒後に書出し処理を行う」という形で、

Timerコントロール(System.Windows.Timer)を利用する方法が考えられます。

Timer クラス (System.Windows.Forms)

マルチスレッドとか考えなくても良さそうだし。

Private Sub ListView1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListView1.SelectedIndexChanged
  timer1.stop()
  timer1.Interval=200  '<-この行はなくてもいいかも
  timer1.start()
End Sub

private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1_Tick
	timer1.stop()
	'(やりたい処理)
end sub

これなら選択する度にタイマーにリセットがかかるので、

処理は軽くなるんじゃないかと思います。

id:halohalolin

khazad-Leftyさん、コメントでタイマーを指摘してくださったtakntさんありがとうございます。

教えて頂いた方法でかなり高速化になりました。ありがとうございます。

ファイルの書き換え処理は、webbrowserコンポーネントで表示する画面の書き換えで使いたかったのですが

自分で書き換え部分をbackgroundコンポーネントでスレッド化したときに、webbrowserコンポーネントに関連する

例外が多発して挫折した経験がありました。

その為Timerクラスを折角提示していただいても、てっきり形を変えたスレッド処理だと

思いこんでいたのですが、食わず嫌いはいけないですねorz

本当にありがとうございました!

2010/04/26 21:04:58
  • id:halohalolin
    なお、現在悩んでいる低速なコードのサンプルは以下の通りです。

    ' リスト項目を選択
    Private Sub ListViewItemSelectionChanged(Optional ByVal sender As Object = Nothing, Optional ByVal e As System.Windows.Forms.ListViewItemSelectionChangedEventArgs = Nothing) Handles ListView.ItemSelectionChanged

    if ListView.SelectedItems Is Nothing Then
    return
    End If

    Dim strMakerComment() As String = New String(ListView.SelectedItems.Count) {}
    Dim i As Integer

    i = 0
    For Each datItem As ListViewItem In ListView.SelectedItems
    strMakerComment(i) = "X = " & datItem.SubItems(enmListView.X).Text & " Y = " & datItem.SubItems(enmListView.X).Text & vbCrLf
    i += 1
    Next
    Array.Resize(strMakerComment, i + 1)

    if strMakerComment.count > 0 Then
    vidFileReflesh(strMakerComment) ' ここでファイル書き出し
    End If

    End Sub

    ※即席でオリジナルから修正したコードなので、もし誤りがあればご指摘ください。
  • id:taknt
    最後のひとつってのは 難しいと思う。

    それより、タイマイベントを 用いて 選択始めたら 1秒毎とかに
    反映させれば いいんじゃないかなぁ?
    1秒で 遅いようだったら 0.5秒とか。
  • id:halohalolin
    taknt さんありがとうございます。

    スレッド処理は私の経験値不足もあり、これまでも呼出元関連の例外が多発して苦しんできました。
    そのため、できれば避けたいな・・・と思っているのですが、避けられないんですかね。

    参考にさせていただきます。
  • id:HALSPECIAL
    HALSPECIAL 2010/04/26 22:57:25
    >vidFileReflesh(strMakerComment)が10回呼び出されないでしょうか?
    はい。私の勘違いでなければ1度のみだと思います。


    ListViewItemSelectionChanged でなく、
    ListView.SelectedIndexChanged イベントなので。
  • id:halohalolin
    HALSPECIALさん何度もありがとうございます。

    SelectedIndexChangedに気がつきませんでした。
    早速試してみます。
  • id:HALSPECIAL
    HALSPECIAL 2010/05/06 16:22:24
    ポイントありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません