回答編集履歴

1

見直しキャンペーン中

2023/07/25 14:04

投稿

TN8001
TN8001

スコア9326

test CHANGED
@@ -1,365 +1,181 @@
1
1
  XY 問題な気がします。本当にやりたいことは何ですか?
2
-
3
2
  [「XY 問題」とは何ですか? - スタック・オーバーフローMeta](https://ja.meta.stackoverflow.com/questions/2701/xy-%E5%95%8F%E9%A1%8C-%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%A7%E3%81%99%E3%81%8B)
4
-
5
-
6
-
7
3
 
8
4
 
9
5
  > 一つのコントロールに複数のプロパティを紐づけたく
10
6
 
11
-
12
-
13
7
  複数のプロパティをバインドするなら、`MultiBinding`があります。
14
8
 
15
-
16
-
17
9
  [BindingBase.StringFormat プロパティ (System.Windows.Data) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.data.bindingbase.stringformat)
18
-
19
10
  [IMultiValueConverter インターフェイス (System.Windows.Data) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.data.imultivalueconverter)
20
-
21
-
22
-
23
11
 
24
12
 
25
13
  しかしコードを見るに「バインド先を切り替えたい」ように見えます。
26
14
 
27
-
28
-
29
15
  であれば`ViewModel`側で、切り替え後の値を提供するのが真っ当に思います。
30
-
31
16
  手を抜くなら2つコントロールを置いて、`Visibility`を切り替えるとか^^;
32
-
33
-
34
-
35
17
 
36
18
 
37
19
  > Passが見つからないのがエラーの原因だと考えています。
38
20
 
39
-
40
-
41
21
  Passが見つからないというか`StackOverflowException`ですので、`Mein`と`ViewModel`をぐるぐるしてしまうみたいな状況じゃないでしょうか(よくわかっていませんが^^;
42
-
43
-
44
22
 
45
23
  `Binding`は`DataContext`から探しますから、その`DataContext`自身を切り替えたらダメでしょう(`DataContext`とは何なのかをしっかり意識しましょう)
46
24
 
47
-
48
-
49
- どうしても今の形にこだわるなら、
25
+ どうしても今の形にこだわるなら、↓のようになっていないといけません。
50
-
51
- ```xaml
26
+ ```xml
52
-
53
27
  <DataTrigger Binding="{Binding DataContext.Pass, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="true">
54
-
55
28
  <Setter Property="DataContext" Value="{Binding VM1}" />
56
-
57
29
  </DataTrigger>
58
-
59
- ```
60
-
61
- というようになっていないといけません。
62
-
63
-
64
-
65
-
66
-
67
- ```xaml
68
-
69
- <Window
70
-
71
- x:Class="Questions310362.MainWindow"
72
-
73
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
74
-
75
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
76
-
77
- xmlns:local="clr-namespace:Questions310362"
78
-
79
- Width="450"
80
-
81
- SizeToContent="Height">
82
-
83
- <Window.DataContext>
84
-
85
- <local:MainViewModel />
86
-
87
- </Window.DataContext>
88
-
89
- <Window.Resources>
90
-
91
- <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
92
-
93
- <local:AConverter x:Key="AConverter" />
94
-
95
-
96
-
97
- <Style x:Key="Style" TargetType="{x:Type TextBlock}">
98
-
99
- <Style.Triggers>
100
-
101
- <DataTrigger Binding="{Binding DataContext.Pass, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="true">
102
-
103
- <Setter Property="DataContext" Value="{Binding VM1}" />
104
-
105
- </DataTrigger>
106
-
107
- <DataTrigger Binding="{Binding DataContext.Pass, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="false">
108
-
109
- <Setter Property="DataContext" Value="{Binding VM2}" />
110
-
111
- </DataTrigger>
112
-
113
- </Style.Triggers>
114
-
115
- </Style>
116
-
117
- </Window.Resources>
118
-
119
- <StackPanel>
120
-
121
- <Button Command="{Binding ButtonPush}" Content="Button" />
122
-
123
-
124
-
125
- <GroupBox Margin="5" Header="StringFormat">
126
-
127
- <TextBlock>
128
-
129
- <TextBlock.Text>
130
-
131
- <MultiBinding StringFormat="VM1:{0}, VM2:{1}">
132
-
133
- <Binding Path="VM1.A" />
134
-
135
- <Binding Path="VM2.A" />
136
-
137
- </MultiBinding>
138
-
139
- </TextBlock.Text>
140
-
141
- </TextBlock>
142
-
143
- </GroupBox>
144
-
145
-
146
-
147
- <GroupBox Margin="5" Header="IMultiValueConverter">
148
-
149
- <TextBlock>
150
-
151
- <TextBlock.Text>
152
-
153
- <MultiBinding Converter="{StaticResource AConverter}">
154
-
155
- <Binding Path="Pass" />
156
-
157
- <Binding Path="VM1.A" />
158
-
159
- <Binding Path="VM2.A" />
160
-
161
- </MultiBinding>
162
-
163
- </TextBlock.Text>
164
-
165
- </TextBlock>
166
-
167
- </GroupBox>
168
-
169
-
170
-
171
- <GroupBox Margin="5" Header="切り替え後の値 VM">
172
-
173
- <TextBlock Text="{Binding VM.A}" />
174
-
175
- </GroupBox>
176
-
177
-
178
-
179
- <GroupBox Margin="5" Header="切り替え後の値 A">
180
-
181
- <TextBlock Text="{Binding A}" />
182
-
183
- </GroupBox>
184
-
185
-
186
-
187
- <GroupBox Margin="5" Header="手抜き">
188
-
189
- <Grid>
190
-
191
- <TextBlock Text="{Binding VM2.A}" />
192
-
193
- <TextBlock
194
-
195
- Background="White"
196
-
197
- Text="{Binding VM1.A}"
198
-
199
- Visibility="{Binding Pass, Converter={StaticResource BooleanToVisibilityConverter}}" />
200
-
201
- </Grid>
202
-
203
- </GroupBox>
204
-
205
-
206
-
207
- <GroupBox Margin="5" Header="DataTrigger">
208
-
209
- <TextBlock Style="{StaticResource Style}" Text="{Binding A}" />
210
-
211
- </GroupBox>
212
-
213
- </StackPanel>
214
-
215
- </Window>
216
-
217
30
  ```
218
31
 
219
32
 
33
+ ```xml
34
+ <Window
35
+ x:Class="Questions310362.MainWindow"
36
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
37
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
38
+ xmlns:local="clr-namespace:Questions310362"
39
+ Width="450"
40
+ SizeToContent="Height">
41
+ <Window.DataContext>
42
+ <local:MainViewModel />
43
+ </Window.DataContext>
44
+ <Window.Resources>
45
+ <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
46
+ <local:AConverter x:Key="AConverter" />
220
47
 
48
+ <Style x:Key="Style" TargetType="{x:Type TextBlock}">
49
+ <Style.Triggers>
50
+ <DataTrigger Binding="{Binding DataContext.Pass, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="true">
51
+ <Setter Property="DataContext" Value="{Binding VM1}" />
52
+ </DataTrigger>
53
+ <DataTrigger Binding="{Binding DataContext.Pass, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="false">
54
+ <Setter Property="DataContext" Value="{Binding VM2}" />
55
+ </DataTrigger>
56
+ </Style.Triggers>
221
- ```C#
57
+ </Style>
58
+ </Window.Resources>
59
+ <StackPanel>
60
+ <Button Command="{Binding ButtonPush}" Content="Button" />
222
61
 
62
+ <GroupBox Margin="5" Header="StringFormat">
63
+ <TextBlock>
64
+ <TextBlock.Text>
65
+ <MultiBinding StringFormat="VM1:{0}, VM2:{1}">
66
+ <Binding Path="VM1.A" />
67
+ <Binding Path="VM2.A" />
68
+ </MultiBinding>
69
+ </TextBlock.Text>
70
+ </TextBlock>
71
+ </GroupBox>
72
+
73
+ <GroupBox Margin="5" Header="IMultiValueConverter">
74
+ <TextBlock>
75
+ <TextBlock.Text>
76
+ <MultiBinding Converter="{StaticResource AConverter}">
77
+ <Binding Path="Pass" />
78
+ <Binding Path="VM1.A" />
79
+ <Binding Path="VM2.A" />
80
+ </MultiBinding>
81
+ </TextBlock.Text>
82
+ </TextBlock>
83
+ </GroupBox>
84
+
85
+ <GroupBox Margin="5" Header="切り替え後の値 VM">
86
+ <TextBlock Text="{Binding VM.A}" />
87
+ </GroupBox>
88
+
89
+ <GroupBox Margin="5" Header="切り替え後の値 A">
90
+ <TextBlock Text="{Binding A}" />
91
+ </GroupBox>
92
+
93
+ <GroupBox Margin="5" Header="手抜き">
94
+ <Grid>
95
+ <TextBlock Text="{Binding VM2.A}" />
96
+ <TextBlock
97
+ Background="White"
98
+ Text="{Binding VM1.A}"
99
+ Visibility="{Binding Pass, Converter={StaticResource BooleanToVisibilityConverter}}" />
100
+ </Grid>
101
+ </GroupBox>
102
+
103
+ <GroupBox Margin="5" Header="DataTrigger">
104
+ <TextBlock Style="{StaticResource Style}" Text="{Binding A}" />
105
+ </GroupBox>
106
+ </StackPanel>
107
+ </Window>
108
+ ```
109
+
110
+ ```cs
223
111
  using Prism.Commands;
224
-
225
112
  using Prism.Mvvm;
226
-
227
113
  using System;
228
-
229
114
  using System.Diagnostics;
230
-
231
115
  using System.Globalization;
232
-
233
116
  using System.Windows;
234
-
235
117
  using System.Windows.Data;
236
118
 
237
-
238
-
239
119
  namespace Questions310362
240
-
241
120
  {
242
-
243
121
  internal class AConverter : IMultiValueConverter
244
-
245
122
  {
246
-
247
123
  public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
248
-
249
124
  {
250
-
251
125
  if (values[0] is bool pass) return pass ? values[1].ToString() : values[2].ToString();
252
-
253
126
  return DependencyProperty.UnsetValue;
254
-
255
127
  }
256
-
257
128
  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotSupportedException();
258
-
259
129
  }
260
130
 
261
-
262
-
263
131
  internal class MainViewModel : BindableBase
264
-
265
132
  {
266
-
267
133
  private bool _pass;
268
-
269
134
  public bool Pass { get => _pass; set => SetProperty(ref _pass, value); }
270
-
271
135
  public ChildViewModel VM1 { get; } = new();
272
-
273
136
  public ChildViewModel VM2 { get; } = new();
274
-
275
137
  public ChildViewModel VM => Pass ? VM1 : VM2;
276
-
277
138
  public int A => Pass ? VM1.A : VM2.A;
278
-
279
-
280
139
 
281
140
  public DelegateCommand ButtonPush { get; }
282
141
 
283
-
284
-
285
142
  public MainViewModel() => ButtonPush = new(Push);
286
143
 
287
-
288
-
289
144
  private int i = 2;
290
-
291
145
  private void Push()
292
-
293
146
  {
294
-
295
147
  Pass = ++i % 2 == 0;
296
-
297
148
  VM1.Calculate(i);
298
-
299
149
  VM2.Calculate(-i); // 違いが出ないのでマイナス
300
150
 
301
-
302
-
303
151
  OnPropertyChanged(new(nameof(VM))); // VM変更通知
304
-
305
152
  OnPropertyChanged(new(nameof(A))); // A変更通知
306
153
 
307
-
308
-
309
154
  Debug.WriteLine($"VM1:{VM1.A}, VM2:{VM2.A}");
310
-
311
155
  }
312
-
313
156
  }
314
157
 
315
-
316
-
317
158
  internal class ChildViewModel : BindableBase
318
-
319
159
  {
320
-
321
160
  private int _a;
322
-
323
161
  public int A { get => _a; set => SetProperty(ref _a, value); }
324
-
325
162
  public void Calculate(int c) => A = 2 * c;
326
-
327
163
  }
328
164
 
329
-
330
-
331
165
  public partial class MainWindow : Window
332
-
333
166
  {
334
-
335
167
  public MainWindow() => InitializeComponent();
336
-
337
168
  }
338
-
339
169
  }
340
-
341
170
  ```
342
-
343
171
  ![アプリ画像](f2b2b8ba19667f538401a81c59fc2f1f.png)
344
-
345
-
346
172
 
347
173
  ---
348
174
 
349
-
350
-
351
175
  `BindableBase`・`DelegateCommand`は、`Prism.Core`を使用しました。
352
-
353
176
  [NuGet Gallery | Prism.Core 8.0.0.1909](https://www.nuget.org/packages/Prism.Core/)
354
177
 
355
-
356
-
357
- 特に指定がないので`.NET 5.0`で書きました^^
178
+ 特に指定がないので.NET 5.0で書きました^^
358
-
359
- `.NET Framework 4.8`等では、`new()`でエラーが出るので型を書いてください。
179
+ .NET Framework 4.8等では、`new()`でエラーが出るので型を書いてください。
360
-
361
-
362
-
363
180
  [Target-typed new expressions - C# 9.0 specification proposals | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/proposals/csharp-9.0/target-typed-new)
364
-
365
181
  [ターゲットからの new 型推論 | ++C++; // 未確認飛行 C](https://ufcpp.net/study/csharp/oo_construct.html#target-typed-new)