【WPF】自作カレンダー その1(とりあえず当月を表示)

公開日:2019-06-18
最終更新:2019-06-18
※この記事は外部サイト(https://www.doraxdora.com/blog/2017/10/15/...)からのクロス投稿です

WPFには、カレンダーコントロールが標準であるんですが、
スケジューラ-みたいなことはできないし、あくまで選択された日付を取得するためのものになっています。

常に表示して、カレンダーに対してアクションするようなコントローラーも
需要はあると思うので、標準で使えるようにしてくれればいいのにと思いながらちょっと自作してみます。

今回は新規で専用にプロジェクトを作成します。

プロジェクト作成

VisualStudio2017を起動し、
新規プロジェクトを作成、名前を「CalendarSample」とします。

作成方法などは下記の記事を参考にしていただければ。
Visual Studio 2017 Community のインストールから Hello World

また、スタイルに「MahApps.Metro」を利用するので、
分からなければこちらの記事を参考にしてください。
【WPF】MahApps.Metro で見た目をスタイリッシュにしてみる

プログラム実装

スタイルの設定

App.xaml

<Application x:Class="CalendarSample.App"  
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
             xmlns:local="clr-namespace:CalendarSample"  
             StartupUri="MainWindow.xaml">  
    <Application.Resources>  
        <ResourceDictionary>  
            <ResourceDictionary.MergedDictionaries>  
                <!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->  
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />  
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />  
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />  
                <!-- Accent and AppTheme setting -->  
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />  
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />  
            </ResourceDictionary.MergedDictionaries>  
        </ResourceDictionary>  
    </Application.Resources>  
</Application>  

MahApps.Metroのスタイル設定を記述します。

StyleDic.xaml

<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:WpfApp1.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" />  
    </Style>  
</ResourceDictionary>  

プロジェクト直下に「Style」ディレクトリを追加し、上記ファイルを作成します。

画面の作成

MainWindow.xaml

<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="350" Width="525">  
    <Window.Resources>  
        <ResourceDictionary Source="/Style/StyleDic.xaml"/>  
    </Window.Resources>  

    <Grid>  
        <GroupBox x:Name="CalendarGropu1" Header="" HorizontalAlignment="Left" Height="300" Margin="10,10,0,0" VerticalAlignment="Top" Width="497" Style="{StaticResource gp-normal}">  
            <Grid x:Name="CalendarGrid" HorizontalAlignment="Left" Height="258" Margin="10,10,0,0" VerticalAlignment="Top" Width="467">  
                <Grid.ColumnDefinitions>  
                    <ColumnDefinition Width="1*" />  
                    <ColumnDefinition Width="1*" />  
                    <ColumnDefinition Width="1*" />  
                    <ColumnDefinition Width="1*" />  
                    <ColumnDefinition Width="1*" />  
                    <ColumnDefinition Width="1*" />  
                    <ColumnDefinition Width="1*" />  
                </Grid.ColumnDefinitions>  
                <Grid.RowDefinitions>  
                    <RowDefinition Height="20" />  
                    <RowDefinition Height="1*" />  
                    <RowDefinition Height="1*" />  
                    <RowDefinition Height="1*" />  
                    <RowDefinition Height="1*" />  
                    <RowDefinition Height="1*" />  
                </Grid.RowDefinitions>  
                <Rectangle Stroke="Black" StrokeThickness="1" Grid.ColumnSpan="7" Grid.RowSpan="7"/>  
                <Rectangle Fill="#ff8000" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" Margin="1 1 0 0" Panel.ZIndex="0" />  
                <Rectangle Fill="#ff8000" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="1" VerticalAlignment="Stretch" Margin="1 1 0 0" Panel.ZIndex="0"/>  
                <Rectangle Fill="#ff8000" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="2" VerticalAlignment="Stretch" Margin="1 1 0 0" Panel.ZIndex="0"/>  
                <Rectangle Fill="#ff8000" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="3" VerticalAlignment="Stretch" Margin="1 1 0 0" Panel.ZIndex="0"/>  
                <Rectangle Fill="#ff8000" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="4" VerticalAlignment="Stretch" Margin="1 1 0 0" Panel.ZIndex="0"/>  
                <Rectangle Fill="#ff8000" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="5" VerticalAlignment="Stretch" Margin="1 1 0 0" Panel.ZIndex="0"/>  
                <Rectangle Fill="#ff8000" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="6" VerticalAlignment="Stretch" Margin="1 1 1 0" Panel.ZIndex="0"/>  
                <Rectangle Height="1" Stroke="Black" StrokeThickness="1" VerticalAlignment="Bottom" Grid.ColumnSpan="7"/>  
                <Label Content="日" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" FontSize="11" Padding="0"/>  
                <Label Content="月" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" FontSize="11" Padding="0"/>  
                <Label Content="火" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="2" VerticalAlignment="Center" FontSize="11" Padding="0"/>  
                <Label Content="水" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="3" VerticalAlignment="Center" FontSize="11" Padding="0"/>  
                <Label Content="木" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="4" VerticalAlignment="Center" FontSize="11" Padding="0"/>  
                <Label Content="金" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="5" VerticalAlignment="Center" FontSize="11" Padding="0"/>  
                <Label Content="土" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="6" VerticalAlignment="Center" FontSize="11" Padding="0"/>  

            </Grid>  
        </GroupBox>  

    </Grid>  
</Mah:MetroWindow>  

コードビハインドの実装

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  
using System.Windows;  
using System.Windows.Controls;  
using System.Windows.Data;  
using System.Windows.Documents;  
using System.Windows.Input;  
using System.Windows.Media;  
using System.Windows.Media.Imaging;  
using System.Windows.Navigation;  
using System.Windows.Shapes;  

using MahApps.Metro.Controls;  

namespace CalendarSample  
{  
    /// <summary>  
    /// MainWindow.xaml の相互作用ロジック  
    /// </summary>  
    public partial class MainWindow : MetroWindow  
    {  
        private Rectangle selectedRec;  

        public MainWindow()  
        {  
            InitializeComponent();  

            CalendarGropu1.Header = String.Format("{0:yyyy年MM月}", DateTime.Now);   

            // 当月の月初を取得  
            var firstDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);  

            // 曜日番号の取得  
            int dayOfWeek = (int)firstDate.DayOfWeek;   

            // 月末を取得  
            int lastDay = firstDate.AddMonths(1).AddDays(-1).Day;  

            // 1日から月末までを走査  
            for (int day = 1; day <= lastDay; day++)  
            {  
                // セル位置  
                int index = (day - 1) + dayOfWeek;   
                // 横位置  
                int x = index % 7;  
                // 縦位置  
                int y = index / 7;  

                // 土日は文字色を変更する  
                Color color = Colors.Black;  
                if (x == 0)  
                {  
                    color = Colors.Red;  
                }  
                else if (x == 6)  
                {  
                    color = Colors.Blue;  
                }  

                // テキストブロックを生成してグリッドに追加  
                var tb = new TextBlock()  
                {  
                    Text = string.Format("{0}", day),  
                    FontSize = 12,  
                    Foreground = new SolidColorBrush(color),  
                    Padding = new Thickness(0, 10, 10, 0),  
                    HorizontalAlignment = HorizontalAlignment.Right,  
                    VerticalAlignment = VerticalAlignment.Top  
                };  
                this.CalendarGrid.Children.Add(tb);  
                tb.SetValue(Grid.ColumnProperty, x);  
                tb.SetValue(Grid.RowProperty, y + 1);  

                // 四角形を生成してグリッドに追加  
                // セルの枠線などを表示し、イベントをハンドリングする用  
                var rec = new Rectangle();  
                rec.HorizontalAlignment = HorizontalAlignment.Stretch;  
                rec.VerticalAlignment = VerticalAlignment.Stretch;  
                // 背景色を設定しないとイベントを検知できないらしいので透過色を設定  
                rec.Fill = Brushes.Transparent;  
                // 枠線を調整  
                rec.Margin = (x == 6) ? new Thickness(0.0, -1.0, 0.0, 0.0) : new Thickness(0.0, -1.0, -1.0, 0.0);  
                // イベント設定  
                rec.MouseLeftButtonDown += date_MouseLeftButtonDown;  
                this.CalendarGrid.Children.Add(rec);  
                rec.SetValue(Grid.ColumnProperty, x);  
                rec.SetValue(Grid.RowProperty, y + 1);  

            }  
        }  

        /// <summary>  
        /// セル(日)をクリックした際のイベントハンドラ.  
        /// </summary>  
        /// <param name="sender"></param>  
        /// <param name="e"></param>  
        void date_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)  
        {  
            // 既に選択されたセルがある場合は初期化  
            if (selectedRec != null)  
            {  
                selectedRec.StrokeDashArray = null;  
                selectedRec.StrokeThickness = 0;  
            }  

            // 枠線に点線をセット  
            Rectangle rec = sender as Rectangle;  
            rec.Stroke = Brushes.Black;  
            DoubleCollection dbc = new DoubleCollection();  
            dbc.Add(1);  
            dbc.Add(1);  
            rec.StrokeDashArray = dbc;  
            rec.StrokeThickness = 1;  

            // 選択セルの保持  
            selectedRec = rec;  
        }  
    }  
}  

ポイントは、
「Grid」を使い枠組みを作成してセルに日付用の「Rectangle」、「TextBlock」を配置することです。

起動してみる

日付セルをクリックすると、枠に点線が表示されるようにしました。

まとめ

今回はここまでとなります。

次回以降、このカレンダーを使って色々試してみたいと思います。

ではでは。

記事が少しでもいいなと思ったらクラップを送ってみよう!
0
+1
@doraxdoraの技術ブログ 主に Java, C#, Python, Javascript の記事を載せていく予定。

よく一緒に読まれている記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる

技術ブログをはじめよう

Qrunch(クランチ)は、ITエンジニアリングに携わる全ての人のための技術ブログプラットフォームです。

技術ブログを開設する

Qrunchでアウトプットをはじめよう

Qrunch(クランチ)は、ITエンジニアリングに携わる全ての人のための技術ブログプラットフォームです。

Markdownで書ける

ログ機能でアウトプットを加速

デザインのカスタマイズが可能

技術ブログ開設

ここから先はアカウント(ブログ)開設が必要です

英数字4文字以上
.qrunch.io
英数字6文字以上
ログインする