質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

XAML

XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

Q&A

解決済

1回答

1275閲覧

【WPF】カレンダーをカスタマイズし、日付欄にコメント欄を追加したい

qweqwe

総合スコア1

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

XAML

XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

2グッド

0クリップ

投稿2023/05/21 04:57

編集2023/05/21 05:04

実現したいこと

ここに実現したいことを箇条書きで書いてください。
WPFのカレンダーコントロールのコメント欄を追加したい

前提

.netFramework4.8/Visual Studio2019のWPFカレンダーをカスタマイズしたいです。
下記のサイトを参考にしています。
https://qiita.com/pregum/items/775b24fbf2eb80e43991

発生している問題

別月に移動すると同じセル位置に文字が表示される

該当のソースコード

xaml

1 <Calendar Name="calendar"> 2 <Calendar.CalendarDayButtonStyle> 3 <Style TargetType="CalendarDayButton" BasedOn="{StaticResource CalendarDayButtonStyle1}"> 4 <EventSetter Event="PreviewMouseLeftButtonDown" Handler="CalendarDayButton_PreviewMouseLeftButtonDown" /> 5 </Style> 6 </Calendar.CalendarDayButtonStyle> 7 </Calendar>

C#

1 2 private T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject 3 { 4 for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) 5 { 6 DependencyObject child = VisualTreeHelper.GetChild(parent, i); 7 8 if (child != null && child is T) 9 return (T)child; 10 else 11 { 12 T childOfChild = FindVisualChild<T>(child); 13 if (childOfChild != null) 14 return childOfChild; 15 } 16 } 17 return null; 18 } 19 20 private void CalendarDayButton_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 21 { 22 // イベントが発生したCalendarDayButtonを取得します。 23 CalendarDayButton dayButton = e.Source as CalendarDayButton; 24 if (dayButton != null) 25 { 26 // CalendarDayButtonの子コントロールからTextBoxを取得 27 TextBox textBox = FindVisualChild<TextBox>(dayButton); 28 if (textBox != null) 29 { 30 if (IsVisible) 31 { 32 textBox.Visibility = Visibility.Visible; 33 textBox.Text = "aaa"; 34 } 35 else 36 { 37 textBox.Visibility = Visibility.Hidden; 38 textBox.Text = string.Empty; 39 } 40 } 41 } 42 } 43

↓カレンダーコントロールを右クリック、「追加テンプレートの編集」→calendarDayStyleの編集→コピーして編集
追加した部分

ResourceDictionary

1<Grid> 2 <省略> 3 <Rectangle x:Name="TodayBackground" Fill="#FFAAAAAA" Opacity="0" RadiusY="1" RadiusX="1"/> 4 <Rectangle x:Name="SelectedBackground" Fill="#FFBADDE9" Opacity="0" RadiusY="1" RadiusX="1"/> 5 <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"/> 6 <Rectangle x:Name="HighlightBackground" Fill="#FFBADDE9" Opacity="0" RadiusY="1" RadiusX="1"/> 7 <ContentPresenter x:Name="NormalText" TextElement.Foreground="#FF333333" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="5,1,5,1" VerticalAlignment="Top"/> 8 <!-- ↓追加 --> 9 <TextBox x:Name="CalenderTimeTextBox" BorderThickness="0" Visibility="Visible" VerticalAlignment="Bottom" Margin="3"/> 10 <!-- ↑追加 --> 11 <Path x:Name="Blackout" 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" Fill="#FF000000" HorizontalAlignment="Stretch" Margin="3" Opacity="0" RenderTransformOrigin="0.5,0.5" Stretch="Fill" VerticalAlignment="Stretch"/> 12 <Rectangle x:Name="DayButtonFocusVisual" IsHitTestVisible="false" RadiusY="1" RadiusX="1" Stroke="#FF45D6FA" Visibility="Collapsed"/> 13</Grid> 14

イメージ説明

補足情報(FW/ツールのバージョンなど)

.netFramework4.8/Visual Studio2019

k_mail👍を押しています
TN8001🎉を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

下記のサイトを参考にしています。
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:02

編集2023/05/24 15:52
TN8001

総合スコア9326

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

qweqwe

2023/05/21 13:59

ありがとうございます。 確認後、改めてお返事させて頂きます。 WPFのカレンダーをこのようにカスタマイズ可能なんだな、という事で参考にさせて頂きました。 コードは関係なかったですね。。 失礼しました。
TN8001

2023/05/22 16:33

すいません。通知が来なくて気が付くのが遅れました。 > 確認後、改めてお返事させて頂きます。 はい。回答の不明点はお気軽にコメントください^^ > WPFのカレンダーをこのようにカスタマイズ可能なんだな、という事で参考にさせて頂きました。 なるほど。「これができるならTextBoxもいけそうだな」って思ったってことですね^^;
qweqwe

2023/05/30 06:53

返信が遅くなり申し訳ございません。 私の環境でも再現でき、解決できました!! ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問