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

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

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

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

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

Q&A

解決済

1回答

6592閲覧

ListBoxをMVVMで実装したい

siksmtt

総合スコア20

C#

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

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

0グッド

0クリップ

投稿2019/01/11 04:44

表題の通り、MVVMで構築しているアプリケーションでListBoxを使おうと思っています。
ネットサンプルは一応見たのですが、理解できなかったこともあり自分なりの組み方で動作を確認しました。

コードは以下になります。

C#

1//View 2 <Grid> 3 <ListBox HorizontalAlignment="Left" Margin="80,65,0,126" Width="361" ItemsSource="{Binding list}" SelectedItem="{Binding selectList}" SelectedIndex="{Binding selectIndex}" SelectionMode="Extended" SelectionChanged="ListBox_SelectionChanged"/> 4 <Button Content="Button1" HorizontalAlignment="Left" Height="19" Margin="80,263,0,37" Width="70" Click="Button_Click"/> 5 <Button Content="Button2" HorizontalAlignment="Left" Height="19" Margin="371,263,0,37" Width="70" Click="Button_Click2"/> 6 </Grid>

C#

1//コードビハインド 2 public partial class MainWindow : Window 3 { 4 private MainViewModel viewmodel; 5 public MainWindow() 6 { 7 InitializeComponent(); 8 viewmodel = new MainViewModel(); 9 this.DataContext = viewmodel; 10 } 11 12 //データ追加イベント 13 private void Button_Click(object sender, RoutedEventArgs e) 14 { 15 viewmodel.list.Add("abc1"); 16 viewmodel.list.Add("abc2"); 17 viewmodel.list.Add("abc3"); 18 viewmodel.list.Add("abc4"); 19 viewmodel.list.Add("abc5"); 20 viewmodel.list.Add("abc6"); 21 viewmodel.list.Add("abc7"); 22 viewmodel.list.Add("abc8"); 23 viewmodel.list.Add("abc9"); 24 viewmodel.list.Add("abc10"); 25 viewmodel.list.Add("abc11"); 26 viewmodel.list.Add("abc12"); 27 viewmodel.selectList.Clear(); //初期化状態だと"abc1"にselect状態になってしまうのでリセットさせる 28 } 29 30 //abc7をselect状態にするためのクリックイベント 31 private void Button_Click2(object sender, RoutedEventArgs e) 32 { 33 for (int i = 0; i < viewmodel.list.Count; i++) 34 { 35 string s1 = viewmodel.list[i]; 36 37 if (s1 == "abc7") 38 { 39 viewmodel.selectList.Add(s1); 40 viewmodel.selectIndex = i; 41 } 42 } 43 } 44 45 //select状態が変化した時にVMとデータを同期させるためのイベント 46 private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 47 { 48 ListBox listBox = (ListBox)sender; 49 viewmodel.selectList.Clear(); 50 51 for (int i = 0; i < listBox.SelectedItems.Count; i++) 52 { 53 string s1 = listBox.SelectedItems[i].ToString(); 54 viewmodel.selectList.Add(s1); 55 } 56 } 57 }

C#

1//ViewModel 2 public class MainViewModel : INotifyPropertyChanged 3 { 4 5 private ObservableCollection<string> listVal = new ObservableCollection<string>(); 6 public ObservableCollection<string> list 7 { 8 get { return listVal; } 9 set 10 { 11 listVal = value; 12 NotifyPropertyChanged("list"); 13 } 14 } 15 16 17 18 private int selectIndexVal = new int(); 19 public int selectIndex 20 { 21 get { return selectIndexVal; } 22 set 23 { 24 selectIndexVal = value; 25 NotifyPropertyChanged("selectIndex"); 26 } 27 } 28 29 30 private ObservableCollection<string> selectListVal = new ObservableCollection<string>(); 31 public ObservableCollection<string> selectList 32 { 33 get { return selectListVal; } 34 set 35 { 36 selectListVal = value; 37 NotifyPropertyChanged("selectList"); 38 } 39 } 40 41 42 public event PropertyChangedEventHandler PropertyChanged; 43 private void NotifyPropertyChanged(String info) 44 { 45 if (PropertyChanged != null) 46 { 47 PropertyChanged(this, new PropertyChangedEventArgs(info)); 48 } 49 } 50 }

まだテスト段階でのコードなので大雑把ですが、実アプリケーションでは
・ListBoxの中身を全て取得する
・現在選択されているListの中身を全て取得する
・ListBoxの中身を動的に更新する(中身を全ていれかえる、選択するリストを指定する、の2つしかしません)
の3点ができれば問題ないです。

(そのため現コードでは、ListBoxに「SelectionMode="Extended"」と指定してるにも関わらず、選択されている中身のインデックス位置を取得できないですが、実アプリケーションでは問題ないです)

ただネットのサンプルは他の方法でやっているように見えたので、このコードが間違えた実装になっているのではないかと思っています。
コードは自分が管理するのでできれば複雑なコードではないように修正できればと思うのですが、ご助言いただけないでしょうか。よろしくお願いいたします。

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

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

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

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

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

len_souko

2019/01/11 14:49 編集

回答とは全く関係ないけど、VS2015以降を使ってるなら NotifyPropertyChanged("selectList"); は NotifyPropertyChanged(nameof(selectList));にした方が間違いが起きにくいですよ。あと、publicの名前は先頭を大文字で、privateを小文字にするのがC#のコーディング規約ですが、正直privateように名前を考える手間が省けるのでお勧めです(実際に使いたい名前をpublicプロパティに付けて、保持するprivateフィールドは先頭を小文字にするだけで解決)
siksmtt

2019/01/15 01:36

len_souko様 ご助言ありがとうございます。VS2017なので nameof は問題なさそうです。質問を投稿する前に大文字小文字のミスで上手く動かないことがあったので、そういうのはとても有難いですね...。そのコーディング規約は初耳でした!たしかにすごく便利な命名規則ですね、いつも悩んでました...。ありがとうございます!
guest

回答1

0

ベストアンサー

MVVMではコードビハインドを使わないのが原則です。
絶対に使ってはダメって訳ではありませんが、ほぼいじる必要がありません。

WPF自体は大分理解されているようですので、以下のページを読んでみてください。
Livetの中の人が書かれています。
MVVMパターンの常識
一度読んだぐらいでは、なかなか理解できないと思いますが、MVVMのバイブルとでも呼ぶべき名著です。
一通り読んで、サンプルを動かして、もう一度読むと理解が深まります。
私も何度も繰り返して読んで、最近ようやく理解できました。

投稿2019/01/11 07:03

hihijiji

総合スコア4150

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

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

siksmtt

2019/01/11 08:04

hihijiji様 ご助言ありがとうございます。コードビハインドについてはICommandを実装すれば薄くできるかと思っている(もしかしたら勘違い?)ので、慣れたら実装してみようと思います。また参考ページまでご丁寧にありがとうございます!MVVM自体始めたばかりなので、ぜひ読んでみようと思います。
hihijiji

2019/01/12 01:30

読んだらわかると思いますが、INotifyPropertyChangedもICommandも自分で実装するのではなく、あるものを使ったほうが良いです。 それこそ無駄に複雑にしたいなら都度自分で実装しても良いかもしれませんが
siksmtt

2019/01/15 01:33

hihijiji様 ありがとうございます。参考にさせていただきます!
siksmtt

2019/01/17 07:24

hihijiji様 度々申し訳ありません。もしお時間あればご回答いただけますと幸いです。今コードビハインドに書いているイベント処理をMVVM化しようと思い、ListBox_SelectionChangedを試しにMVVM化しているところなのですが、selectListプロパティのsetterに処理を書いてもsetterに入りません(setterにブレークポイントを置いていますが引っかからないということです)。状態遷移系のイベントはできないのでしょうか?
siksmtt

2019/01/18 01:44

hihijiji様 丁寧にURLまでありがとうございます!ChackListBoxに変えてみましたがやはり想定通りの動きにはなりませんでした...。別途質問として建てようと思います。アドバイス等ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問