【WPF】自作カレンダー その2(動的生成)
おはようございます。
自作カレンダーその2です。
今回は、Xamlではなくコードからカレンダーを生成します。
最終的に年間カレンダー的なものにしようと思うので、
Xamlで定義すると Grid だらけになってしまうし、色々やろうと思ったらやっぱり動的に生成した方がやりやすいような気がするので。
前回のプログラムはこちら。
スポンサーリンク
スタイル定義の変更
まずはスタイルの外出しをします。
StyleDic.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:local="clr-namespace:CalendarSample.Style"> <!-- グループ:通常--> <Style x:Key="gp-normal"TargetType="GroupBox" > <Setter Property="VerticalAlignment"Value="Top"/> <Setter Property="HorizontalAlignment"Value="Left"/> <Setter Property="Background"Value="#FFFFFFFF"/> <Setter Property="Foreground"Value="#FF777777"/> <Setter Property="Height"Value="300"/> <Setter Property="Width"Value="500"/> <Setter Property="Margin"Value="10,10,0,0"/> </Style> <!-- グリッド:カレンダー用 --> <Style x:Key="grid-calendar"TargetType="Grid" > <Setter Property="VerticalAlignment"Value="Center"/> <Setter Property="HorizontalAlignment"Value="Center"/> <Setter Property="Background"Value="#FFFFFFFF"/> <Setter Property="Height"Value="258"/> <Setter Property="Width"Value="450"/> <Setter Property="Margin"Value="0,0,0,0"/> </Style> <!-- テキストブロック:日付セル(通常) --> <Style x:Key="txb-date"TargetType="TextBlock"> <Setter Property="FontSize"Value="12"/> <Setter Property="Foreground"Value="Black"/> <Setter Property="Padding"Value="0,10,10,0"/> <Setter Property="VerticalAlignment"Value="Top"/> <Setter Property="HorizontalAlignment"Value="Right"/> </Style> <!-- テキストブロック:日付セル(土曜) --> <Style x:Key="txb-date-sat" TargetType="TextBlock" BasedOn="{StaticResourcetxb-date}"> <Setter Property="Foreground"Value="Blue"/> </Style> <!-- テキストブロック:日付セル(日曜) --> <Style x:Key="txb-date-sun" TargetType="TextBlock" BasedOn="{StaticResourcetxb-date}"> <Setter Property="Foreground"Value="Red"/> </Style> <!-- 四角形:外枠用 --> <Style x:Key="rec-border"TargetType="Rectangle"> <Setter Property="Stroke"Value="Black"/> <Setter Property="StrokeThickness"Value="1"/> <Setter Property="Grid.ColumnSpan"Value="7"/> <Setter Property="Grid.RowSpan"Value="7"/> </Style> <!-- 四角形:下線用 --> <Style x:Key="rec-underlining"TargetType="Rectangle"> <Setter Property="Stroke"Value="Black"/> <Setter Property="StrokeThickness"Value="1"/> <Setter Property="Height"Value="1"/> <Setter Property="VerticalAlignment"Value="Bottom"/> <Setter Property="Grid.ColumnSpan"Value="7"/> </Style> <!-- 四角形:曜日 --> <Style x:Key="rec-week"TargetType="Rectangle"> <Setter Property="Fill"Value="#FF8000"/> <Setter Property="VerticalAlignment"Value="Stretch"/> <Setter Property="HorizontalAlignment"Value="Stretch"/> <Setter Property="Grid.Row"Value="0"/> <Setter Property="Margin"Value="1,1,0,0"/> <Setter Property="Panel.ZIndex"Value="0"/> </Style> <!-- 四角形:曜日 --> <Style x:Key="rec-week-sat" TargetType="Rectangle" BasedOn="{StaticResourcerec-week}"> <Setter Property="Margin"Value="1,1,1,0"/> </Style> <!-- 四角形:日付セル(通常) --> <Style x:Key="rec-date"TargetType="Rectangle"> <Setter Property="VerticalAlignment"Value="Stretch"/> <Setter Property="HorizontalAlignment"Value="Stretch"/> <Setter Property="Fill"Value="Transparent"/> <Setter Property="Margin"Value="0,-1,-1,0"/> <!-- トリガーを使ってマウスオーバーで背景色を変更する--> <Style.Triggers> <Trigger Property="IsMouseOver"Value="true"> <Trigger.Setters> <Setter Property="Margin"Value="0,0,0,0"/> <Setter Property="Fill"Value="#60d0ff"/> <Setter Property="Opacity"Value="0.1"/> </Trigger.Setters> </Trigger> </Style.Triggers> </Style> <!-- 四角形:日付セル(土曜) → 最後の列を微調整--> <Style x:Key="rec-date-sat" TargetType="Rectangle" BasedOn="{StaticResourcerec-date}"> <Setter Property="Margin"Value="0,-1,0,0"/> </Style> <!-- 四角形:日付セル(選択) --> <Style x:Key="rec-date-selected"TargetType="Rectangle"> <Setter Property="VerticalAlignment"Value="Stretch"/> <Setter Property="HorizontalAlignment"Value="Stretch"/> <Setter Property="Stroke"Value="Black"/> <Setter Property="StrokeDashArray"Value="11"/> <Setter Property="StrokeThickness"Value="1"/> <Setter Property="Fill"Value="#007acc"/> <Setter Property="Opacity"Value="0.2"/> </Style> <!-- ラベル:曜日ヘッダ--> <Style x:Key="lb-week"TargetType="Label"> <Setter Property="VerticalAlignment"Value="Center"/> <Setter Property="HorizontalAlignment"Value="Center"/> <Setter Property="Grid.Row"Value="0"/> <Setter Property="FontSize"Value="11"/> <Setter Property="Padding"Value="0"/> </Style> </ResourceDictionary> |
ポイントは、日付セルの上をマウスオーバーした際と、クリックして選択した際に背景色を変更するところですかね。
画面の変更
画面に年月を選択するコンボボックスと、選択された日付を表示するラベルを追加しました。
後は カレンダー用の Grid がなくなってすっきりしました。
MainWIndow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <Mah:MetroWindow x:Class="CalendarSample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:CalendarSample" xmlns:Mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" GlowBrush="{DynamicResource AccentColorBrush}" mc:Ignorable="d" WindowStartupLocation="CenterScreen" Title="カレンダーサンプル"Height="400"Width="525"> <Window.Resources> <ResourceDictionary Source="/Style/StyleDic.xaml"/> </Window.Resources> <Grid x:Name="MainContainer"> <Label x:Name="lbYearMonth"Content="年月:"HorizontalAlignment="Left"Margin="10,20,0,0"VerticalAlignment="Top" /> <ComboBox x:Name="cbYearMonth"HorizontalAlignment="Left"Margin="61,20,0,0"VerticalAlignment="Top"Width="120"SelectionChanged="cbYearMonth_SelectionChanged"/> <Grid x:Name="CalendarContainer"HorizontalAlignment="Left"Height="317"Margin="0,53,0,0"VerticalAlignment="Top"Width="517"/> <Label x:Name="lbDate"Content="選択された日付:"HorizontalAlignment="Left"Margin="222,20,0,0"VerticalAlignment="Top"/> <Label x:Name="lbSelectedDate"Content=""HorizontalAlignment="Left"Margin="333,20,0,0"VerticalAlignment="Top"/> </Grid> </Mah:MetroWindow> |
プログラム修正
新規クラス追加
新規で、年月コンボボックス用と、日付セル用のクラスを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text; usingSystem.Threading.Tasks; namespaceCalendarSample { /// <summary> /// 年月情報 /// </summary> publicclassMonthInfo { /// <summary> /// コンストラクタ /// </summary> /// <param name="yearMonth"></param> publicMonthInfo(StringyearMonth) { this.YearMonth=yearMonth; this.YearMonthWithKanji=getYear()+"年"+getMonth()+"月"; } /// <summary> /// 年月 /// </summary> publicStringYearMonth{set;get;} /// <summary> /// 年月(YYYY年MM月) /// </summary> publicStringYearMonthWithKanji{set;get;} /// <summary> /// 年を返します. /// </summary> /// <returns></returns> publicStringgetYear() { if(String.IsNullOrEmpty(YearMonth))return""; returnYearMonth.Substring(0,4); } /// <summary> /// 月を返します. /// </summary> /// <returns></returns> publicStringgetMonth() { if(String.IsNullOrEmpty(YearMonth))return""; returnYearMonth.Substring(4,2); } } } |
DateInfo.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text; usingSystem.Threading.Tasks; namespaceCalendarSample { /// <summary> /// 日付情報 /// </summary> publicclassDateInfo:MonthInfo { /// <summary> /// コンストラクタ /// </summary> /// <param name="yearMonth"></param> /// <param name="day"></param> publicDateInfo(StringyearMonth,Stringday):base(yearMonth) { this.YearMonthDay=yearMonth+day; this.Date=newDateTime(int.Parse(getYear()),int.Parse(getMonth()),int.Parse(day)); } publicDateTimeDate{set;get;} /// <summary> /// 年月日 /// </summary> publicStringYearMonthDay{set;get;} /// <summary> /// 年月日(YYYY年MM月DD日) /// </summary> publicStringgetYearMonthDayWithKanji() { returnString.Format("{0:yyyy年MM月dd日(ddd)}",Date); } /// <summary> /// 日を返します. /// </summary> /// <returns></returns> publicStringgetDay() { if(String.IsNullOrEmpty(YearMonthDay))return""; returnYearMonthDay.Substring(6,2); } } } |
コードビハインドの修正
年月コンボボックスの項目設定と、カレンダーの生成メソッドを追加したりしました。
MainWindow.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 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 | usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text; usingSystem.Threading.Tasks; usingSystem.Windows; usingSystem.Windows.Controls; usingSystem.Windows.Data; usingSystem.Windows.Documents; usingSystem.Windows.Input; usingSystem.Windows.Media; usingSystem.Windows.Media.Imaging; usingSystem.Windows.Navigation; usingSystem.Windows.Shapes; usingMahApps.Metro.Controls; namespaceCalendarSample { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> publicpartial classMainWindow:MetroWindow { privateRectangle selectedRec; privateStyle selectedRecStyle; publicMainWindow() { InitializeComponent(); // 前月から6カ月分のリストを作成し、当月を選択させる List<MonthInfo>list=newList<MonthInfo>(); DateTime now=DateTime.Now; DateTime dt=now.AddMonths(-1); for(inti=0;i<6;i++) { list.Add(newMonthInfo(String.Format("{0:yyyyMM}",dt))); dt=dt.AddMonths(1); } this.cbYearMonth.ItemsSource=list; this.cbYearMonth.DisplayMemberPath="YearMonthWithKanji"; this.cbYearMonth.SelectedIndex=1; createCalendar(this.cbYearMonth.SelectedItem asMonthInfo); } /// <summary> /// 年月コンボの選択変更イベントハンドラー. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> privatevoidcbYearMonth_SelectionChanged(objectsender,SelectionChangedEventArgse) { createCalendar(cbYearMonth.SelectedItem asMonthInfo); } /// <summary> /// 指定された年月のカレンダーを作成 /// </summary> /// <param name="monthInfo"></param> privatevoidcreateCalendar(MonthInfo monthInfo){ CalendarContainer.Children.Clear(); // グループボックス GroupBox calendarGroup1=newGroupBox(); calendarGroup1.Header=monthInfo.YearMonthWithKanji; calendarGroup1.Style=FindResource("gp-normal")asStyle; // グリッド Grid calendarGrid1=newGrid(); calendarGrid1.Style=FindResource("grid-calendar")asStyle; calendarGrid1.ColumnDefinitions.Add(newColumnDefinition(){Width=newGridLength(1,GridUnitType.Star)}); calendarGrid1.ColumnDefinitions.Add(newColumnDefinition(){Width=newGridLength(1,GridUnitType.Star)}); calendarGrid1.ColumnDefinitions.Add(newColumnDefinition(){Width=newGridLength(1,GridUnitType.Star)}); calendarGrid1.ColumnDefinitions.Add(newColumnDefinition(){Width=newGridLength(1,GridUnitType.Star)}); calendarGrid1.ColumnDefinitions.Add(newColumnDefinition(){Width=newGridLength(1,GridUnitType.Star)}); calendarGrid1.ColumnDefinitions.Add(newColumnDefinition(){Width=newGridLength(1,GridUnitType.Star)}); calendarGrid1.ColumnDefinitions.Add(newColumnDefinition(){Width=newGridLength(1,GridUnitType.Star)}); calendarGrid1.RowDefinitions.Add(newRowDefinition(){Height=newGridLength(20)}); calendarGrid1.RowDefinitions.Add(newRowDefinition(){Height=newGridLength(1,GridUnitType.Star)}); calendarGrid1.RowDefinitions.Add(newRowDefinition(){Height=newGridLength(1,GridUnitType.Star)}); calendarGrid1.RowDefinitions.Add(newRowDefinition(){Height=newGridLength(1,GridUnitType.Star)}); calendarGrid1.RowDefinitions.Add(newRowDefinition(){Height=newGridLength(1,GridUnitType.Star)}); calendarGrid1.RowDefinitions.Add(newRowDefinition(){Height=newGridLength(1,GridUnitType.Star)}); // グリッド枠線 Rectangle border=newRectangle(); border.Style=FindResource("rec-border")asStyle; calendarGrid1.Children.Add(border); for(intcol=0;col<7;col++) { Rectangle week=newRectangle(); week.Style=(col==6)?FindResource("rec-week-sat")asStyle:FindResource("rec-week")asStyle; week.SetValue(Grid.ColumnProperty,col); calendarGrid1.Children.Add(week); Label lbWeek=newLabel(); lbWeek.Style=FindResource("lb-week")asStyle; lbWeek.Content=("日月火水木金土").Substring(col,1); lbWeek.SetValue(Grid.ColumnProperty,col); calendarGrid1.Children.Add(lbWeek); } // ヘッダ行下線 Rectangle underlining=newRectangle(); underlining.Style=FindResource("rec-underlining")asStyle; calendarGrid1.Children.Add(underlining); // グループボックスにグリッドを追加 calendarGroup1.Content=calendarGrid1; CalendarContainer.Children.Add(calendarGroup1); // 当月の月初を取得 varfirstDate=newDateTime(int.Parse(monthInfo.getYear()),int.Parse(monthInfo.getMonth()),1); // 曜日番号の取得 intdayOfWeek=(int)firstDate.DayOfWeek; // 月末を取得 intlastDay=firstDate.AddMonths(1).AddDays(-1).Day; // 1日から月末までを走査 for(intday=1;day<=lastDay;day++) { // セル位置 intindex=(day-1)+dayOfWeek; // 横位置 intx=index%7; // 縦位置 inty=index/7; // テキストブロックを生成してグリッドに追加 vartb=newTextBlock(); tb.Text=string.Format("{0}",day); // 土日は文字色を変更する if(x==0) { tb.Style=FindResource("txb-date-sun")asStyle; } elseif(x==6) { tb.Style=FindResource("txb-date-sat")asStyle; } else { tb.Style=FindResource("txb-date")asStyle; } calendarGrid1.Children.Add(tb); tb.SetValue(Grid.ColumnProperty,x); tb.SetValue(Grid.RowProperty,y+1); // 四角形を生成してグリッドに追加 // セルの枠線などを表示し、イベントをハンドリングする用 varrec=newRectangle(); DateInfo dt=newDateInfo(monthInfo.YearMonth,string.Format("{0:00}",day)); rec.DataContext=dt; // 枠線を調整 rec.Style=(x==6)?FindResource("rec-date-sat")asStyle:FindResource("rec-date")asStyle; // イベント設定 rec.MouseLeftButtonDown+=date_MouseLeftButtonDown; calendarGrid1.Children.Add(rec); rec.SetValue(Grid.ColumnProperty,x); rec.SetValue(Grid.RowProperty,y+1); } } /// <summary> /// セル(日)をクリックした際のイベントハンドラ. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> privatevoiddate_MouseLeftButtonDown(objectsender,MouseButtonEventArgse) { // 既に選択されたセルがある場合はスタイルを戻す if(selectedRec!=null) { selectedRec.Style=selectedRecStyle; } // 選択されたセルの取得 Rectangle rec=sender asRectangle; // 選択セルの保持 selectedRec=rec; selectedRecStyle=rec.Style; // 選択時のスタイルに変更 rec.Style=FindResource("rec-date-selected")asStyle; // ラベルに日付をセット lbSelectedDate.Content=(rec.DataContext asDateInfo).getYearMonthDayWithKanji(); } } } |
起動してみる
起動後は当月を表示するようにしました。
日付を選択すると、選択箇所の背景色が変わり、選択された日付が右上に表示されます。
なんとなく使えそうな気がしてきました。
バインディングなんかがうまく利用できていませんが、それは追々ということで。
次回は、年間カレンダーにしようかと思います。
ではでは。
ディスカッション
コメント一覧
まだ、コメントがありません