質問するログイン新規登録

質問編集履歴

5

コンパイルが通らない問題を解決しました

2019/06/14 12:55

投稿

arw.tyx-out_mz
arw.tyx-out_mz

スコア27

title CHANGED
File without changes
body CHANGED
@@ -14,36 +14,55 @@
14
14
  #### PersonList(シングルトン)
15
15
 
16
16
  ```C#
17
+ using System;
17
- public sealed class PersonList : BindableBase
18
+ using System.Collections.Generic;
19
+ using System.Linq;
20
+ using System.Text;
21
+ using System.Threading.Tasks;
22
+ using Prism.Mvvm;
23
+ using Reactive.Bindings;
24
+
25
+ namespace ForTeratail.Models
18
26
  {
19
- private static readonly PersonList m_instance = new PersonList();
27
+ public sealed class PersonList : BindableBase
20
-
21
- private PersonList()
22
28
  {
23
- PersonCollection = new ReactiveCollection<Person>();
24
- Add();
25
- }
26
- public static PersonList Instance { get { return m_instance; } }
29
+ static readonly PersonList m_instance = new PersonList();
27
30
 
28
- ReactiveCollection<Person> m_collection;
29
- public ReactiveCollection<Person> PersonCollection
31
+ public static PersonList Instance
30
- {
32
+ {
31
- get { return m_collection; }
33
+ get { return m_instance; }
32
- set { SetProperty(ref m_collection, value); }
33
- }
34
+ }
34
35
 
35
- Person m_current;
36
+ int count;
36
- public Person CurrentPerson
37
- {
38
- get { return m_current; }
39
- set { SetProperty(ref m_current, value); }
40
- }
41
37
 
38
+ private PersonList()
39
+ {
40
+ count = 0;
41
+ PersonCollection = new ReactiveCollection<Person>();
42
+ Add();
43
+ }
44
+
45
+ ReactiveCollection<Person> m_collection;
46
+ public ReactiveCollection<Person> PersonCollection
47
+ {
48
+ get { return m_collection; }
49
+ set { SetProperty(ref m_collection, value); }
50
+ }
51
+
52
+ Person m_current;
53
+ public Person CurrentPerson
54
+ {
55
+ get { return m_current; }
56
+ set { SetProperty(ref m_current, value); }
57
+ }
58
+
42
- public void Add()
59
+ public void Add()
43
- {
60
+ {
44
- Person p = new Person();
61
+ Person p = new Person(count);
45
- PersonCollection.Add(p);
62
+ PersonCollection.Add(p);
46
- CurrentPerson = PersonCollection[PersonCollection.Count - 1];
63
+ CurrentPerson = PersonCollection[PersonCollection.Count - 1];
64
+ count++;
65
+ }
47
66
  }
48
67
  }
49
68
  ```
@@ -51,20 +70,38 @@
51
70
  #### Person
52
71
 
53
72
  ```C#
73
+ using System;
74
+ using System.Collections.Generic;
75
+ using System.Linq;
76
+ using System.Text;
54
- public class Person : BindableBase
77
+ using System.Threading.Tasks;
78
+ using Prism.Mvvm;
79
+ using Reactive.Bindings;
80
+
81
+ namespace ForTeratail.Models
55
82
  {
56
- string m_name;
57
- public string Name
83
+ public class Person : BindableBase
58
84
  {
59
- get { return m_name; }
85
+ public int Id { get; set; }
60
- set { SetProperty(ref m_name, value); }
61
- }
62
86
 
87
+ string m_name;
88
+ public string Name
89
+ {
90
+ get { return m_name; }
91
+ set { SetProperty(ref m_name, value); }
92
+ }
93
+
63
- int m_age;
94
+ int m_age;
64
- public int Age
95
+ public int Age
65
- {
96
+ {
66
- get { return m_age; }
97
+ get { return m_age; }
67
- set { SetProperty(ref m_age, value); }
98
+ set { SetProperty(ref m_age, value); }
99
+ }
100
+
101
+ public Person(int id)
102
+ {
103
+ Id = id;
104
+ }
68
105
  }
69
106
  }
70
107
  ```
@@ -73,44 +110,56 @@
73
110
  #### MyViewModel(ComboBoxがあるViewのVM)
74
111
 
75
112
  ```C#
113
+ using System.Reactive.Linq;
114
+ using Prism.Mvvm;
76
- class MyViewModel : BindableBase
115
+ using Reactive.Bindings;
116
+ using Reactive.Bindings.Extensions;
117
+ using ForTeratail.Models;
118
+
119
+ namespace ForTeratail.ViewModels
77
120
  {
78
- public ReactiveCollection<Person> Collection { get; }
79
- public ReactiveProperty<Person> CurrentPerson { get; }
80
- public ReactiveProperty<string> HereName { get; }
81
- public ReactiveProperty<int> HereAge { get; }
82
- public ReactiveProperty<string> Introduction { get; }
83
-
84
- public ReactiveCommand<string> UIInteractiveNameCommand { get; }
85
- public ReactiveCommand<int> UIInteractiveAgeCommand { get; }
86
- public ReactiveCommand AddCommand { get; }
121
+ public class MainWindowViewModel : BindableBase
87
-
88
- public MyViewModel()
89
122
  {
90
- // ComboBoxで表示されるリスト
91
- Collection = PersonList.Instance.PersonCollection;
123
+ private string _title = "Prism Application";
124
+ public string Title
125
+ {
126
+ get { return _title; }
92
- // ComboBoxで現在選択されているリスト
127
+ set { SetProperty(ref _title, value); }
93
- CurrentPerson = PersonList.Instance.ToReactivePropertyAsSynchronized(x => x.CurrentPerson);
128
+ }
94
-
95
- HereName = CurrentPerson.Select(x => x.Name).ToReactiveProperty(); // => これがずっとnullになる
96
- HereAge = CurrentPerson.Select(x => x.Age).ToReactiveProperty(); // => これがずっとnullになる
97
129
 
130
+ public ReactiveCollection<Person> Collection { get; }
98
- // このプロパティはCurrentPersonの変更と,CurrentPerson.Value.Nameの変更の両方を検知したい
131
+ public ReactiveProperty<Person> CurrentPerson { get; }
132
+ public ReactiveProperty<string> HereName { get; }
133
+ public ReactiveProperty<int> HereAge { get; }
99
- Introduction = HereName.Where(x => x != null).Select(x => "I am " + x).ToReactiveProperty();
134
+ public ReactiveProperty<string> Introduction { get; }
100
135
 
101
- UIInteractiveNameCommand = new ReactiveCommand<string>().WithSubscribe(x =>
136
+ public ReactiveCommand<string> UIInteractiveNameCommand { get; }
102
- {
137
+ public ReactiveCommand<int> UIInteractiveAgeCommand { get; }
103
- CurrentPerson.Name = x;
138
+ public ReactiveCommand AddCommand { get; }
104
- });
105
139
 
106
- UIInteractiveAgeCommand = new ReactiveCommand<int>().WithSubscribe(x =>
140
+ public MainWindowViewModel()
107
141
  {
108
- CurrentPerson.Age = x;
142
+ Collection = PersonList.Instance.PersonCollection;
109
- });
143
+ CurrentPerson = PersonList.Instance.ToReactivePropertyAsSynchronized(x => x.CurrentPerson);
110
144
 
111
- // AddされるとCurrentPersonが変化する
145
+ HereName = CurrentPerson.Select(x => x.Name).ToReactiveProperty();
146
+ HereAge = CurrentPerson.Select(x => x.Age).ToReactiveProperty();
147
+
148
+ Introduction = HereName.Where(x => x != null).Select(x => "I am " + x).ToReactiveProperty();
149
+
150
+ UIInteractiveNameCommand = new ReactiveCommand<string>().WithSubscribe(x =>
151
+ {
112
- // そのときにHereNameの値が更新されない
152
+ CurrentPerson.Value.Name = x;
153
+ });
154
+
155
+ UIInteractiveAgeCommand = new ReactiveCommand<int>().WithSubscribe(x =>
156
+ {
157
+ CurrentPerson.Value.Age = x;
158
+ });
159
+
160
+ AddCommand = new ReactiveCommand();
113
- AddCommand = new ReactiveCommand().WithSubscribe(_ => PersonList.Instance.Add());
161
+ AddCommand.Subscribe(PersonList.Instance.Add);
162
+ }
114
163
  }
115
164
  }
116
165
  ```
@@ -118,14 +167,57 @@
118
167
  #### MyView (ComboBoxがあるView)
119
168
 
120
169
  ```C#
170
+ <Window x:Class="ForTeratail.Views.MainWindow"
171
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
172
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
173
+ xmlns:prism="http://prismlibrary.com/"
174
+ prism:ViewModelLocator.AutoWireViewModel="True"
175
+ Title="{Binding Title}" Height="350" Width="525">
176
+ <Grid>
177
+ <Grid.RowDefinitions>
121
- // 省略
178
+ <RowDefinition/>
179
+ <RowDefinition/>
180
+ <RowDefinition/>
181
+ <RowDefinition/>
182
+ </Grid.RowDefinitions>
183
+ <Grid.ColumnDefinitions>
184
+ <ColumnDefinition/>
185
+ <ColumnDefinition/>
186
+ </Grid.ColumnDefinitions>
187
+ <ComboBox Grid.Column="0" Margin="10 20"
188
+ ItemsSource="{Binding Collection}"
189
+ SelectedValue="{Binding CurrentPerson.Value}"
190
+ DisplayMemberPath="Id" />
122
- <ComboBox ItemsSource="{Binding Collection}" SelectedValue="{Binding CurrentPerson.Value}" DisplayMemberPath="Name"
191
+ <Button Grid.Column="1" Content="新規追加" Command="{Binding AddCommand}" Margin="20" />
192
+
193
+ <TextBox Grid.Row="1" Grid.Column="0" Margin="10" Height="30" FontSize="18"
194
+ TextAlignment="Center" VerticalContentAlignment="Center"
195
+ x:Name="NameBlock"/>
196
+ <Button Grid.Row="1" Grid.Column="1" Content="登録" Margin="20"
197
+ Command="{Binding UIInteractiveNameCommand}"
198
+ CommandParameter="{Binding Text, ElementName=NameBlock}" />
199
+
200
+ <TextBox Grid.Row="2" Grid.Column="0" Margin="10" Height="30" FontSize="18"
201
+ TextAlignment="Center" VerticalContentAlignment="Center"
202
+ x:Name="AgeBlock"/>
123
- Grid.Row="2" Grid.Column="0" Margin="0 0"/>
203
+ <Button Grid.Row="2" Grid.Column="1" Content="登録" Margin="20"
204
+ Command="{Binding UIInteractiveAgeCommand}"
124
- <Button Command="{Binding AddCommand}" />
205
+ CommandParameter="{Binding Text, ElementName=AgeBlock}" />
206
+
207
+ <Label Grid.Row="3" Grid.ColumnSpan="2" Content="{Binding Introduction.Value}" />
125
- // 省略
208
+ </Grid>
209
+ </Window>
126
210
  ```
127
211
 
212
+ ### 問題
213
+ 新規追加ボタンを押すと`PersonList`クラスの`PersonCollection`に空の`Person`オブジェクトが追加されます.
214
+ それがComboBoxに紐付いています.
215
+ また,登録ボタンを押すとテキストボックスにあるテキストがCommandの引数として渡され,現在選択されている`Person`オブジェクトのプロパティとしてセットされます.
216
+ ここはあくまで発生している問題を再現する簡易的な例なので,TextBoxの内容を`ReactiveProperty`とBindingするということは考えないでください.
217
+ あくまで,コマンド経由で現在選択されているオブジェクトのプロパティを変更したときに,それを監視している`ReactiveProperty`の値が変更されないという問題です.
218
+
128
219
  上記クラスの`CurrentPerson`の`Name`プロパティや`Age`プロパティは適切に変更されますが,`HereName`や`HereAge`が`null`のままで書き換わってくれません.
220
+ しかし,ComboBoxで選択しているオブジェクトを変更し(例えば`Id=0`のオブジェクトから`Id=1`のオブジェクトへ),その後同じオブジェクト(`Id=0`)に戻ってくると,プロパティの値がちゃんと`Here〇〇`に設定されています.
129
221
  `CurrentPerson`が保持している`Person`オブジェクト自体の変更と,その`Person`オブジェクト内のプロパティ両方の変更を検知するためにはどのように修正すればいいでしょうか?
130
222
 
131
223
 

4

ソースコードの修正

2019/06/14 12:55

投稿

arw.tyx-out_mz
arw.tyx-out_mz

スコア27

title CHANGED
File without changes
body CHANGED
@@ -79,6 +79,7 @@
79
79
  public ReactiveProperty<Person> CurrentPerson { get; }
80
80
  public ReactiveProperty<string> HereName { get; }
81
81
  public ReactiveProperty<int> HereAge { get; }
82
+ public ReactiveProperty<string> Introduction { get; }
82
83
 
83
84
  public ReactiveCommand<string> UIInteractiveNameCommand { get; }
84
85
  public ReactiveCommand<int> UIInteractiveAgeCommand { get; }
@@ -94,6 +95,9 @@
94
95
  HereName = CurrentPerson.Select(x => x.Name).ToReactiveProperty(); // => これがずっとnullになる
95
96
  HereAge = CurrentPerson.Select(x => x.Age).ToReactiveProperty(); // => これがずっとnullになる
96
97
 
98
+ // このプロパティはCurrentPersonの変更と,CurrentPerson.Value.Nameの変更の両方を検知したい
99
+ Introduction = HereName.Where(x => x != null).Select(x => "I am " + x).ToReactiveProperty();
100
+
97
101
  UIInteractiveNameCommand = new ReactiveCommand<string>().WithSubscribe(x =>
98
102
  {
99
103
  CurrentPerson.Name = x;

3

ソースコード及びやりたいことの追記

2019/06/14 02:43

投稿

arw.tyx-out_mz
arw.tyx-out_mz

スコア27

title CHANGED
File without changes
body CHANGED
@@ -3,9 +3,10 @@
3
3
  `ReactiveProperty`を使ってWPFアプリを作成しています.
4
4
  ComboBoxを使うところでハマってしまったので,アドバイスお願いします.
5
5
 
6
- # 問題
6
+ # やりたいこと
7
7
 
8
- ある自作クラスの`ReactiveProperty`と,そのクラスのプロパティの`ReactiveProperty`を作っています.
8
+ ある自作クラスの`ReactiveProperty`Aと,そのクラスのプロパティの`ReactiveProperty`Bを作っています.
9
+ Bにおいて,`A.Value`と,その`A.Value.Property`の両方を監視したいです.
9
10
  自作クラスの`ReactiveProperty`を書換えたときに,連動してプロパティの`ReactiveProperty`も書き換わってほしいのですが,ずっとnullのままです.
10
11
 
11
12
  # ソースコード
@@ -58,6 +59,13 @@
58
59
  get { return m_name; }
59
60
  set { SetProperty(ref m_name, value); }
60
61
  }
62
+
63
+ int m_age;
64
+ public int Age
65
+ {
66
+ get { return m_age; }
67
+ set { SetProperty(ref m_age, value); }
68
+ }
61
69
  }
62
70
  ```
63
71
 
@@ -70,26 +78,53 @@
70
78
  public ReactiveCollection<Person> Collection { get; }
71
79
  public ReactiveProperty<Person> CurrentPerson { get; }
72
80
  public ReactiveProperty<string> HereName { get; }
73
- public ReactiveCommand<string> UIInteractiveCommand { get; }
81
+ public ReactiveProperty<int> HereAge { get; }
74
82
 
83
+ public ReactiveCommand<string> UIInteractiveNameCommand { get; }
84
+ public ReactiveCommand<int> UIInteractiveAgeCommand { get; }
85
+ public ReactiveCommand AddCommand { get; }
86
+
75
87
  public MyViewModel()
76
88
  {
89
+ // ComboBoxで表示されるリスト
77
90
  Collection = PersonList.Instance.PersonCollection;
91
+ // ComboBoxで現在選択されているリスト
78
92
  CurrentPerson = PersonList.Instance.ToReactivePropertyAsSynchronized(x => x.CurrentPerson);
93
+
79
94
  HereName = CurrentPerson.Select(x => x.Name).ToReactiveProperty(); // => これがずっとnullになる
95
+ HereAge = CurrentPerson.Select(x => x.Age).ToReactiveProperty(); // => これがずっとnullになる
80
96
 
81
- UIInteractiveCommand = new ReactiveCommand<string>().WithSubscribe(x =>
97
+ UIInteractiveNameCommand = new ReactiveCommand<string>().WithSubscribe(x =>
82
98
  {
83
- CurrentPerson.Value.Name = x;
99
+ CurrentPerson.Name = x;
84
- })
100
+ });
101
+
102
+ UIInteractiveAgeCommand = new ReactiveCommand<int>().WithSubscribe(x =>
103
+ {
104
+ CurrentPerson.Age = x;
105
+ });
106
+
107
+ // AddされるとCurrentPersonが変化する
108
+ // そのときにHereNameの値が更新されない
109
+ AddCommand = new ReactiveCommand().WithSubscribe(_ => PersonList.Instance.Add());
85
110
  }
86
111
  }
87
112
  ```
88
113
 
89
- 上記クラスの`CurrentPerson`の`Name`プロパティは適切に変更されますが,`HereName`が`null`のままで書き換わってくれません.
90
- どのように修正すればいいでしょうか?
114
+ #### MyView (ComboBoxがあるView)
91
115
 
116
+ ```C#
117
+ // 省略
118
+ <ComboBox ItemsSource="{Binding Collection}" SelectedValue="{Binding CurrentPerson.Value}" DisplayMemberPath="Name"
119
+ Grid.Row="2" Grid.Column="0" Margin="0 0"/>
120
+ <Button Command="{Binding AddCommand}" />
121
+ // 省略
122
+ ```
92
123
 
124
+ 上記クラスの`CurrentPerson`の`Name`プロパティや`Age`プロパティは適切に変更されますが,`HereName`や`HereAge`が`null`のままで書き換わってくれません.
125
+ `CurrentPerson`が保持している`Person`オブジェクト自体の変更と,その`Person`オブジェクト内のプロパティ両方の変更を検知するためにはどのように修正すればいいでしょうか?
126
+
127
+
93
128
  ## バージョン情報
94
129
  Visual Studio 2017 Community
95
130
  .NET Framework 4.6.1

2

ソースコードの修正を行いました.

2019/06/14 02:36

投稿

arw.tyx-out_mz
arw.tyx-out_mz

スコア27

title CHANGED
File without changes
body CHANGED
@@ -80,7 +80,7 @@
80
80
 
81
81
  UIInteractiveCommand = new ReactiveCommand<string>().WithSubscribe(x =>
82
82
  {
83
- CurrentPerson.Name = x;
83
+ CurrentPerson.Value.Name = x;
84
84
  })
85
85
  }
86
86
  }

1

ソースコードの修正を行いました.

2019/06/13 14:05

投稿

arw.tyx-out_mz
arw.tyx-out_mz

スコア27

title CHANGED
File without changes
body CHANGED
@@ -13,8 +13,17 @@
13
13
  #### PersonList(シングルトン)
14
14
 
15
15
  ```C#
16
- sealed class PersonList : BindableBase
16
+ public sealed class PersonList : BindableBase
17
17
  {
18
+ private static readonly PersonList m_instance = new PersonList();
19
+
20
+ private PersonList()
21
+ {
22
+ PersonCollection = new ReactiveCollection<Person>();
23
+ Add();
24
+ }
25
+ public static PersonList Instance { get { return m_instance; } }
26
+
18
27
  ReactiveCollection<Person> m_collection;
19
28
  public ReactiveCollection<Person> PersonCollection
20
29
  {
@@ -28,13 +37,20 @@
28
37
  get { return m_current; }
29
38
  set { SetProperty(ref m_current, value); }
30
39
  }
40
+
41
+ public void Add()
42
+ {
43
+ Person p = new Person();
44
+ PersonCollection.Add(p);
45
+ CurrentPerson = PersonCollection[PersonCollection.Count - 1];
46
+ }
31
47
  }
32
48
  ```
33
49
 
34
50
  #### Person
35
51
 
36
52
  ```C#
37
- class Person : BindableBase
53
+ public class Person : BindableBase
38
54
  {
39
55
  string m_name;
40
56
  public string Name
@@ -70,7 +86,7 @@
70
86
  }
71
87
  ```
72
88
 
73
- 上記クラスの`CurrentPerson`の中の`Name`プロパティは適切に変更されますが,`HereName`が`null`のままで書き換わってくれません.
89
+ 上記クラスの`CurrentPerson`の`Name`プロパティは適切に変更されますが,`HereName`が`null`のままで書き換わってくれません.
74
90
  どのように修正すればいいでしょうか?
75
91
 
76
92