前回:http://blogs.wankuma.com/kazuki/archive/2008/01/20/118336.aspx
前回、なんとなく表示されるまで作ったカレンダーだけど、デザイナ上で例外が出たとかいって表示されない。
これは、コンバータの手抜き実装が原因でif文を1ついれてあげるだけでとりあえずOK。
namespace WpfCalendar
{
public class DateTimeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// 今までnullを気にしてなかった
if (value == null)
{
return new List<DateTime>();
}
DateTime date = (DateTime)value;
var days = (from day in Enumerable.Range(1, DateTime.DaysInMonth(date.Year, date.Month))
select new DateTime(date.Year, date.Month, day)).ToList();
var first = days.First();
for (int i = 0; i < (int)first.DayOfWeek; i++)
{
days.Insert(0, days.First().AddDays(-1));
}
var last = days.Last();
for (int i = 0; i < 6 - (int)last.DayOfWeek; i++)
{
days.Add(days.Last().AddDays(1));
}
return days;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
引き続き実装してみようと思う。
今のカレンダーだと、何年何月のカレンダーを表示してるのかわかりにくいので、今表示してるカレンダーが何年何月なのか表示するようにする。
ListBoxのテンプレートにちょびっと追加。
<ControlTemplate TargetType="{x:Type ListBox}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="{Binding Year}" />
<TextBlock Text="年" />
<TextBlock Text="{Binding Month}" />
<TextBlock Text="月" />
</StackPanel>
<UniformGrid Grid.Row="1" Columns="7">
<TextBlock Text="日" />
<TextBlock Text="月" />
<TextBlock Text="火" />
<TextBlock Text="水" />
<TextBlock Text="木" />
<TextBlock Text="金" />
<TextBlock Text="土" />
</UniformGrid>
<UniformGrid Grid.Row="2" Columns="7" IsItemsHost="True">
</UniformGrid>
</Grid>
</ControlTemplate>
今までStackPanelに追加してたけど、Gridに変更してみた。
カレンダーのサイズも、ぴったりフィットするようになった!ここまでの実行結果は↓になる。
さて、最後に土曜日は青色・日曜日は赤色にしてみようと思う。
これは、DayOfWeekをForegroundにバインドしてコンバータを1つかませるだけ。
namespace WpfCalendar
{
public class DayOfWeekForegroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
// nullはとりあえず黒
return Brushes.Black;
}
DayOfWeek week = (DayOfWeek) value;
if (DayOfWeek.Sunday == week)
{
return Brushes.Red;
}
if (DayOfWeek.Saturday == week)
{
return Brushes.Blue;
}
return Brushes.Black;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type sys:DateTime}">
<TextBlock Text="{Binding Day}" >
<TextBlock.Foreground>
<Binding Path="DayOfWeek">
<Binding.Converter>
<c:DayOfWeekForegroundConverter />
</Binding.Converter>
</Binding>
</TextBlock.Foreground>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
これを適当にWindowに置いて、ボタンを押したら選択日を表示するようなコードを書いてみた。
<Window x:Class="WpfStyle.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Calendar">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Grid.Row="0" Name="calendar"
IsSynchronizedWithCurrentItem="True"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:c="clr-namespace:WpfCalendar">
<ListBox.ItemsSource>
<Binding>
<Binding.Converter>
<c:DateTimeConverter />
</Binding.Converter>
</Binding>
</ListBox.ItemsSource>
<ListBox.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="TextAlignment" Value="Right" />
</Style>
</ListBox.Resources>
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="{Binding Year}" />
<TextBlock Text="年" />
<TextBlock Text="{Binding Month}" />
<TextBlock Text="月" />
</StackPanel>
<UniformGrid Grid.Row="1" Columns="7">
<TextBlock Text="日" />
<TextBlock Text="月" />
<TextBlock Text="火" />
<TextBlock Text="水" />
<TextBlock Text="木" />
<TextBlock Text="金" />
<TextBlock Text="土" />
</UniformGrid>
<UniformGrid Grid.Row="2" Columns="7" IsItemsHost="True">
</UniformGrid>
</Grid>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Right" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type sys:DateTime}">
<TextBlock Text="{Binding Day}" >
<TextBlock.Foreground>
<Binding Path="DayOfWeek">
<Binding.Converter>
<c:DayOfWeekForegroundConverter />
</Binding.Converter>
</Binding>
</TextBlock.Foreground>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Grid.Row="1" Content="何日?" Click="Button_Click"/>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace WpfStyle
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
calendar.DataContext = DateTime.Today;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
DateTime date = (DateTime) calendar.SelectedItem;
MessageBox.Show(date.ToString("yyyy/MM/dd"));
}
}
}
実行するとこんな感じ。
適当な日付を選んで…
ボタンを押すとダイアログが出る。
ただし、ボタンとかにフォーカスがうつると何処を選択してるかわからない…
う~んイマイチ。