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

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

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

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

MVVM

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

Q&A

解決済

2回答

1056閲覧

トリガーイベントをMVVMで実装したい

siksmtt

総合スコア20

C#

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

MVVM

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

0グッド

0クリップ

投稿2019/01/18 01:58

編集2019/01/18 02:05

発生している問題

WPFアプリケーションを作っておりMVVMで実装しようと考えています。
ListBoxのSelectionChagedイベントを実装しようとしていますが、想定通りの動きにならず困っています。

該当のソースコード

Viewのコードに一部コメント箇所があります。
別の質問で「ListBoxではSelectedItemの問題でできないため、CheckListBoxを使ってください」というご回答をいただき、
CheckListBoxを使った場合がコメントアウト箇所になります。
結果としてはどちらでも上手くいきませんでした。

C#

1//View 2 xmlns:xcad="http://schemas.xceed.com/wpf/xaml/toolkit" 3 mc:Ignorable="d" 4 Title="MainWindow" Height="350" Width="525"> 5 <Grid> 6 <ListBox HorizontalAlignment="Left" Height="56" Margin="64,67,0,0" VerticalAlignment="Top" Width="380" SelectedItem="{Binding SelectColorList}" ItemsSource="{Binding ColorList}"/> 7 <ListBox HorizontalAlignment="Left" Height="56" Margin="64,182,0,0" VerticalAlignment="Top" Width="380" ItemsSource="{Binding ItemList}"/> 8 9 <!--<xcad:CheckListBox HorizontalAlignment="Left" Height="56" Margin="64,67,0,0" VerticalAlignment="Top" Width="380" SelectedItemsOverride="{Binding SelectColorList}" ItemsSource="{Binding ColorList}"/> 10 <xcad:CheckListBox HorizontalAlignment="Left" Height="56" Margin="64,182,0,0" VerticalAlignment="Top" Width="380" ItemsSource="{Binding ItemList}"/>--> 11 12 <Label Content="色" HorizontalAlignment="Left" Height="24" Margin="65,38,0,0" VerticalAlignment="Top" Width="65"/> 13 <Label Content="アイテム" HorizontalAlignment="Left" Height="24" Margin="64,153,0,0" VerticalAlignment="Top" Width="65"/> 14 15 <Button Content="Button" HorizontalAlignment="Left" Height="37" Margin="354,260,0,0" VerticalAlignment="Top" Width="90" Click="Button_Click"/> 16 </Grid>

C#

1//ViewModel 2 public class MainViewModel : INotifyPropertyChanged 3 { 4 private ObservableCollection<string> ColorListVal; 5 public ObservableCollection<string> ColorList 6 { 7 get { return ColorListVal; } 8 set 9 { 10 ColorListVal = value; 11 NotifyPropertyChanged("ColorList"); 12 13 } 14 } 15 16 private ObservableCollection<string> SelectColorListVal = new ObservableCollection<string>(); 17 public ObservableCollection<string> SelectColorList 18 { 19 get { return SelectColorListVal; } 20 set 21 { 22 SelectColorListVal = value; 23 NotifyPropertyChanged("SelectColorList"); 24 25 ItemListVal.Clear(); 26 27 for (int i = 0; i < SelectColorList.Count; i++) 28 { 29 switch (SelectColorList[i]) 30 { 31 case "赤": 32 ItemListVal.Add("りんご"); 33 ItemListVal.Add("太陽"); 34 ItemListVal.Add("チューリップ"); 35 break; 36 37 case "青": 38 ItemListVal.Add("海"); 39 ItemListVal.Add("ブルーハワイ"); 40 ItemListVal.Add("空"); 41 break; 42 43 case "黄": 44 ItemListVal.Add("レモン"); 45 ItemListVal.Add("パイナップル"); 46 ItemListVal.Add("チューリップ"); 47 break; 48 49 case "緑": 50 ItemListVal.Add("青りんご"); 51 ItemListVal.Add("野菜"); 52 ItemListVal.Add("お茶"); 53 break; 54 } 55 } 56 } 57 } 58 59 private ObservableCollection<string> ItemListVal; 60 public ObservableCollection<string> ItemList 61 { 62 get { return ItemListVal; } 63 set 64 { 65 ItemListVal = value; 66 NotifyPropertyChanged("ItemList"); 67 } 68 } 69 70 71 72 public MainViewModel() 73 { 74 ColorListVal = new ObservableCollection<string>(){ "赤", "青", "黄", "緑" }; 75 ItemListVal = new ObservableCollection<string>() { "何も選択されていません"}; 76 } 77 78 79 80 public event PropertyChangedEventHandler PropertyChanged; 81 private void NotifyPropertyChanged(String info) 82 { 83 if (PropertyChanged != null) 84 { 85 PropertyChanged(this, new PropertyChangedEventArgs(info)); 86 } 87 } 88 }

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 private void Button_Click(object sender, RoutedEventArgs e) 13 { 14 string s1 = ""; 15 16 for (int i = 0; i < viewmodel.SelectColorList.Count; i++) 17 { 18 s1 += viewmodel.SelectColorList[i] + "\r\n"; 19 } 20 21 MessageBox.Show(s1); 22 } 23 }

試したこと

本来であれば「色」リストの項目を選択すると「アイテム」リストに対応するアイテムが反映されるのですが、
初期値である「何も選択されていません」から変わりません。

プロパティのデータバインドが上手くいっていないのかと思い、
ボタンを追加して現在選択されている「色」リストの項目を確認するようにもしましたが、そこは正常に反映されています。

やはりプロパティのセッターを使うのではなく、コマンドをバインドさせる形になるのでしょうか?
ご助言いただけますと幸いです。

###補足

ちなみに本番アプリケーションでは複数選択をするので SelectionMode="Extended" プロパティを設定します。(ListBoxの場合)
ListBox、ChechListBoxどちらを使うかは大きな問題ではないのですが、
複数選択した時にも「アイテム」リストに複数の色アイテムが表示されるようにできればと思っています。

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

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

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

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

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

guest

回答2

0

ベストアンサー

その作りかただと、MainViewModelにてSelectColorListのCollectionChangedイベントをリスニングする必要があります。
リスニングには IWeakEventListener を実装したクラスを用いることが多いですが、Livet(MVVMインフラ)以外でやると結構面倒です。
また、変更はItemListValではなく、ItemListに対して行ってください。

Model が階層構造を持っていれば、それをそのまま表示するだけなのでVMでのリスニングは不要になります。
こんな風に

C#

1 // ViewModel 2 public class MyViewModel 3 { 4 public MyViewModel() 5 { 6 Groups = MyGroupPresenter.GetMaterials(); 7 SelectedGroups = new ObservableCollection<MyGroup>(); 8 } 9 10 public IEnumerable<MyGroup> Groups { get; private set; } 11 12 public ObservableCollection<MyGroup> SelectedGroups { get; set; } 13 } 14 15 // 以下Model 16 public enum ColorTypes 17 { 18,,,19 } 20 21 public class Item 22 { 23 public string Name { get; set; } 24 } 25 26 public class MyGroup 27 { 28 public ColorTypes Color { get; set; } 29 public ICollection<Item> Items { get; set; } 30 } 31 32 public class MyGroupPresenter 33 { 34 public static List<MyGroup> GetMaterials() 35 { 36 return new List<MyGroup> 37 { 38 new MyGroup 39 { 40 Items = new Item [] 41 { 42 new Item {Name = "リンゴ"}, 43 new Item {Name = "太陽"}, 44 new Item {Name = "チューリップ"} 45 }, 46 Color = ColorTypes.47 } 48 }; 49 } 50 }

XML

1<Grid> 2 <Grid.ColumnDefinitions> 3 <ColumnDefinition Width="*"/> 4 <ColumnDefinition Width="*"/> 5 </Grid.ColumnDefinitions> 6 <tk:CheckListBox ItemsSource="{Binding Groups}" 7 SelectedItemsOverride="{Binding SelectedGroups}" 8 DisplayMemberPath="Color"/> 9 <ListBox Grid.Column="1" 10 ItemsSource="{Binding SelectedGroups}"> 11 <ListBox.ItemTemplate> 12 <DataTemplate> 13 <Grid> 14 <Grid.RowDefinitions> 15 <RowDefinition Height="auto"/> 16 <RowDefinition Height="*"/> 17 </Grid.RowDefinitions> 18 <TextBlock Grid.Row="0" Text="{Binding Color}"/> 19 <ListBox Grid.Row="1" ItemsSource="{Binding Items}" 20 DisplayMemberPath="Name"/> 21 </Grid> 22 </DataTemplate> 23 </ListBox.ItemTemplate> 24 </ListBox> 25</Grid>

投稿2019/01/18 03:37

編集2019/01/18 04:27
hihijiji

総合スコア4150

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

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

siksmtt

2019/01/18 06:57

hihijiji様 ご回答ありがとうございます。ご教示いただいたコード自体は動いたのですが2つだけ質問させてください。 ①色とアイテムのリストが動的に追加される(中身が可変で数も可変ある)場合、どのように書いたらいいのでしょうか。 ②ItemSource="{Binding Items}"のListBoxをTextBlockにすることは可能でしょうか。
hihijiji

2019/01/18 07:16 編集

1.Modelが変わるだけです。動的に変化するModelを書いてください。 2.出来ないことは無いですが、Textを扱うととても面倒で厄介なのでまずそんな書きかたはしません。
siksmtt

2019/01/18 08:03

hihijiji様 ご回答ありがとうございます。試しにTextBlockにしたらすごく大変でしかもやっぱり解決できなかったので、手は出さないでおこうと思います...。前回に引き続きありがとうございました。
guest

0

一つ目の ListBox の SelectedItem に SelectColorList が設定されているからでは?

SelectedItem には ListBox で選択されている内容、この場合"赤"やら"青"といった文字列が設定されるべきなのに、Bind されているのが ObservableCollection<string> だからではないですか?
※デバッガに「ObservableCollectionに変換できません云々」のエラーが表示されていないですか?

以下でどうでしょう。

C#

1 private string SelectColorListVal = ""; 2 public string SelectColorList 3 { 4 get { return SelectColorListVal; } 5 set 6 { 7 if( SelectColorListVal == value ) 8 return; 9 10 SelectColorListVal = value; 11 NotifyPropertyChanged("SelectColorList"); 12 13 ItemListVal.Clear(); 14 15 switch (SelectColorListVal) 16 { 17 case "赤": 18 ItemListVal.Add("りんご"); 19 ItemListVal.Add("太陽"); 20 ItemListVal.Add("チューリップ"); 21 break; 22 case "青": 23 ItemListVal.Add("海"); 24 ItemListVal.Add("ブルーハワイ"); 25 ItemListVal.Add("空"); 26 break; 27 case "黄": 28 ItemListVal.Add("レモン"); 29 ItemListVal.Add("パイナップル"); 30 ItemListVal.Add("チューリップ"); 31 break; 32 case "緑": 33 ItemListVal.Add("青りんご"); 34 ItemListVal.Add("野菜"); 35 ItemListVal.Add("お茶"); 36 break; 37 } 38 } 39 }

なお複数選択を考慮するということであれば、別途違やり方を考える必要があります。

投稿2019/01/18 03:27

ebiryo

総合スコア797

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

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

siksmtt

2019/01/18 08:03

ebiryo様 ご回答ありがとうございます。複数選択は絶対外せない仕様なので、他に考えてみます。ちなみに「ObservableCollectionに変換できません云々」は出ていませんでした。それにSelectionChangeイベントとしてコードビハインドにゴリゴリ書いていた時は上手くできていたので...。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問