質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

Q&A

4回答

2994閲覧

FormアプリケーションのListViewのSelectedIndexChangedのハンドラでSelectedIndexを変更したいがうまくいかない。

abroad128

総合スコア60

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

0グッド

0クリップ

投稿2021/04/05 11:24

編集2021/04/05 11:36

FormアプリケーションにListView(MultiSelect=false)を追加して下記コードを実行して、SelectedIndexをマウスで変えた時に、クリックしたアイテムが一瞬選択状態になった後に選択が解除されてしまいます。
想定では普通にクリックしたアイテムが選択状態になると思ったのですが、原因は何でしょうか。

C#

1using System; 2using System.Collections.Generic; 3using System.ComponentModel; 4using System.Data; 5using System.Drawing; 6using System.Linq; 7using System.Text; 8using System.Threading.Tasks; 9using System.Windows.Forms; 10 11namespace WindowsFormsApp9 12{ 13 public partial class Form1 : Form 14 { 15 private int disableEventCounter = 0; 16 17 public Form1() 18 { 19 InitializeComponent(); 20 } 21 22 private void Form1_Load(object sender, EventArgs e) 23 { 24 func(); 25 } 26 27 private void func() 28 { 29 var selectedIndex = listView1.SelectedItems.Count > 0 ? listView1.SelectedIndices[0] : -1; 30 31 if (selectedIndex != -1) 32 disableEventCounter++; 33 listView1.Items.Clear(); 34 35 listView1.Items.Add("aaaaaaaaaaa"); 36 listView1.Items.Add("bbbbbbbbbbb"); 37 listView1.Items.Add("ccccccccccc"); 38 39 if (selectedIndex != -1) 40 { 41 disableEventCounter++; 42 listView1.SelectedIndices.Add(selectedIndex); 43 } 44 } 45 46 private void listView1_SelectedIndexChanged(object sender, EventArgs e) 47 { 48 Console.WriteLine("enter"); 49 if (disableEventCounter > 0) 50 { 51 disableEventCounter--; 52 return; 53 } 54 55 Console.WriteLine("pass"); 56 57 func(); 58 } 59 } 60} 61

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

目的の達成方法を考えて頂き嬉しいのですが、どちらかと言うと質問文のコードがうまくいかない原因を知りたいという勉強的な理由なのでそちらの回答も頂けると嬉しいです。

https://docs.microsoft.com/ja-jp/dotnet/desktop/winforms/controls/how-to-select-an-item-in-the-windows-forms-listview-control?view=netframeworkdesktop-4.8

に書いてあるように選択項目に対してフォーカスを移さないと駄目だと思います。
なので下記部分を

C#

1listView1.SelectedIndices.Add(selectedIndex);

下記のようにすると正しく動作します

C#

1listView1.Items[selectedIndex].Focused = true; 2listView1.Items[selectedIndex].Selected = true;

また、カウンターを使用してイベントの無効化を行うと私的には関数外での変数等を使用するのでバグを生みやすいと感じます。
ここで行いたいのは

 リストの再構築時はSelectedIndexChangedを発生させたくない

ということだと思うので下記のようにイベント自体の 紐づけ/解除 をする方法もありだと思いますがどうでしょうか?
また、SelectedIndicesで選択されたIndexを取得しているのに選択項目があるかどうかはSelectedItemsを使用するというのはよくないと思うのでそちらも統一したほうがいいと思います。

C#

1private void Form1_Load(object sender, EventArgs e) { 2 func(); 3} 4 5private void func() { 6 7 var selectedIndex = listView1.SelectedIndices.Count > 0 ? listView1.SelectedIndices[0] : -1; 8 9 this.listView1.SelectedIndexChanged -= listView1_SelectedIndexChanged; 10 11 listView1.Items.Clear(); 12 13 listView1.Items.Add("aaaaaaaaaaa"); 14 listView1.Items.Add("bbbbbbbbbbb"); 15 listView1.Items.Add("ccccccccccc"); 16 17 if (selectedIndex != -1) { 18 listView1.Items[selectedIndex].Focused = true; 19 listView1.Items[selectedIndex].Selected = true; 20 } 21 22 this.listView1.SelectedIndexChanged += listView1_SelectedIndexChanged; 23} 24 25private void listView1_SelectedIndexChanged(object sender, EventArgs e) { 26 func(); 27}

投稿2021/04/06 00:52

dekaaki

総合スコア292

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dekaaki

2021/04/06 02:16

補足ですが今回の方法はSelectedIndexChangedで項目を再構築し、元の選択状態を復元するという目的になります。 何が言いたいかというと復元する選択項目を強制的に別の項目にすると正しく動作しなくなります。 例:2番目の項目をマウスで選択したのに3番目の項目を選択状態にするとか前回選択してたindex位置の項目がなくなったとか 他の方も言われてるようにそもそもユーザーの操作を阻害する可能性があるので、 方法1: SelectedIndexChangedで項目の作り変えは行わない この場合、例えばボタンのクリック処理とかで再構築とかにすると特殊なことはしなくてもSelectedIndices.Addで正常に動作します。 方法2: SelectedIndexChangedで項目を作り変えたいのであれば、毎回作り変えるのではなく、再構築が必要な状態かどうか判断して必要な場合だけ再構築して選択状態は復元しない といったことを検討したほうがいいかもしれません
guest

0

マウスでアイテムを選択すると listView1_SelectedIndexChanged() が呼ばれますが、その最終行で func() を呼び出しています。
func() の中でアイテムが全削除されている(listView1.Items.Clear())ので、その時点で選択アイテムがなくなります。func()を呼び出す意図が分かってないですが、そこをコメントアウトしてはいかがでしょうか。

投稿2021/04/06 00:55

hqf00342

総合スコア273

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

どうも触った感じだと、
・通常はMouseDown直後にSelectedIndexChangedが呼ばれるだけ
・SelectedIndexChanged中にlistView1.Items.Clear();した場合はマウスから指を離した直後にもSelectedIndexChangedが呼ばれ、選択が解除される(その後MouseDownイベント)

なので、提案として、MouseDown、MouseUpイベントを使うのはいかがでしょうか。

C#

1using System; 2using System.Collections.Generic; 3using System.ComponentModel; 4using System.Data; 5using System.Diagnostics; 6using System.Drawing; 7using System.Linq; 8using System.Text; 9using System.Threading.Tasks; 10using System.Windows.Forms; 11 12namespace WinFormListViewSelectedIndex { 13 public partial class Form1 : Form { 14 public Form1() { 15 InitializeComponent(); 16 17 func(); 18 } 19 ListViewItem selectedItem = null; 20 private void func() { 21 var selectedIndex = listView1.Items.IndexOf(selectedItem); 22 listView1.Items.Clear(); 23 24 var r = new Random(); 25 var cnt = r.Next(10, 50); 26 for (int i = 1; i <= cnt; i++) { 27 listView1.Items.Add("Item" + string.Format("{0:D2}", i)); 28 } 29 30 if (selectedIndex != -1 && listView1.Items.Count > selectedIndex) { 31 listView1.SelectedIndices.Add(selectedIndex); 32 listView1.EnsureVisible(selectedIndex); 33 } 34 } 35 36 private void listView1_MouseUp(object sender, MouseEventArgs e) { 37 selectedItem = listView1.GetItemAt(e.X, e.Y); 38 if (selectedItem == null) return; 39 func(); 40 } 41 } 42}

投稿2021/04/05 15:34

編集2021/04/05 15:48
Hey_CH

総合スコア437

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

abroad128

2021/04/05 15:48

回答ありがとうございます。 目的の達成方法を考えて頂き嬉しいのですが、どちらかと言うと質問文のコードがうまくいかない原因を知りたいという勉強的な理由なのでそちらの回答も頂けると嬉しいです。
Hey_CH

2021/04/05 15:51

中身についてはさっぱりわかりませんねー申し訳ないです。
guest

0

listView1.Items.Clear();

で選択状態も全部クリアされます。

これでなにをしたいんでしょう

投稿2021/04/05 11:43

y_waiwai

総合スコア87749

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

abroad128

2021/04/05 12:30

>これでなにをしたいんでしょう 実際には変更されたリストを再リストアップするので最初に前回のリストアップを消しています。 >選択状態も全部クリアされます。 listView1.SelectedIndices.Add(selectedIndex); で選択状態を復元しようとしているのですがうまくいきません。
y_waiwai

2021/04/05 13:52

そのクリアしたときもSelectedIndexChangedでたりしてませんかw
abroad128

2021/04/05 13:55

何かが選択されているとSelectedIndexChangedが発火するので if (selectedIndex != -1) disableEventCounter++; や if (disableEventCounter > 0) { disableEventCounter--; return; } などで回避しようとしているのですがうまくいかない原因が分からないです。
y_waiwai

2021/04/05 13:58

ならそれを聞けばどうなんです? 質問に書いてないことを後付でどーこー言われても困りますぜw
abroad128

2021/04/05 14:01

私の質問は元から添付されたコードが期待した動作をしない原因を知るためのもので後付けはありません。
y_waiwai

2021/04/05 14:10

なら質問に書いてない事柄には答えないことにしますねw
abroad128

2021/04/05 14:13

書いてありますが、不快なので通報しておきました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問