- PR -

ListBoxの項目を選択した時、ArgumentOutOfRangeが発生する

投稿者投稿内容
いつき
会議室デビュー日: 2004/01/08
投稿数: 9
お住まい・勤務地: 神奈川県
投稿日時: 2004-03-04 13:25
ゆうじゅんさんのおっしゃるように、再現できる操作は以下ですね。
私の最初の投稿のでは残り1個を選択した時とか書いてますが、残りの個数は関係ないようです。

[再現手順]
ListBoxの最後の項目を選択し、移動処理を実行(ボタンクリック)
移動元となったListBoxの項目を選択。
ゆうじゅん
ぬし
会議室デビュー日: 2004/01/16
投稿数: 347
投稿日時: 2004-03-04 13:27
C#で申し訳ありませんが、以下のようにソースを直したところ解決できました。

コード:
foreach( int index in listBox1.SelectedIndices )
{
	// 選択状態をクリア
	listBox1.SetSelected( index, false );
	// 項目を取得
	string s = (string)listBox1.Items[index];
	// 自リストから削除
	a1.Remove( s );
	// 相手リストへ追加
	a2.Add( s );
}



やはり直前の選択状態が残ってしまっていたためにおかしくなったと思われます。
いつき
会議室デビュー日: 2004/01/08
投稿数: 9
お住まい・勤務地: 神奈川県
投稿日時: 2004-03-04 14:23
ゆうじゅんさんのコードをVBで下記のように書いてみました。
コード:
' ←ボタン
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    Dim s As String
    ' 移動元の選択項目を一件ずつ移動先へ移動
    For Each index As Integer In Me.ListBox2.SelectedIndices
        ' 移動元の選択状態を解除
        Me.ListBox2.SetSelected(index, False)
        ' DataSource指定の時はListBox.ItemのIndex指定が使えない?
        s = CStr(al2.Item(index))
        ' 移動先へ加える
        al1.Add(s)
        ' 移動元から削除
        al2.Remove(s)
    Next
    ' 移動先のDataSource指定
    Me.ListBox1.DataSource = Nothing
    Me.ListBox1.DataSource = al1
    ' 移動元のDataSource指定
    Me.ListBox2.DataSource = Nothing
    Me.ListBox2.DataSource = al2
End Sub



最後の項目を移動することで出ていたエラーは出なくなりました。
しかし、最初のように複数件(11〜19)選択して移動するとOutOfRangeが出てしまいました。

今回はコードの中で発生しているみたいなので追ってみると、選択したIndexは1〜9なのに飛び飛び(1,3,5,7)になっています。(ちなみにエラーの発生はIndex=7の時です)
削除したことでIndexが変わっているのでしょうか?
追加と削除を分けて、以下のようにも試してみました。

コード:
' ←ボタン
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    Dim s As String
    ' 移動元の選択項目を一件ずつ移動先へ移動
    For Each index As Integer In Me.ListBox2.SelectedIndices
        ' DataSource指定の時はListBox.ItemのIndex指定が使えない?
        s = CStr(al2.Item(index))
        ' 移動先へ加える
        al1.Add(s)
    Next
    For Each index As Integer In Me.ListBox2.SelectedIndices
        ' 移動元の選択状態を解除
        Me.ListBox2.SetSelected(index, False)
        ' 移動元から削除
        al2.RemoveAt(index)
    Next
    ' 移動先のDataSource指定
    Me.ListBox1.DataSource = Nothing
    Me.ListBox1.DataSource = al1
    ' 移動元のDataSource指定
    Me.ListBox2.DataSource = Nothing
    Me.ListBox2.DataSource = al2
End Sub



この例では追加はうまくいきますが、削除のループでエラーが発生します。(やはりIndexが飛び飛びになります)
選択項目を削除する方法が問題のようですね。
問題の起こらない方法ってどのようにしたらよいでしょうか…?
_________________
ゆうじゅん
ぬし
会議室デビュー日: 2004/01/16
投稿数: 347
投稿日時: 2004-03-04 14:46
こちらでもきちんと確認すればよかったですね。申し訳ない
↓のように変更したらきちんと動くはずです。
コード:
    ' 移動元の選択項目を一件ずつ移動先へ移動
    For Each index As Integer In Me.ListBox2.SelectedIndices
        ' DataSource指定の時はListBox.ItemのIndex指定が使えない?
        s = CStr(al2.Item(index))
        ' 移動先へ加える
        al1.Add(s)
        ' 移動元から削除
        al2.Remove(s)
    Next
    ' 選択状態を解除
    For Each index As Integer In Me.ListBox2.SelectedIndices
        ' 移動元の選択状態を解除
        Me.ListBox2.SetSelected(index, False)
    Next


いつき
会議室デビュー日: 2004/01/08
投稿数: 9
お住まい・勤務地: 神奈川県
投稿日時: 2004-03-04 16:54
ゆうじゅんさんのコードを実行したところ、やはりエラーが出てしまいました。
該当箇所は↓です。
コード:
s = CStr(al2.Item(index))


今回は、Indexは1,2,3…と増えていったのですが、帰ってくる値sが、飛び飛びでした。
また、追加と削除と選択解除をそれぞれ別ループにしても、削除のループでエラーが発生します。
画面で11〜19を選択し、移動した時のそれぞれの値を下に記します。

コード:
帰ってきてほしい状態
Index	s
1		"11"
2		"12"
3		"13"
4		"14"
5		"15"
…		…
9		"19"

現在の状態
Index	s
1		"11"
2		"13"
3		"15"
4		"17"
5		"19"
6		エラー発生



コレクションを後ろから回せれば解決できると思うのですが、そういった方法(For NextのStepのような)はないものでしょうか?
ゆうじゅん
ぬし
会議室デビュー日: 2004/01/16
投稿数: 347
投稿日時: 2004-03-04 18:28
いろいろ試してみましたがデータ連結しないで自前でListBoxを生成したほうが
簡単だと思います。

データ連結しているArrayListからデータが削除されているが選択情報は残ったままに
なっているのが直接的な原因のようです。これを解消するために選択情報を初期化
しようとあれこれやってみましたが、データ連結しているためListBoxの内容を
自由に変更できないため簡単には初期化できなさそうです。

お力にならず、申し訳ありませんでした。

(自前でListBoxを生成する場合)
コード:
// ListBoxにArrayListの内容を反映
private void BindListData( ListBox list, ArrayList a )
{
	// 選択情報をクリア
	list.ClearSelected();
	// 項目をクリア
	list.Items.Clear();
	// ArrayListの内容をListBoxに追加
	foreach( string s in a )
	{
		list.Items.Add( s );
	}
}

private void button1_Click(object sender, System.EventArgs e)
{
	foreach( string s in listBox1.SelectedItems )
	{
		a1.Remove( s );
		a2.Add( s );
	}

	BindListData( listBox1, a1 );
	BindListData( listBox2, a2 );
}

いつき
会議室デビュー日: 2004/01/08
投稿数: 9
お住まい・勤務地: 神奈川県
投稿日時: 2004-03-05 02:55
引用:
いろいろ試してみましたがデータ連結しないで自前でListBoxを生成したほうが
簡単だと思います。



そうですね。代案は(まだ動作確認していませんが)それでいこうと思います。

引用:
お力にならず、申し訳ありませんでした。



いえ、とんでもない。丸一日お付き合いくださったおかげで、いろいろ勉強になりました。
ありがとうございます。

スキルアップ/キャリアアップ(JOB@IT)