トップ回答者
ListViewでの選択行変更キャンセルについて

質問
-
初めて質問させていただきます。
ListViewで、選択行が変更されたことをSelectedIndexChangedイベントで判断して、「選択を変更してよろしいですか?」という確認ダイアログを表示し、
このダイアログに対してキャンセルlボタンが押下された場合は選択を変更前の行に戻すという処理を行いたいと思っています。
選択を戻すために次のような処理を行っていますが、listView1.Items[index].Selected = trueのところでもう一度SelectedIndexChangedイベントが発生してしまい、
「選択を変更してよろしいですか?」のダイアログが2度表示されてしまいます。
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
---- 略 ----
if (MessageBox.Show("選択を変更してよろしいですか?", "確認", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
{
listView1.Items[previousIndex].Selected = true;
listView1.Items[previousIndex].Focused = true;
}
}
ListViewのMultiSelectはfalse、
開発環境はVisualC#2008です。
ダイアログが一度しか表示されないようにするための、
何か方法がございましたらアドバイスいただけると幸いです。
よろしくお願い致します。
回答
-
ComboBox.SelectionChangeCommitted イベント
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.combobox.selectionchangecommitted(VS.80).aspxに、
「SelectedIndexChanged イベントと SelectedValueChanged イベントは、プログラム上で選択項目が変更されたときにも発生するため、ユーザーによる変更をキャプチャする目的でこれらのイベントを使用しないでください。」
と書かれています。ListViewでも同様の動作をするため、SelectedIndexChangedイベント内で選択行を操作するのは推薦されないでしょう。
以下にItemActivateイベントを使った例がありますので、参考になるのではないかと思います。ListViewで行選択変更をキャンセルしたい
http://bbs.wankuma.com/index.cgi?mode=al2&namber=11713&KLOG=25
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
すべての返信
-
選択を戻すために次のような処理を行っていますが、listView1.Items[index].Selected = trueのところでもう一度SelectedIndexChangedイベントが発生してしまい、
イベントの中で、previousIndex と今回選択されたインデックスが一致しているかどうか判定したらどうでしょうか?(2度目のイベントでは一致しているはず)
「選択を変更してよろしいですか?」のダイアログが2度表示されてしまいます。
なお、if ブロックの中では return と書いておいて、previousIndex が変化しないようにする工夫が必要かも知れません。
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。 -
ComboBox.SelectionChangeCommitted イベント
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.combobox.selectionchangecommitted(VS.80).aspxに、
「SelectedIndexChanged イベントと SelectedValueChanged イベントは、プログラム上で選択項目が変更されたときにも発生するため、ユーザーによる変更をキャプチャする目的でこれらのイベントを使用しないでください。」
と書かれています。ListViewでも同様の動作をするため、SelectedIndexChangedイベント内で選択行を操作するのは推薦されないでしょう。
以下にItemActivateイベントを使った例がありますので、参考になるのではないかと思います。ListViewで行選択変更をキャンセルしたい
http://bbs.wankuma.com/index.cgi?mode=al2&namber=11713&KLOG=25
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/ -
> クリックの場合は、選択が入る時と外れるときの二回イベントが呼ばれていることが原因かと考えています。
これについて少し考えてみました。
(結局わからなかったんですが。。)イベントの発生について実験してみると
イベントメソッド内での設定はコメント化しても
SelectedIndexChanged が2回発生します。
↓イベント発生順。
listView1_MouseClick
listView1_MouseDown
listView1_SelectedIndexChanged
listView1_SelectedIndexChanged
listView1_MouseUp似たようなイベントで ItemSelectionChanged があります。
こちらは引数で Select が false か true かがわかります。
これについて実験してみると。
false の true の組み合わせが 2回発生します。(計4回)なんとなく、セレクト (アイテムの周囲が点で囲まれる)と
フォーカス(アイテムが反転表示)の2つの状態が存在していることが
原因として考えられるかと思いましたが、
それだとカーソルキーで移動したときとの動作の違いが説明できません。。 -
こんばんは。
処理中かどうか判断するフィールドを使用するという手はどうでしょう?
private bool _isChanging = false;
---- 略 ----
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (this._isChanging)
{
return;
}
this._isChanging = true;
---- 略 ----
if (MessageBox.Show("選択を変更してよろしいですか?", "確認", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
{
listView1.Items[previousIndex].Selected = true;
listView1.Items[previousIndex].Focused = true;
}
---- 略 ----
this._isChanging = false;
}
あるいは、試していないので不確かではあるのですが
listView1.BeginUpdate()で描画を中断しておけば、SelectedIndexChangedイベントが
2度発生することがなかったりしませんか?
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
listView1.BeginUpdate();
---- 略 ----
if (MessageBox.Show("選択を変更してよろしいですか?", "確認", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
{
listView1.Items[previousIndex].Selected = true;
listView1.Items[previousIndex].Focused = true;
}
---- 略 ----
listView1.EndUpdate();
}