- PR -

ListBoxでのSelectedIndexChangedイベントの動作について

投稿者投稿内容
まどか
ぬし
会議室デビュー日: 2005/09/06
投稿数: 372
お住まい・勤務地: ますのすし管区
投稿日時: 2007-11-01 13:28
引用:

1.ListBoxの説明サイトを見てもフォームを閉じるときにSelectedIndexChanged
イベントは発生することは説明がありません。なぜでしょうか



「書かれていない」「書かなかった」という事実のみだと思います。

引用:

2.SelectedItem の返値(System.Data.DataRowView)は何を示しているのですか



ListBoxのItemはObject(型)です。つまりなんでも追加できます。
見た目に表示されているのは、DisplayMemberを設定しない場合、Object.ToString()の結果が採用されます。
Object.ToString()は派生先でオーバーライドしなければ型の表示用文字列が返されます。
ここら辺はリストボックスやコンボボックスの説明にちゃんと書かれていますよ。

引用:

3.返値をListBox1.Textから取得しても問題ないのでしょうか。



2を踏まえたうえで仕様上欲する値そのものであれば問題ないでしょう。
ただし、リストボックスの場合は「表示するための文字列」であることを意識してください。
処理データと表示データを区別しましょうという意味です。

たとえば、
Private Class ListData
Public P1 As String
Protected Overrides Function ToString() As String
Return P1
End Function
End Class
というクラスインスタンスをItemに追加したとします。
リストボックスにはToStringの結果が表示されます。
選択されていればTextプロパティにはそれが格納されます。

ここで、処理の仕様として「選択されたアイテムからP1を求めて〜」であるとします。
上記コードではToStringはP1そのものを返します。
つまりTextプロパティを参照しても動作することになります。
しかし、先にいった考え方でいくと
選択されたItemからListDataのインスタンスを求めてP1フィールドを参照する
というのが正解となります。
だんじり
大ベテラン
会議室デビュー日: 2007/08/10
投稿数: 155
お住まい・勤務地: 神奈川県
投稿日時: 2007-11-01 16:08
まどかさん、色々ありがとうございました。

引用:

まどかさんの書き込み (2007-11-01 13:28) より:

2を踏まえたうえで仕様上欲する値そのものであれば問題ないでしょう。
ただし、リストボックスの場合は「表示するための文字列」であることを意識してください。
処理データと表示データを区別しましょうという意味です。



この辺のことは私の力不足で、まだ理解できていませんがこれから勉強いたします。
おかげさまでフォームを閉じるときにエラー解除策が理解でき大変助かりました。
これからもよろしくお願いいたします。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2007-11-01 22:15
引用:

まどかさんの書き込み (2007-11-01 13:28) より:
引用:

1.ListBoxの説明サイトを見てもフォームを閉じるときにSelectedIndexChanged
イベントは発生することは説明がありません。なぜでしょうか


「書かれていない」「書かなかった」という事実のみだと思います。


 それはちょっと違うとおもいます。
SelectedIndexChanged は、SelectedIndex が変化した後に発生します。
フォームを閉じるときに何らかの要因で SelectedIndex が「変化する」と考えるのが妥当かと思います。

 で、この「テスト」といっているものは SelectedIndexChanged イベント ハンドラしか見ていないと思います。
ブレーク ポイントを張って止めてみたとか、メッセージ ボックスを表示させたとか。
本当にフォームを閉じることが、SelectedIndex を変更することなく SelectedIndexChanged を発生させている(だんじりさんの疑問は、この形かと思います)かどうかを確認するには、SelectedIndexChanged イベントハンドラ内でブレークし、呼び出し履歴を確認する必要があると思います。
もちろん、閉じる前にどんな値だったかもメモしておく必要があるでしょう。


引用:

だんじりさんの書き込み (2007-11-01 11:57) より:
3.返値をListBox1.Textから取得しても問題ないのでしょうか。


 だから、ちゃんと読もうよ。
引用:

ListBox.ToString メソッド<microsoft.com>より:
このメソッドは,.NET Framework インフラストラクチャをサポートします。独自に作成したコードから直接使用するためのものではありません。

文字数が 0 でない場合は、コントロールの型、ListBox コントロール内の項目数、および ListBox 内の最初の項目の Text プロパティを記述した文字列。


まどか
ぬし
会議室デビュー日: 2005/09/06
投稿数: 372
お住まい・勤務地: ますのすし管区
投稿日時: 2007-11-02 09:10
引用:

 それはちょっと違うとおもいます。



「発生することがあるよ」という記述がどこにも見受けられなかったという事実に対して
「なぜ書かれていないのか」という疑問だと理解してそのように答えました。
#対象の説明サイトが一般サイトでしたし、仕様の話ではないと理解

引用:

引用:

3.返値をListBox1.Textから取得しても問題ないのでしょうか。


 だから、ちゃんと読もうよ。



今気が付いた(汗
だんじり
大ベテラン
会議室デビュー日: 2007/08/10
投稿数: 155
お住まい・勤務地: 神奈川県
投稿日時: 2007-11-02 13:24
Jittさん、まどかさん、ありがとうございます。

引用:

Jittaさんの書き込み (2007-11-01 22:15) より:
SelectedIndexChanged は、SelectedIndex が変化した後に発生します。
フォームを閉じるときに何らかの要因で SelectedIndex が「変化する」と
考えるのが妥当かと思います。

で、この「テスト」といっているものは SelectedIndexChanged イベント ハンドラしか見ていないと思います。
ブレーク ポイントを張って止めてみたとか、メッセージ ボックスを表示させたとか。
もちろん、閉じる前にどんな値だったかもメモしておく必要があるでしょう。


テストの内容は次のように行いました。
ListBox1_SelectedIndexChangedイベント ハンドラに次のコードのみを記述し、
リストボックスの項目選択時とフォームクローズ時の内容を各TextBoxで取得しました

MessageBox.Show("SelectedIndexChangedが発生しました")
TextBox1.Text = ListBox1.SelectedIndex.ToString
If CInt(ListBox1.SelectedIndex) > -1 Then
TextBox2.Text = ListBox1.SelectedItem.ToString
TextBox3.Text = ListBox1.SelectedValue.ToString
TextBox4.Text = ListBox1.Text
Else
TextBox2.Text = "ヌルです"
TextBox3.Text = "ヌルです"
TextBox4.Text = "ヌルです"
End If

結果は次の通りです。
リストボックスの項目選択時:正常に動作
フォームクローズ時:まずメッセージが表示されて[OK]ボタンでTextBox1には
「-1」と表示されます。その他のTextBoxはエラーが発生するためスルーしています。

以上のことから次のように考えました。
1.メッセージが表示されたのはイベントが発生していることになる
2.SelectedIndexが「-1」となるのはリストボックスの選択がされていない

以上ですが、Jittさんの意見だとフォームクローズ時には、SelectedIndexの変化は
ないはずとお考えなのでしょうか。
よろしくお願いいたします。

【追記】
上記の「フォームクローズ時」はフォーム右上の「×」ボタンをクリックしています。
フォームクローズ時にElseに分岐させたのはSelectedValueの値がNullとなってエラーとなるためです。

[ メッセージ編集済み 編集者: だんじり 編集日時 2007-11-02 14:15 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2007-11-02 21:50
げ!見るところ間違ってる。。。
ちゃんと読め>Jitta

失礼いたしました。訂正。
引用:

ListBox.Text プロパティ<microsoft.com>より:
ListBox 内で現在選択されている項目のテキストを取得または検索します。

ListBox の SelectionMode プロパティが SelectionMode.MultiExtended に設定されている場合、このプロパティは、最初に選択された項目のテキストを返します。ListBox の SelectionMode プロパティが SelectionMode.None 以外の値に設定されている場合も、このプロパティは、最初に選択された項目のテキストを返します。


項目がひとつしか選択できないなら、Text プロパティから取って良い、ということです。


引用:

だんじりさんの書き込み (2007-11-02 13:24) より:
以上ですが、Jittさんの意見だとフォームクローズ時には、SelectedIndexの変化は
ないはずとお考えなのでしょうか。
よろしくお願いいたします。


 少々卑怯なことをしています。
私は「Form を閉じるときに SelectedIndex は変わらない」とは言っていません。
そうではなく、「SelectedIndexChanged が発生するのは SelectedIndex が変わるときだ」としか書いておらず、Form が閉じるときにそうなるかどうかは断定していません。
しかし、その現象を調べるための方法が、だんじりさんの方法では正しくないと書いています。

 Form を閉じるときに、何らかの作用で SelectedIndex が変化するなら、変化したというイベントが上がるのは当然です。
それを調べるために、「SelectedIndexChanged イベント ハンドラ内でブレークし、呼び出し履歴を確認する必要があると思います。」と、書いています。

 これは憶測ですが、
Form を閉じると、Close から Dispose が(場合によって)呼ばれます。このときに、自身が持っている Control 類を、先に Dipose しているでしょう。
このときに、ListBox.Items から、オブジェクトを削除していると思います。
選択すべきものが無くなるので、当然 SelectedIndex が変化しますよね?
これをキャッチしているのではないでしょうか。


 他のスレッドでも、「結果をそのまま受け入れるのではなく、結果に至った理由を考える」と書きました。
このスレッドでの結果は、「Form を閉じるときに SelectedIndex が変化する」です。
この結果をそのまま受け入れるのではなく、なぜ変化するのかを調べておけば、後々疑問が出てきたときに、この調査結果から類推することができます。
 私は、「憶測ですが」と書いているように、上記の現象を確認しているわけではありません。
しかし、オブジェクトが破棄される順番については、以前に調べたことがあるので、そのことから類推して、ListBox が破棄される直前に、抱えているアイテムから参照を外すため、その時に発生するのではないか、と推測するわけです。
すると、その推測が正しいかどうかを確かめれば、疑問は解決します。
その方法が、「SelectedIndexChanged イベントハンドラ内でブレークし、呼び出し履歴を確認する」ということです。

 ここまで書いておいて、VS.NET 2003 C# でプロジェクトを作成してみました。
結果、イベントは発生しませんでした。
だんじりさんの所では発生するのなら、結果が異なります。このことから、結果だけをそのまま受け入れてはいけないと、もう一度書いておきます。
結果を引き起こす環境にも、注意が必要です。
 アイテムの追加の方法などが関係していることが考えられます。
私は、Form 上に ListBox をひとつおき、デザイナでアイテムを追加しました。
だんじり
大ベテラン
会議室デビュー日: 2007/08/10
投稿数: 155
お住まい・勤務地: 神奈川県
投稿日時: 2007-11-03 10:05
Jittaさん、お返事ありがとうございます。
私の質問が悪かったのでしょうか。Jittaさんもおっしゃるように「結果だけをそのまま
受け入れてはいけない」と思い、もともとのSelectedIndexChangedイベントについての
仕様をご存知ならと、以下の質問をしたつもりでした。
1.フォームクローズ時(IndexChangedして)にイベントを発生する。
2.フォームクローズ時(IndexChangedして)にイベントは発生しない。
3.発生の有無は知らないが、イベントの発生はIndexChangedだ。

貴重なテストをしていただきありがとうございました。Jittaさんの意見は3番であった
ことが分りました。そしてJittaさんのテスト結果から判断しますと

1.フォームクローズ時はIndexChangedはなくイベントは発生しない。
2.原因は私のPC環境によるものらしい。
ということになりそうですね。ありがとうございました。


私のテストによれれば、まどかさんからご指導いただいた
1.フォームクローズ時、IndexChangedがありイベントを発生する。
となっています。

結果だけを鵜呑みにしないで、これからJittaさんの方法(Form 上に ListBox をひとつ
おき、デザイナでアイテムを追加アイテムの追加の方法)と私の方法(テーブルをアイ
テムとして設定する方法)について調べてみて、結果を報告します。

Jittaさん、大変ありがとうございました。
だんじり
大ベテラン
会議室デビュー日: 2007/08/10
投稿数: 155
お住まい・勤務地: 神奈川県
投稿日時: 2007-11-03 11:51
テスト結果を報告します。
テストは新しいプロジェクトを作成して、1個のForm 上に 次のような ListBox1
と ListBox2 を配置し、両方のListBoxにSelectedIndexChangedイベントを設け、
そのイベントハンドラにそれぞれ次のMessageBox のみを記述しました。

1.ListBox1
DataSource: A_BindingSource
DisplayMenber:項目名
イベントハンドラ記述→MessageBox.Show("ListBox1_SelectedIndex: " & _
ListBox1.SelectedIndex)

2.ListBox2
デザイナでItems のコレクションにアイテムを記述(シマリス、ニホンリス、ヨーロッパアカリス)
イベントハンドラ記述→MessageBox.Show("ListBox2_SelectedIndex: " & _
ListBox2.SelectedIndex)

以上の設定でデバッグしたところ、項目の選択では両方とも正常にSelectedIndex が
表示されました。
続いてフォームを画面右上の「×」で閉じるとListBox1だけが次のように表示され、
ListBox2 のMessageBoxは表示されません。
→「ListBox1_SelectedIndex: -1」

ちなみにListBox2 側のアイテムを ListBoxA_Load時に次のようにItems.Add で設定して
同じテストを行いました。
ListBox2.Items.Add("シマリス")
ListBox2.Items.Add("ニホンリス")
ListBox2.Items.Add("ヨーロッパアカリス")

テスト結果は同じようにフォームを閉じる時はListBox1 のMessageBoxが「-1」と表示され、ListBox2 側は表示されません。
Jittaさんの言われたとおり、アイテムの設定方法によって、フォームを閉じる時の
SelectedIndexChangedイベント動作が違っているのかもしれません。
以上、取り急ぎテスト結果を報告しました。

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