下記のサイトを参考にしています。
https://qiita.com/pregum/items/775b24fbf2eb80e43991
まったく影も形もありませんが、どういうことでしょうか?
別月に移動すると同じセル位置に文字が表示される
CalendarDayButton
は1か月分(7*6週分=42個)しか作らずに、すべての月で使いまわしているせいですね。
WPFのカレンダーコントロールのコメント欄を追加したい
参考サイトではすべてのコメントをObservableCollection
で保持し、MultiValueConverter
でその日のコメントを表示するのが肝になっています。
ですがConvertBack
で追加や変更を反映できるわけでもないので、わかりやすさ重視ですべてコードビハインドに変更しました^^(MVVM教の方はビヘイビアにでもしてください)
あとなぜかTextBox
にキーボードフォーカスが入りません(Calendar
が選択周りで何かやってそう)でしたので、クソい手を使っていますw
参考サイトは同日に複数コメント対応ですが、(回答コードは)TextBox
がひとつだけなので1件のみです。
xml
1<Window
2 x:Class="Qa6deqmgkhn71do.MainWindow"
3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5 xmlns:gl="clr-namespace:System.Globalization;assembly=mscorlib"
6 SizeToContent="WidthAndHeight">
7 <Window.Resources>
8 <Style x:Key="CalendarDayButtonStyle1" TargetType="{x:Type CalendarDayButton}">
9
10 <!-- デフォルトからの変更点 追加 -->
11 <EventSetter Event="PreviewMouseUp" Handler="CalendarDayButton_PreviewMouseUp" />
12
13 <Setter Property="MinWidth" Value="5" />
14 <Setter Property="MinHeight" Value="5" />
15
16 <!-- デフォルトからの変更点 削除 -->
17 <!--<Setter Property="FontSize" Value="10" />-->
18
19 <Setter Property="HorizontalContentAlignment" Value="Center" />
20 <Setter Property="VerticalContentAlignment" Value="Center" />
21 <Setter Property="Template">
22 <Setter.Value>
23 <ControlTemplate TargetType="{x:Type CalendarDayButton}">
24
25 <!-- デフォルトからの変更点 Width・Height追加 -->
26 <!--<Grid>-->
27 <Grid Width="80" Height="80">
28 <Rectangle x:Name="TodayBackground" Fill="#FFAAAAAA" Opacity="0" RadiusX="1" RadiusY="1" />
29 <Rectangle x:Name="SelectedBackground" Fill="#FFBADDE9" Opacity="0" RadiusX="1" RadiusY="1" />
30 <Border
31 Background="{TemplateBinding Background}"
32 BorderBrush="{TemplateBinding BorderBrush}"
33 BorderThickness="{TemplateBinding BorderThickness}" />
34 <Rectangle x:Name="HighlightBackground" Fill="#FFBADDE9" Opacity="0" RadiusX="1" RadiusY="1" />
35
36 <!-- デフォルトからの変更点 VerticalAlignment="Top" -->
37 <!--<ContentPresenter
38 x:Name="NormalText"
39 Margin="5,1,5,1"
40 HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
41 VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
42 TextElement.Foreground="#FF333333" />-->
43 <ContentPresenter
44 x:Name="NormalText"
45 Margin="5,1,5,1"
46 HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
47 VerticalAlignment="Top"
48 TextElement.Foreground="#FF333333" />
49
50 <!-- デフォルトからの変更点 追加 -->
51 <TextBox
52 x:Name="CalenderTimeTextBox"
53 Margin="3"
54 VerticalAlignment="Bottom"
55 BorderThickness="0"
56 DataContextChanged="CalenderTimeTextBox_DataContextChanged"
57 Loaded="CalenderTimeTextBox_Loaded"
58 TextChanged="CalenderTimeTextBox_TextChanged" />
59
60 <!-- 以下変更なし -->
61
62 <Path
63 x:Name="Blackout"
64 Margin="3"
65 HorizontalAlignment="Stretch"
66 VerticalAlignment="Stretch"
67 Data="M8.1772461,11.029181 L10.433105,11.029181 L11.700684,12.801641 L12.973633,11.029181 L15.191895,11.029181 L12.844727,13.999395 L15.21875,17.060919 L12.962891,17.060919 L11.673828,15.256231 L10.352539,17.060919 L8.1396484,17.060919 L10.519043,14.042364 z"
68 Fill="#FF000000"
69 Opacity="0"
70 RenderTransformOrigin="0.5,0.5"
71 Stretch="Fill" />
72 <Rectangle x:Name="DayButtonFocusVisual" IsHitTestVisible="false" RadiusX="1" RadiusY="1" Stroke="#FF45D6FA" Visibility="Collapsed" />
73 <VisualStateManager.VisualStateGroups>
74<!-- 省略 -->
75 </VisualStateManager.VisualStateGroups>
76 </Grid>
77 </ControlTemplate>
78 </Setter.Value>
79 </Setter>
80 </Style>
81 </Window.Resources>
82
83 <Grid>
84 <Grid.ColumnDefinitions>
85 <ColumnDefinition Width="2*" />
86 <ColumnDefinition />
87 </Grid.ColumnDefinitions>
88
89 <Calendar
90 x:Name="calendar"
91 Background="White"
92 CalendarDayButtonStyle="{StaticResource CalendarDayButtonStyle1}" />
93
94 <DataGrid
95 Grid.Column="1"
96 AutoGenerateColumns="False"
97 IsReadOnly="True"
98 ItemsSource="{Binding Comments}">
99 <DataGrid.Columns>
100 <DataGridTextColumn Binding="{Binding Value}" Header="コメント" />
101 <DataGridTextColumn Binding="{Binding Date, ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}, StringFormat={}{0:yyyy/MM/dd(ddd)}}" Header="日付" />
102 </DataGrid.Columns>
103 </DataGrid>
104 </Grid>
105</Window>
cs
1using System;
2using System.Collections.Generic;
3using System.Collections.ObjectModel;
4using System.Linq;
5using System.Threading.Tasks;
6using System.Windows;
7using System.Windows.Controls;
8using System.Windows.Controls.Primitives;
9using System.Windows.Input;
10using System.Windows.Media;
11using CommunityToolkit.Mvvm.ComponentModel;
12
13
14namespace Qa6deqmgkhn71do
15{
16 public class ViewModel
17 {
18 public ObservableCollection<Comment> Comments { get; }
19
20 public ViewModel()
21 {
22 Comments = new ObservableCollection<Comment>
23 {
24 new Comment("first", DateTime.Now),
25 new Comment("second", DateTime.Now.AddDays(1)),
26 new Comment("third", DateTime.Now.AddDays(7)),
27 new Comment("forth", DateTime.Now.AddMonths(1)),
28 new Comment("fifth", DateTime.Now.AddMonths(1).AddDays(1)),
29 new Comment("sixth", DateTime.Now.AddMonths(1).AddDays(7)),
30 };
31 }
32 }
33
34 public class Comment : ObservableObject
35 {
36 public string Value { get => _Value; set => SetProperty(ref _Value, value); }
37 private string _Value;
38
39 public DateTime Date { get; } // 日時のみ(常に0:00:00)
40
41 public Comment(string value, DateTime date) => (Value, Date) = (value, date.Date);
42 }
43
44 public partial class MainWindow : Window
45 {
46 private readonly ViewModel vm = new ViewModel();
47
48 public MainWindow()
49 {
50 InitializeComponent();
51 DataContext = vm;
52 }
53
54 // TextBoxが読み込まれたとき(初回1回だけ)CalendarDayButton分(7*6週分=42個)呼ばれる
55 private void CalenderTimeTextBox_Loaded(object sender, RoutedEventArgs e)
56 {
57 if (sender is TextBox textBox && textBox.DataContext is DateTime date)
58 {
59 // TextBox(CalendarDayButton)のDataContextはDateTime(例えば2023/05/21 0:00:00)
60 // CommentsのDateが一致したもの(同日にコメントは1件の想定)があれば
61 // Value(コメント文)をTextにセット
62 textBox.Text = vm.Comments?.FirstOrDefault(x => x.Date == date)?.Value;
63 }
64 }
65
66 // DataContextが変わったとき(=月が替わったとき)都度CalendarDayButton分呼ばれる
67 private void CalenderTimeTextBox_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
68 // やることは↑と同じなので雑に呼び出しw
69 => CalenderTimeTextBox_Loaded(sender, default);
70
71 // ユーザーが何か文字入力(文字削除)したとき
72 private void CalenderTimeTextBox_TextChanged(object sender, TextChangedEventArgs e)
73 {
74 if (sender is TextBox textBox && textBox.DataContext is DateTime date)
75 {
76 // 同日にコメントは1件の想定
77 var comment = vm.Comments.FirstOrDefault(x => x.Date.Date == date);
78
79 if (comment != null) // すでにコメントがあれば...
80 {
81 if (!string.IsNullOrEmpty(textBox.Text))
82 comment.Value = textBox.Text; // Valueを更新
83 else
84 vm.Comments.Remove(comment); // 空コメントはまるごと削除
85 }
86 else // コメントがまだなければ...
87 {
88 if (!string.IsNullOrEmpty(textBox.Text))
89 vm.Comments.Add(new Comment(textBox.Text, date)); // 追加
90 }
91 }
92 }
93
94 private async void CalendarDayButton_PreviewMouseUp(object sender, MouseButtonEventArgs e)
95 {
96 // キーボードフォーカスがうまく入らないのと
97 // カレンダーの[前の月|次の月]の日を選択すると月が替わるため
98 // クリック後ちょっと時間をおいてから選択日のTextBoxをフォーカス
99 await Task.Delay(10);
100 calendar.Descendants<CalendarDayButton>()
101 .FirstOrDefault(x => x.IsSelected)
102 ?.Descendants<TextBox>()
103 ?.FirstOrDefault()
104 ?.Focus();
105 }
106 }
107
108
109 // [VisualTreeの子孫要素を取得する - xin9le.net](https://blog.xin9le.net/entry/2013/10/29/222336)
110 public static class DependencyObjectExtensions
111 {
112 public static IEnumerable<DependencyObject> Children(this DependencyObject obj)
113 {
114 if (obj == null) throw new ArgumentNullException(nameof(obj));
115
116 var count = VisualTreeHelper.GetChildrenCount(obj);
117 if (count == 0) yield break;
118 for (var i = 0; i < count; i++)
119 {
120 var child = VisualTreeHelper.GetChild(obj, i);
121 if (child != null) yield return child;
122 }
123 }
124 public static IEnumerable<DependencyObject> Descendants(this DependencyObject obj)
125 {
126 if (obj == null) throw new ArgumentNullException(nameof(obj));
127
128 foreach (var child in obj.Children())
129 {
130 yield return child;
131 foreach (var grandChild in child.Descendants()) yield return grandChild;
132 }
133 }
134 public static IEnumerable<T> Descendants<T>(this DependencyObject obj) where T : DependencyObject => obj.Descendants().OfType<T>();
135 }
136}
NuGet Gallery | CommunityToolkit.Mvvm 8.2.0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/05/21 13:59
2023/05/22 16:33
2023/05/30 06:53