回答編集履歴
4
無駄x:Name
test
CHANGED
@@ -99,7 +99,7 @@
|
|
99
99
|
</Style>
|
100
100
|
</Window.Resources>
|
101
101
|
|
102
|
-
<Grid
|
102
|
+
<Grid>
|
103
103
|
<Grid.ColumnDefinitions>
|
104
104
|
<ColumnDefinition Width="2*" />
|
105
105
|
<ColumnDefinition />
|
3
(7*6週分=42個)
test
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
> 別月に移動すると同じセル位置に文字が表示される
|
7
7
|
|
8
|
-
`CalendarDayButton`は1か月分しか作らずに、すべての月で使いまわしているせいですね。
|
8
|
+
`CalendarDayButton`は1か月分(7*6週分=42個)しか作らずに、すべての月で使いまわしているせいですね。
|
9
9
|
|
10
10
|
> WPFのカレンダーコントロールのコメント欄を追加したい
|
11
11
|
|
2
わかりやすさ重視でコードビハインドに変更
test
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
|
12
12
|
参考サイトではすべてのコメントを`ObservableCollection`で保持し、`MultiValueConverter`で**その日**のコメントを表示するのが肝になっています。
|
13
13
|
|
14
|
-
`
|
14
|
+
ですが`ConvertBack`で追加や変更を反映できるわけでもないので、わかりやすさ重視ですべてコードビハインドに変更しました^^(MVVM教の方はビヘイビアにでもしてください)
|
15
15
|
|
16
16
|
あとなぜか`TextBox`にキーボードフォーカスが入りません(`Calendar`が選択周りで何かやってそう)でしたので、クソい手を使っていますw
|
17
17
|
|
@@ -22,20 +22,27 @@
|
|
22
22
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
23
23
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
24
24
|
xmlns:gl="clr-namespace:System.Globalization;assembly=mscorlib"
|
25
|
-
xmlns:local="clr-namespace:Qa6deqmgkhn71do"
|
26
25
|
SizeToContent="WidthAndHeight">
|
27
26
|
<Window.Resources>
|
28
|
-
<local:CalendarCommentConverter x:Key="CalendarCommentConverter" />
|
29
|
-
|
30
27
|
<Style x:Key="CalendarDayButtonStyle1" TargetType="{x:Type CalendarDayButton}">
|
28
|
+
|
29
|
+
<!-- デフォルトからの変更点 追加 -->
|
31
30
|
<EventSetter Event="PreviewMouseUp" Handler="CalendarDayButton_PreviewMouseUp" />
|
31
|
+
|
32
32
|
<Setter Property="MinWidth" Value="5" />
|
33
33
|
<Setter Property="MinHeight" Value="5" />
|
34
|
+
|
35
|
+
<!-- デフォルトからの変更点 削除 -->
|
36
|
+
<!--<Setter Property="FontSize" Value="10" />-->
|
37
|
+
|
34
38
|
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
35
39
|
<Setter Property="VerticalContentAlignment" Value="Center" />
|
36
40
|
<Setter Property="Template">
|
37
41
|
<Setter.Value>
|
38
42
|
<ControlTemplate TargetType="{x:Type CalendarDayButton}">
|
43
|
+
|
44
|
+
<!-- デフォルトからの変更点 Width・Height追加 -->
|
45
|
+
<!--<Grid>-->
|
39
46
|
<Grid Width="80" Height="80">
|
40
47
|
<Rectangle x:Name="TodayBackground" Fill="#FFAAAAAA" Opacity="0" RadiusX="1" RadiusY="1" />
|
41
48
|
<Rectangle x:Name="SelectedBackground" Fill="#FFBADDE9" Opacity="0" RadiusX="1" RadiusY="1" />
|
@@ -44,6 +51,14 @@
|
|
44
51
|
BorderBrush="{TemplateBinding BorderBrush}"
|
45
52
|
BorderThickness="{TemplateBinding BorderThickness}" />
|
46
53
|
<Rectangle x:Name="HighlightBackground" Fill="#FFBADDE9" Opacity="0" RadiusX="1" RadiusY="1" />
|
54
|
+
|
55
|
+
<!-- デフォルトからの変更点 VerticalAlignment="Top" -->
|
56
|
+
<!--<ContentPresenter
|
57
|
+
x:Name="NormalText"
|
58
|
+
Margin="5,1,5,1"
|
59
|
+
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
60
|
+
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
61
|
+
TextElement.Foreground="#FF333333" />-->
|
47
62
|
<ContentPresenter
|
48
63
|
x:Name="NormalText"
|
49
64
|
Margin="5,1,5,1"
|
@@ -51,19 +66,17 @@
|
|
51
66
|
VerticalAlignment="Top"
|
52
67
|
TextElement.Foreground="#FF333333" />
|
53
68
|
|
69
|
+
<!-- デフォルトからの変更点 追加 -->
|
54
70
|
<TextBox
|
55
71
|
x:Name="CalenderTimeTextBox"
|
56
72
|
Margin="3"
|
57
73
|
VerticalAlignment="Bottom"
|
58
74
|
BorderThickness="0"
|
75
|
+
DataContextChanged="CalenderTimeTextBox_DataContextChanged"
|
76
|
+
Loaded="CalenderTimeTextBox_Loaded"
|
59
|
-
TextChanged="CalenderTimeTextBox_TextChanged">
|
77
|
+
TextChanged="CalenderTimeTextBox_TextChanged" />
|
60
|
-
|
78
|
+
|
61
|
-
<MultiBinding Converter="{StaticResource CalendarCommentConverter}" Mode="OneWay">
|
62
|
-
<Binding Path="Date" />
|
63
|
-
<Binding ElementName="rootGrid" Path="DataContext.Comments" />
|
64
|
-
</MultiBinding>
|
65
|
-
</TextBox.Text>
|
66
|
-
<
|
79
|
+
<!-- 以下変更なし -->
|
67
80
|
|
68
81
|
<Path
|
69
82
|
x:Name="Blackout"
|
@@ -92,7 +105,10 @@
|
|
92
105
|
<ColumnDefinition />
|
93
106
|
</Grid.ColumnDefinitions>
|
94
107
|
|
108
|
+
<Calendar
|
109
|
+
x:Name="calendar"
|
110
|
+
Background="White"
|
95
|
-
|
111
|
+
CalendarDayButtonStyle="{StaticResource CalendarDayButtonStyle1}" />
|
96
112
|
|
97
113
|
<DataGrid
|
98
114
|
Grid.Column="1"
|
@@ -110,14 +126,13 @@
|
|
110
126
|
|
111
127
|
```cs
|
112
128
|
using System;
|
129
|
+
using System.Collections.Generic;
|
113
130
|
using System.Collections.ObjectModel;
|
114
|
-
using System.Globalization;
|
115
131
|
using System.Linq;
|
116
132
|
using System.Threading.Tasks;
|
117
133
|
using System.Windows;
|
118
134
|
using System.Windows.Controls;
|
119
135
|
using System.Windows.Controls.Primitives;
|
120
|
-
using System.Windows.Data;
|
121
136
|
using System.Windows.Input;
|
122
137
|
using System.Windows.Media;
|
123
138
|
using CommunityToolkit.Mvvm.ComponentModel;
|
@@ -125,104 +140,130 @@
|
|
125
140
|
|
126
141
|
namespace Qa6deqmgkhn71do
|
127
142
|
{
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
143
|
+
public class ViewModel
|
144
|
+
{
|
145
|
+
public ObservableCollection<Comment> Comments { get; }
|
146
|
+
|
147
|
+
public ViewModel()
|
148
|
+
{
|
149
|
+
Comments = new ObservableCollection<Comment>
|
150
|
+
{
|
151
|
+
new Comment("first", DateTime.Now),
|
152
|
+
new Comment("second", DateTime.Now.AddDays(1)),
|
153
|
+
new Comment("third", DateTime.Now.AddDays(7)),
|
154
|
+
new Comment("forth", DateTime.Now.AddMonths(1)),
|
155
|
+
new Comment("fifth", DateTime.Now.AddMonths(1).AddDays(1)),
|
156
|
+
new Comment("sixth", DateTime.Now.AddMonths(1).AddDays(7)),
|
157
|
+
};
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
public class Comment : ObservableObject
|
162
|
+
{
|
163
|
+
public string Value { get => _Value; set => SetProperty(ref _Value, value); }
|
164
|
+
private string _Value;
|
165
|
+
|
166
|
+
public DateTime Date { get; } // 日時のみ(常に0:00:00)
|
167
|
+
|
168
|
+
public Comment(string value, DateTime date) => (Value, Date) = (value, date.Date);
|
169
|
+
}
|
170
|
+
|
171
|
+
public partial class MainWindow : Window
|
172
|
+
{
|
173
|
+
private readonly ViewModel vm = new ViewModel();
|
174
|
+
|
175
|
+
public MainWindow()
|
176
|
+
{
|
177
|
+
InitializeComponent();
|
178
|
+
DataContext = vm;
|
179
|
+
}
|
180
|
+
|
181
|
+
// TextBoxが読み込まれたとき(初回1回だけ)CalendarDayButton分(7*6週分=42個)呼ばれる
|
182
|
+
private void CalenderTimeTextBox_Loaded(object sender, RoutedEventArgs e)
|
183
|
+
{
|
184
|
+
if (sender is TextBox textBox && textBox.DataContext is DateTime date)
|
185
|
+
{
|
186
|
+
// TextBox(CalendarDayButton)のDataContextはDateTime(例えば2023/05/21 0:00:00)
|
187
|
+
// CommentsのDateが一致したもの(同日にコメントは1件の想定)があれば
|
188
|
+
// Value(コメント文)をTextにセット
|
189
|
+
textBox.Text = vm.Comments?.FirstOrDefault(x => x.Date == date)?.Value;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
// DataContextが変わったとき(=月が替わったとき)都度CalendarDayButton分呼ばれる
|
194
|
+
private void CalenderTimeTextBox_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
195
|
+
// やることは↑と同じなので雑に呼び出しw
|
196
|
+
=> CalenderTimeTextBox_Loaded(sender, default);
|
197
|
+
|
198
|
+
// ユーザーが何か文字入力(文字削除)したとき
|
199
|
+
private void CalenderTimeTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
200
|
+
{
|
201
|
+
if (sender is TextBox textBox && textBox.DataContext is DateTime date)
|
202
|
+
{
|
203
|
+
// 同日にコメントは1件の想定
|
204
|
+
var comment = vm.Comments.FirstOrDefault(x => x.Date.Date == date);
|
205
|
+
|
206
|
+
if (comment != null) // すでにコメントがあれば...
|
207
|
+
{
|
208
|
+
if (!string.IsNullOrEmpty(textBox.Text))
|
209
|
+
comment.Value = textBox.Text; // Valueを更新
|
210
|
+
else
|
211
|
+
vm.Comments.Remove(comment); // 空コメントはまるごと削除
|
212
|
+
}
|
213
|
+
else // コメントがまだなければ...
|
214
|
+
{
|
215
|
+
if (!string.IsNullOrEmpty(textBox.Text))
|
216
|
+
vm.Comments.Add(new Comment(textBox.Text, date)); // 追加
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
private async void CalendarDayButton_PreviewMouseUp(object sender, MouseButtonEventArgs e)
|
222
|
+
{
|
223
|
+
// キーボードフォーカスがうまく入らないのと
|
224
|
+
// カレンダーの[前の月|次の月]の日を選択すると月が替わるため
|
225
|
+
// クリック後ちょっと時間をおいてから選択日のTextBoxをフォーカス
|
226
|
+
await Task.Delay(10);
|
227
|
+
calendar.Descendants<CalendarDayButton>()
|
228
|
+
.FirstOrDefault(x => x.IsSelected)
|
229
|
+
?.Descendants<TextBox>()
|
230
|
+
?.FirstOrDefault()
|
231
|
+
?.Focus();
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
|
236
|
+
// [VisualTreeの子孫要素を取得する - xin9le.net](https://blog.xin9le.net/entry/2013/10/29/222336)
|
237
|
+
public static class DependencyObjectExtensions
|
238
|
+
{
|
239
|
+
public static IEnumerable<DependencyObject> Children(this DependencyObject obj)
|
240
|
+
{
|
241
|
+
if (obj == null) throw new ArgumentNullException(nameof(obj));
|
242
|
+
|
243
|
+
var count = VisualTreeHelper.GetChildrenCount(obj);
|
244
|
+
if (count == 0) yield break;
|
245
|
+
for (var i = 0; i < count; i++)
|
246
|
+
{
|
247
|
+
var child = VisualTreeHelper.GetChild(obj, i);
|
248
|
+
if (child != null) yield return child;
|
249
|
+
}
|
250
|
+
}
|
251
|
+
public static IEnumerable<DependencyObject> Descendants(this DependencyObject obj)
|
252
|
+
{
|
253
|
+
if (obj == null) throw new ArgumentNullException(nameof(obj));
|
254
|
+
|
255
|
+
foreach (var child in obj.Children())
|
256
|
+
{
|
257
|
+
yield return child;
|
258
|
+
foreach (var grandChild in child.Descendants()) yield return grandChild;
|
259
|
+
}
|
260
|
+
}
|
261
|
+
public static IEnumerable<T> Descendants<T>(this DependencyObject obj) where T : DependencyObject => obj.Descendants().OfType<T>();
|
262
|
+
}
|
223
263
|
}
|
224
264
|
```
|
225
265
|
[NuGet Gallery | CommunityToolkit.Mvvm 8.2.0](https://www.nuget.org/packages/CommunityToolkit.Mvvm/8.2.0)
|
226
266
|
|
267
|
+
---
|
227
268
|
|
228
269
|
![アプリ画像](https://ddjkaamml8q8x.cloudfront.net/questions/2023-05-21/1c4e2692-d416-4651-ba9f-a004797e9d42.png)
|
1
は
test
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
|
16
16
|
あとなぜか`TextBox`にキーボードフォーカスが入りません(`Calendar`が選択周りで何かやってそう)でしたので、クソい手を使っていますw
|
17
17
|
|
18
|
-
参考サイトは同日に複数コメント対応ですが、(回答
|
18
|
+
参考サイトは同日に複数コメント対応ですが、(回答コードは)`TextBox`がひとつだけなので1件のみです。
|
19
19
|
```xml
|
20
20
|
<Window
|
21
21
|
x:Class="Qa6deqmgkhn71do.MainWindow"
|