C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: 別スレッドからListViewに要素を追加したい


(過去ログ 113 を表示中)

[トピック内 3 記事 (1 - 3 表示)]  << 0 >>

■67028 / inTopicNo.1)  別スレッドからListViewに要素を追加したい
  
□投稿者/ 酢吉 (1回)-(2013/06/21(Fri) 11:53:38)

分類:[.NET 全般] 

VB2008Express XP32bit使用のコピペプログラマです

FormにListViewとButtonを設置し、文字列配列をListView渡して文字列を表示させようとしていますが
別スレッドから配列を渡そうとするとき、TextBoxにTextプロパティを設定するときのようにしても
 TargetParameterCountExceptionはハンドルされませんでした。
 パラメーターカウントが一致しません。
というエラーが発生してうまくいきません。
検索してもItems.Addについてはコピペさせていただけるソースが見つからずおのれの限界を感じています。
どこを直せばよいのでしょうか?
ListView1.Items.AddのパラメータをNew ListViewItem(ar)としていますが、これ以外のパラメータが必要なんでしょうか?



以下ソース

Imports System.Threading
Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim arr(0) As String

        'ListView1を初期化
        Call InitializeListView()

        'テキトーな配列を生成
        For i As Integer = 0 To 5
            ReDim Preserve arr(i)
            arr(i) = Format(i * 10, "0000")
        Next

        'AddList1に配列を渡す これはうまくいく
        Call AddList1(arr)

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'Class1のオブジェクト参照を保持
        Dim cl1 As New Class1(Me)

        'Class1.testをスレッド化
        Dim Thread1 As New System.Threading.Thread(New System.Threading.ThreadStart(AddressOf cl1.test))

        'バックグラウンドで実行する
        Thread1.IsBackground = True

        'スレッドの開始
        Thread1.Start()

    End Sub

    'リストビューの初期化
    Private Sub InitializeListView()

        ' ListViewコントロールのプロパティを設定
        ListView1.FullRowSelect = True
        ListView1.GridLines = True
        ListView1.Sorting = SortOrder.Ascending
        ListView1.View = View.Details

        ' 列(コラム)ヘッダの作成
        Dim columnA = New ColumnHeader
        Dim columnB = New ColumnHeader
        Dim columnC = New ColumnHeader
        Dim columnD = New ColumnHeader
        Dim columnE = New ColumnHeader
        Dim columnF = New ColumnHeader

        columnA.Text = "列A"
        columnB.Text = "列B"
        columnC.Text = "列C"
        columnD.Text = "列D"
        columnE.Text = "列E"
        columnF.Text = "列F"

        'ヘッダーを設定
        Dim colHeaderRegValue() As ColumnHeader = {columnA, columnB, columnC, _
                                                   columnD, columnE, columnF}
        ListView1.Columns.AddRange(colHeaderRegValue)

    End Sub

    '一次元配列を受けてListViewに要素を追加する(Delegateするメソッド)
    Public Sub AddList1(ByRef ar() As String)

        '配列をListView1にAdd
        Me.ListView1.Items.Add(New ListViewItem(ar))

    End Sub

End Class

Imports System.Threading
Public Class Class1

    'フォームの参照を保持する
    Private _Form1 As Form1

    'コントロールを扱うためのデリゲート宣言
    Delegate Sub AddList1Delegate(ByRef ar() As String)

    'デリゲート宣言をデータ型とした変数を作成
    Private List1Delegate As AddList1Delegate

    Private ar(0) As String

    'コンストラクタ
    Public Sub New(ByVal frm As Form)

        _Form1 = CType(frm, Form1)

    End Sub

    Public Sub test()

        '文字列の配列を適当に生成
        For i As Long = 0 To 5
            ReDim Preserve ar(i)
            Debug.Print(i)
            ar(i) = Format(i, "0000")
        Next

        List1Delegate = New AddList1Delegate(AddressOf _Form1.AddList1)

        '配列をAddList1に渡す  ここでエラー発生
        _Form1.Invoke(List1Delegate, ar)

    End Sub


End Class



引用返信 編集キー/
■67029 / inTopicNo.2)  Re[1]: 別スレッドからListViewに要素を追加したい
□投稿者/ Hongliang (62回)-(2013/06/21(Fri) 12:25:41)
ある型の配列は、親(先祖)の型の配列として代入したり引数に渡すことができます。
StringはObjectを継承する型なので、こんな代入ができます。
Dim objs As Object() = New String() { "a", "b", "c" }

// ただしIntegerなど構造体の配列ではできない。

さて、Control.Invokeの宣言はこんな形です。
Public Function Invoke (method As Delegate, ParamArray args As Object()) As Object
ParamArrayは可変長引数を意味し、コンパイラによって自動的に配列に変換されて引数に渡されます。
例えば
Invoke(hogeDelegate, "a", "b")
はコンパイラによって
Invoke(hogeDelegate, New Object() { "a", "b" })
とコンパイルされ、実行されます。

ParamArrayの引数に直接Object()を渡すこともできます。
Dim objs As Object() = { "a", "b" }
Invoke(hogeDelegate, objs)
これは一つ前のInvoke(hogeDelegate, "a", "b")と全く同じ動作になります。


ではこのargsパラメータにString()を渡した場合どうなるでしょうか?
ここで、冒頭で述べた動作が出てきます。
つまり、
Dim strs As String() = { "a", "b" }
Invoke(hogeDelegate, strs)
は、strsがObject()として扱えるために、
Invoke(hogeDelegate, objs)
と同じに扱われます。
その結果、hogeDelegateに渡される引数は、String()が一つではなく、Stringが2つということになります。
Delegate Sub hogeDelegate(strs AS String()) ' ←想定していたデリゲート
Delegate Sub hogeDelegate(strA AS String, strB As String) ' ←実際に渡された引数

配列一つをParamArray Object()に渡す場合は
Invoke(hogeDelegate, New Object() { strs })
のように明示的にObject()を作るのが安全です。
こうすれば、引数は「String()が一つ」であることがはっきりします。

引用返信 編集キー/
■67031 / inTopicNo.3)  Re[2]: 別スレッドからListViewに要素を追加したい
□投稿者/ 酢吉 (3回)-(2013/06/21(Fri) 12:56:37)
2013/06/21(Fri) 12:57:18 編集(投稿者)

> 配列一つをParamArray Object()に渡す場合は
> Invoke(hogeDelegate, New Object() { strs })
> のように明示的にObject()を作るのが安全です。
> こうすれば、引数は「String()が一つ」であることがはっきりします。


できました超ありがとうございます
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -