回答編集履歴
1
見直しキャンペーン中
test
CHANGED
@@ -1,541 +1,271 @@
|
|
1
|
-
|
1
|
+
WPFでMVVMするには、WinForms的な考え方は捨ててください。
|
2
|
-
|
3
|
-
|
2
|
+
コントロールにどう入れるかではなく、表示したいデータ(Model≒ViewModel)をバインドし、結果的にテンプレートが当たって表示されます。
|
4
|
-
|
5
|
-
|
6
3
|
|
7
4
|
> カレンダーの日付部分にあたる箇所
|
8
5
|
|
9
|
-
|
10
|
-
|
11
6
|
カレンダーを作っているわけですね。
|
12
|
-
|
13
7
|
日付は1~31あってそれを表示したいのであれば、その数字のコレクション(例えば`List<int>`)を作ってバインドします。
|
14
|
-
|
15
8
|
コレクションですから、`ItemsControl`や`ListBox`にバインドすることになります。
|
16
9
|
|
17
|
-
|
18
|
-
|
19
10
|
`Grid`にこだわりがあるなら↓こういった手法があります。
|
20
|
-
|
21
11
|
[Gridへのアイテムのバインド(WPF編) | 泥庭](https://yone64.wordpress.com/2013/05/29/grid%E3%81%B8%E3%81%AE%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%81%AE%E3%83%90%E3%82%A4%E3%83%B3%E3%83%89%EF%BC%88wpf%E7%B7%A8%EF%BC%89/)
|
22
12
|
|
23
|
-
|
24
|
-
|
25
13
|
しかしカレンダーは`UniformGrid`のほうが向いていますので、回答はそちらを採用しました。
|
26
14
|
|
27
|
-
|
28
|
-
|
29
15
|
[ItemsControl 攻略 ~ 外観のカスタマイズ | grabacr.nét](http://grabacr.net/archives/1240)
|
30
|
-
|
31
16
|
こちらをじっくり読んで、各テンプレート等がどういう役割か把握しておいてください(ブックマーク推奨)
|
32
17
|
|
33
|
-
|
34
|
-
|
35
|
-
```x
|
18
|
+
```xml
|
36
|
-
|
37
19
|
<Window
|
38
|
-
|
39
20
|
x:Class="Questions333874.Views.MainWindow"
|
40
|
-
|
41
21
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
42
|
-
|
43
22
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
44
|
-
|
45
23
|
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
|
46
|
-
|
47
24
|
xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
|
48
|
-
|
49
25
|
xmlns:m="clr-namespace:Questions333874.Models"
|
50
|
-
|
51
26
|
xmlns:vm="clr-namespace:Questions333874.ViewModels"
|
52
|
-
|
53
27
|
Width="650" Height="550">
|
54
28
|
|
55
|
-
|
56
|
-
|
57
29
|
<Window.Resources>
|
58
|
-
|
59
30
|
<DataTemplate DataType="{x:Type m:Schedule}">
|
60
|
-
|
61
31
|
<TextBlock Text="{Binding Text}" />
|
62
|
-
|
63
32
|
</DataTemplate>
|
64
|
-
|
65
33
|
</Window.Resources>
|
66
34
|
|
67
|
-
|
68
|
-
|
69
35
|
<Window.DataContext>
|
70
|
-
|
71
36
|
<vm:MainWindowViewModel />
|
72
|
-
|
73
37
|
</Window.DataContext>
|
74
38
|
|
75
|
-
|
76
|
-
|
77
39
|
<behaviors:Interaction.Triggers>
|
78
|
-
|
79
40
|
<behaviors:EventTrigger EventName="ContentRendered">
|
80
|
-
|
81
41
|
<l:LivetCallMethodAction MethodName="Initialize" MethodTarget="{Binding}" />
|
82
|
-
|
83
42
|
</behaviors:EventTrigger>
|
84
|
-
|
85
43
|
</behaviors:Interaction.Triggers>
|
86
44
|
|
87
|
-
|
88
|
-
|
89
45
|
<DockPanel>
|
90
|
-
|
91
46
|
<DockPanel Margin="10" DockPanel.Dock="Bottom">
|
92
|
-
|
93
47
|
<Button Command="{Binding AddCommand}" Content="Add" DockPanel.Dock="Right" IsDefault="True" />
|
94
|
-
|
95
48
|
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
|
96
|
-
|
97
49
|
</DockPanel>
|
98
50
|
|
99
|
-
|
100
|
-
|
101
51
|
<GroupBox Margin="10" Padding="10">
|
102
|
-
|
103
52
|
<GroupBox.Header>
|
104
|
-
|
105
53
|
<StackPanel Orientation="Horizontal">
|
106
|
-
|
107
54
|
<TextBlock VerticalAlignment="Center" Text="{Binding HeaderMonth}" />
|
108
|
-
|
109
55
|
<Button Command="{Binding PreviousCommand}" Content="<" />
|
110
|
-
|
111
56
|
<Button Command="{Binding NextCommand}" Content=">" />
|
112
|
-
|
113
57
|
</StackPanel>
|
114
|
-
|
115
58
|
</GroupBox.Header>
|
116
59
|
|
117
|
-
|
118
|
-
|
119
60
|
<ListBox HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" ItemsSource="{Binding Items}" SelectedItem="{Binding Selected}">
|
120
|
-
|
121
61
|
<ListBox.Template>
|
122
|
-
|
123
62
|
<ControlTemplate TargetType="ListBox">
|
124
|
-
|
125
63
|
<Border BorderBrush="Black" BorderThickness="1">
|
126
|
-
|
127
64
|
<DockPanel>
|
128
|
-
|
129
65
|
<Border BorderBrush="Black" BorderThickness="0,0,0,1" DockPanel.Dock="Top">
|
130
|
-
|
131
66
|
<UniformGrid Columns="7">
|
132
|
-
|
133
67
|
<UniformGrid.Resources>
|
134
|
-
|
135
68
|
<Style TargetType="Label">
|
136
|
-
|
137
69
|
<Setter Property="Margin" Value="1,0,0,0" />
|
138
|
-
|
139
70
|
<Setter Property="Padding" Value="0" />
|
140
|
-
|
141
71
|
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
142
|
-
|
143
72
|
<Setter Property="Background" Value="#B0E0E6" />
|
144
|
-
|
145
73
|
</Style>
|
146
|
-
|
147
74
|
</UniformGrid.Resources>
|
148
|
-
|
149
75
|
<Label Margin="0" Content="日" Foreground="Red" />
|
150
|
-
|
151
76
|
<Label Content="月" />
|
152
|
-
|
153
77
|
<Label Content="火" />
|
154
|
-
|
155
78
|
<Label Content="水" />
|
156
|
-
|
157
79
|
<Label Content="木" />
|
158
|
-
|
159
80
|
<Label Content="金" />
|
160
|
-
|
161
81
|
<Label Content="土" Foreground="Blue" />
|
162
|
-
|
163
82
|
</UniformGrid>
|
164
|
-
|
165
83
|
</Border>
|
166
|
-
|
167
84
|
<ItemsPresenter />
|
168
|
-
|
169
85
|
</DockPanel>
|
170
|
-
|
171
86
|
</Border>
|
172
|
-
|
173
87
|
</ControlTemplate>
|
174
|
-
|
175
88
|
</ListBox.Template>
|
176
89
|
|
177
|
-
|
178
|
-
|
179
90
|
<ListBox.ItemsPanel>
|
180
|
-
|
181
91
|
<ItemsPanelTemplate>
|
182
|
-
|
183
92
|
<UniformGrid Columns="7" FirstColumn="{Binding FirstDayOffset}" />
|
184
|
-
|
185
93
|
</ItemsPanelTemplate>
|
186
|
-
|
187
94
|
</ListBox.ItemsPanel>
|
188
95
|
|
189
|
-
|
190
|
-
|
191
96
|
<ListBox.ItemTemplate>
|
192
|
-
|
193
97
|
<DataTemplate>
|
194
|
-
|
195
98
|
<DockPanel>
|
196
|
-
|
197
99
|
<TextBlock HorizontalAlignment="Center" DockPanel.Dock="Top" Foreground="{Binding Color}" Text="{Binding Day}" />
|
198
|
-
|
199
100
|
<ItemsControl ItemsSource="{Binding Schedules}" />
|
200
|
-
|
201
101
|
</DockPanel>
|
202
|
-
|
203
102
|
</DataTemplate>
|
204
|
-
|
205
103
|
</ListBox.ItemTemplate>
|
206
|
-
|
207
104
|
</ListBox>
|
208
|
-
|
209
105
|
</GroupBox>
|
210
|
-
|
211
106
|
</DockPanel>
|
212
|
-
|
213
107
|
</Window>
|
214
|
-
|
215
108
|
```
|
216
109
|
|
217
|
-
|
218
|
-
|
219
|
-
```
|
110
|
+
```cs
|
220
|
-
|
221
111
|
using Livet;
|
222
|
-
|
223
112
|
using Livet.Commands;
|
224
|
-
|
225
113
|
using Questions333874.Models;
|
226
|
-
|
227
114
|
using System;
|
228
|
-
|
229
115
|
using System.Collections.Generic;
|
230
|
-
|
231
116
|
using System.Collections.ObjectModel;
|
232
|
-
|
233
117
|
using System.Linq;
|
234
|
-
|
235
118
|
using System.Windows.Media;
|
236
119
|
|
237
|
-
|
238
|
-
|
239
120
|
namespace Questions333874.ViewModels
|
240
|
-
|
241
121
|
{
|
242
|
-
|
243
122
|
public class DayViewModel //: ViewModel
|
244
|
-
|
245
123
|
{
|
246
|
-
|
247
124
|
public DateTime DateTime { get; set; }
|
248
|
-
|
249
125
|
public int Day => DateTime.Day;
|
250
|
-
|
251
126
|
public Brush Color => DateTime.DayOfWeek == DayOfWeek.Sunday ? Brushes.Red
|
252
|
-
|
253
127
|
: DateTime.DayOfWeek == DayOfWeek.Saturday ? Brushes.Blue
|
254
|
-
|
255
128
|
: Brushes.Black;
|
256
|
-
|
257
129
|
public ObservableCollection<Schedule> Schedules { get; } = new ObservableCollection<Schedule>();
|
258
|
-
|
259
130
|
}
|
260
131
|
|
261
|
-
|
262
|
-
|
263
132
|
public class MainWindowViewModel : ViewModel
|
264
|
-
|
265
133
|
{
|
266
|
-
|
267
134
|
public string HeaderMonth => current.ToString("yyyy/MM");
|
268
135
|
|
269
|
-
|
270
|
-
|
271
136
|
private int firstDayOffset;
|
272
|
-
|
273
137
|
public int FirstDayOffset { get => firstDayOffset; set => RaisePropertyChangedIfSet(ref firstDayOffset, value); }
|
274
138
|
|
275
|
-
|
276
|
-
|
277
139
|
private DayViewModel selected;
|
278
|
-
|
279
140
|
public DayViewModel Selected
|
280
|
-
|
281
|
-
{
|
141
|
+
{
|
282
|
-
|
283
142
|
get => selected;
|
284
|
-
|
285
143
|
set
|
286
|
-
|
287
|
-
{
|
144
|
+
{
|
288
|
-
|
289
145
|
if (RaisePropertyChangedIfSet(ref selected, value) && selected != null)
|
290
|
-
|
291
146
|
current = selected.DateTime.Date;
|
292
|
-
|
293
147
|
}
|
294
|
-
|
295
|
-
}
|
148
|
+
}
|
296
|
-
|
297
|
-
|
298
149
|
|
299
150
|
private List<DayViewModel> items;
|
300
|
-
|
301
151
|
public List<DayViewModel> Items { get => items; set => RaisePropertyChangedIfSet(ref items, value); }
|
302
152
|
|
303
|
-
|
304
|
-
|
305
153
|
private string text;
|
306
|
-
|
307
154
|
public string Text
|
308
|
-
|
309
|
-
{
|
155
|
+
{
|
310
|
-
|
311
156
|
get => text;
|
312
|
-
|
313
157
|
set
|
314
|
-
|
315
|
-
{
|
158
|
+
{
|
316
|
-
|
317
159
|
if (RaisePropertyChangedIfSet(ref text, value))
|
318
|
-
|
319
160
|
AddCommand.RaiseCanExecuteChanged();
|
320
|
-
|
321
161
|
}
|
322
|
-
|
323
|
-
}
|
162
|
+
}
|
324
|
-
|
325
|
-
|
326
|
-
|
327
163
|
|
328
164
|
|
329
165
|
private ViewModelCommand previousCommand;
|
330
|
-
|
331
166
|
public ViewModelCommand PreviousCommand => previousCommand ??= new ViewModelCommand(Previous);
|
332
|
-
|
333
167
|
private void Previous()
|
334
|
-
|
335
|
-
{
|
168
|
+
{
|
336
|
-
|
337
169
|
current = current.AddMonths(-1);
|
338
|
-
|
339
170
|
Update();
|
340
|
-
|
341
|
-
}
|
171
|
+
}
|
342
|
-
|
343
|
-
|
344
172
|
|
345
173
|
private ViewModelCommand nextCommand;
|
346
|
-
|
347
174
|
public ViewModelCommand NextCommand => nextCommand ??= new ViewModelCommand(Next);
|
348
|
-
|
349
175
|
private void Next()
|
350
|
-
|
351
|
-
{
|
176
|
+
{
|
352
|
-
|
353
177
|
current = current.AddMonths(1);
|
354
|
-
|
355
178
|
Update();
|
356
|
-
|
357
|
-
}
|
179
|
+
}
|
358
|
-
|
359
|
-
|
360
180
|
|
361
181
|
private ViewModelCommand addCommand;
|
362
|
-
|
363
182
|
public ViewModelCommand AddCommand => addCommand ??= new ViewModelCommand(Add, () => !string.IsNullOrEmpty(Text));
|
364
|
-
|
365
183
|
private void Add()
|
366
|
-
|
367
|
-
{
|
184
|
+
{
|
368
|
-
|
369
185
|
var s = new Schedule { DateTime = selected.DateTime.Date, Text = Text, };
|
370
|
-
|
371
186
|
schedules.Add(s);
|
372
|
-
|
373
187
|
selected.Schedules.Add(s);
|
374
|
-
|
375
188
|
Text = null;
|
376
|
-
|
377
|
-
}
|
189
|
+
}
|
378
|
-
|
379
|
-
|
380
190
|
|
381
191
|
private List<Schedule> schedules = new List<Schedule>();
|
382
|
-
|
383
192
|
private DateTime current = DateTime.Now.Date;
|
384
193
|
|
385
|
-
|
386
|
-
|
387
194
|
// 月変更時 Items再生成 雑w
|
388
|
-
|
389
195
|
private void Update()
|
390
|
-
|
391
|
-
{
|
196
|
+
{
|
392
|
-
|
393
197
|
// 選択月 日数
|
394
|
-
|
395
198
|
var days = DateTime.DaysInMonth(current.Year, current.Month);
|
396
199
|
|
397
|
-
|
398
|
-
|
399
200
|
// 日数分DayViewModel作成
|
400
|
-
|
401
201
|
Items = Enumerable.Range(1, days).Select(x =>
|
402
|
-
|
403
|
-
{
|
202
|
+
{
|
404
|
-
|
405
203
|
var d = new DateTime(current.Year, current.Month, x);
|
406
|
-
|
407
204
|
return new DayViewModel { DateTime = d, };
|
408
|
-
|
409
205
|
}).ToList();
|
410
206
|
|
411
|
-
|
412
|
-
|
413
207
|
// DayViewModelにScheduleを突っ込む
|
414
|
-
|
415
208
|
foreach (var d in Items)
|
416
|
-
|
417
209
|
foreach (var s in schedules.Where(x => x.DateTime.Date == d.DateTime.Date))
|
418
|
-
|
419
210
|
d.Schedules.Add(s);
|
420
211
|
|
421
|
-
|
422
|
-
|
423
212
|
firstDayOffset = (int)new DateTime(current.Year, current.Month, 1).DayOfWeek;
|
424
|
-
|
425
213
|
selected = Items.Single(x => x.DateTime.Date == current.Date);
|
426
|
-
|
427
214
|
current = selected.DateTime.Date;
|
428
215
|
|
429
|
-
|
430
|
-
|
431
216
|
// 更新
|
432
|
-
|
433
217
|
RaisePropertyChanged(nameof(FirstDayOffset));
|
434
|
-
|
435
218
|
RaisePropertyChanged(nameof(HeaderMonth));
|
436
|
-
|
437
219
|
RaisePropertyChanged(nameof(Items));
|
438
|
-
|
439
220
|
RaisePropertyChanged(nameof(Selected));
|
440
|
-
|
441
|
-
}
|
221
|
+
}
|
442
|
-
|
443
|
-
|
444
222
|
|
445
223
|
public void Initialize()
|
446
|
-
|
447
|
-
{
|
224
|
+
{
|
448
|
-
|
449
225
|
// 見本Scheduleデータ作成
|
450
|
-
|
451
226
|
var r = new Random();
|
452
|
-
|
453
227
|
var n = DateTime.Now.Date;
|
454
|
-
|
455
228
|
schedules = Enumerable.Range(0, 10).Select(_ =>
|
456
|
-
|
457
|
-
{
|
229
|
+
{
|
458
|
-
|
459
230
|
var d = n.AddDays(r.Next(-30, 30));
|
460
|
-
|
461
231
|
return new Schedule { DateTime = d, Text = d.ToString("MM/dd の予定"), };
|
462
|
-
|
463
232
|
}).ToList();
|
464
233
|
|
465
|
-
|
466
|
-
|
467
234
|
Update();
|
468
|
-
|
469
|
-
}
|
235
|
+
}
|
470
|
-
|
471
236
|
}
|
472
|
-
|
473
237
|
}
|
474
|
-
|
475
238
|
```
|
476
239
|
|
477
|
-
|
478
|
-
|
479
|
-
```
|
240
|
+
```cs
|
480
|
-
|
481
241
|
using Livet;
|
482
|
-
|
483
242
|
using System;
|
484
|
-
|
485
243
|
using System.Diagnostics;
|
486
244
|
|
487
245
|
|
488
|
-
|
489
|
-
|
490
|
-
|
491
246
|
namespace Questions333874.Models
|
492
|
-
|
493
247
|
{
|
494
|
-
|
495
248
|
[DebuggerDisplay("{DateTime} {Text}")]
|
496
|
-
|
497
249
|
public class Schedule : NotificationObject
|
498
|
-
|
499
250
|
{
|
500
|
-
|
501
251
|
private DateTime dateTime;
|
502
|
-
|
503
252
|
public DateTime DateTime { get => dateTime; set => RaisePropertyChangedIfSet(ref dateTime, value); }
|
504
253
|
|
505
|
-
|
506
|
-
|
507
254
|
private string text;
|
508
|
-
|
509
255
|
public string Text { get => text; set => RaisePropertyChangedIfSet(ref text, value); }
|
510
|
-
|
511
256
|
}
|
512
|
-
|
513
257
|
}
|
514
|
-
|
515
258
|
```
|
516
259
|
|
517
|
-
|
518
|
-
|
519
260
|
![アプリ画像](143582f9facbd7b768725544b5280d23.png)
|
520
261
|
|
521
|
-
|
522
|
-
|
523
262
|
---
|
524
263
|
|
525
|
-
|
526
|
-
|
527
|
-
|
264
|
+
MVVM寄せで回答しましたが、私だったらこの方式は使いませんね。
|
528
|
-
|
529
|
-
|
530
|
-
|
265
|
+
|
531
|
-
カレンダー表示というのは、
|
266
|
+
カレンダー表示というのは、Viewの都合ですよね?(縦に並ぼうが横に並ぼうが、Modelは知ったこっちゃない)
|
532
|
-
|
533
267
|
カスタムコントロール(あるいはユーザーコントロール)を作って、`List<Schedule>`のようなものをバインドすれば勝手に表示するように作りますかね。
|
534
268
|
|
535
|
-
|
536
|
-
|
537
269
|
その際はバリバリにコードビハインドということになります(例えばこのような [wpf/Calendar.cs at main · dotnet/wpf](https://github.com/dotnet/wpf/blob/main/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Calendar.cs))
|
538
270
|
|
539
|
-
|
540
|
-
|
541
|
-
|
271
|
+
MVVMがパワーワードすぎて、なかなか本質が見えないのが難しく感じる原因でしょうか。
|