質問編集履歴
5
コンパイルが通らない問題を解決しました
title
CHANGED
|
File without changes
|
body
CHANGED
|
@@ -14,36 +14,55 @@
|
|
|
14
14
|
#### PersonList(シングルトン)
|
|
15
15
|
|
|
16
16
|
```C#
|
|
17
|
+
using System;
|
|
17
|
-
|
|
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
|
-
|
|
27
|
+
public sealed class PersonList : BindableBase
|
|
20
|
-
|
|
21
|
-
private PersonList()
|
|
22
28
|
{
|
|
23
|
-
PersonCollection = new ReactiveCollection<Person>();
|
|
24
|
-
Add();
|
|
25
|
-
}
|
|
26
|
-
|
|
29
|
+
static readonly PersonList m_instance = new PersonList();
|
|
27
30
|
|
|
28
|
-
ReactiveCollection<Person> m_collection;
|
|
29
|
-
|
|
31
|
+
public static PersonList Instance
|
|
30
|
-
|
|
32
|
+
{
|
|
31
|
-
|
|
33
|
+
get { return m_instance; }
|
|
32
|
-
set { SetProperty(ref m_collection, value); }
|
|
33
|
-
|
|
34
|
+
}
|
|
34
35
|
|
|
35
|
-
|
|
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
|
-
|
|
59
|
+
public void Add()
|
|
43
|
-
|
|
60
|
+
{
|
|
44
|
-
|
|
61
|
+
Person p = new Person(count);
|
|
45
|
-
|
|
62
|
+
PersonCollection.Add(p);
|
|
46
|
-
|
|
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
|
-
|
|
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
|
|
83
|
+
public class Person : BindableBase
|
|
58
84
|
{
|
|
59
|
-
|
|
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
|
-
|
|
94
|
+
int m_age;
|
|
64
|
-
|
|
95
|
+
public int Age
|
|
65
|
-
|
|
96
|
+
{
|
|
66
|
-
|
|
97
|
+
get { return m_age; }
|
|
67
|
-
|
|
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
|
-
|
|
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
|
|
121
|
+
public class MainWindowViewModel : BindableBase
|
|
87
|
-
|
|
88
|
-
public MyViewModel()
|
|
89
122
|
{
|
|
90
|
-
// ComboBoxで表示されるリスト
|
|
91
|
-
|
|
123
|
+
private string _title = "Prism Application";
|
|
124
|
+
public string Title
|
|
125
|
+
{
|
|
126
|
+
get { return _title; }
|
|
92
|
-
|
|
127
|
+
set { SetProperty(ref _title, value); }
|
|
93
|
-
|
|
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
|
-
|
|
131
|
+
public ReactiveProperty<Person> CurrentPerson { get; }
|
|
132
|
+
public ReactiveProperty<string> HereName { get; }
|
|
133
|
+
public ReactiveProperty<int> HereAge { get; }
|
|
99
|
-
|
|
134
|
+
public ReactiveProperty<string> Introduction { get; }
|
|
100
135
|
|
|
101
|
-
|
|
136
|
+
public ReactiveCommand<string> UIInteractiveNameCommand { get; }
|
|
102
|
-
{
|
|
137
|
+
public ReactiveCommand<int> UIInteractiveAgeCommand { get; }
|
|
103
|
-
|
|
138
|
+
public ReactiveCommand AddCommand { get; }
|
|
104
|
-
});
|
|
105
139
|
|
|
106
|
-
|
|
140
|
+
public MainWindowViewModel()
|
|
107
141
|
{
|
|
108
|
-
|
|
142
|
+
Collection = PersonList.Instance.PersonCollection;
|
|
109
|
-
|
|
143
|
+
CurrentPerson = PersonList.Instance.ToReactivePropertyAsSynchronized(x => x.CurrentPerson);
|
|
110
144
|
|
|
111
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
203
|
+
<Button Grid.Row="2" Grid.Column="1" Content="登録" Margin="20"
|
|
204
|
+
Command="{Binding UIInteractiveAgeCommand}"
|
|
124
|
-
|
|
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
ソースコードの修正
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
ソースコード及びやりたいことの追記
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
|
|
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
|
-
|
|
97
|
+
UIInteractiveNameCommand = new ReactiveCommand<string>().WithSubscribe(x =>
|
|
82
98
|
{
|
|
83
|
-
CurrentPerson.
|
|
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
ソースコードの修正を行いました.
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
ソースコードの修正を行いました.
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`の
|
|
89
|
+
上記クラスの`CurrentPerson`の`Name`プロパティは適切に変更されますが,`HereName`が`null`のままで書き換わってくれません.
|
|
74
90
|
どのように修正すればいいでしょうか?
|
|
75
91
|
|
|
76
92
|
|