今回はCalendarGridで日付毎の打ち合わせ担当者名を表示し、打ち合わせ担当者毎の予定日をMultiRow for Windows Forms(以下、MultiRow)で表示するという例を紹介します。
CalendarGrid、MultiRow、2つのコンポーネントがプログラム側から利用する場合にも同じような感覚で扱える点に注目してください。
参考
サンプルファイル
本記事にアップロードしているサンプルファイルは、GitHubでも公開しています。
今回紹介するコンポーネント
本記事では主にCalendarGridについて解説しますが、組み合わせの例としてMultiRowについても言及します。
以下にそれらの概要も併せて紹介します。
CalendarGrid
グレープシティ社の提供する、柔軟なカスタマイズに対応したカレンダーを提供するためのコンポーネントです。
MutiRow
複雑な構成や複数行のグリッドを簡単に作成できるコンポーネントです。CalendarGridと組み合わせることで、データを別の切り口から表示することができます。
対象読者
Visual Studioを利用してアプリケーションを作成した経験がある、またはC#、Visual Basicなどの.NET系言語での開発経験がある方。
必要な環境
CalendarGridを利用するには以下の環境が必要となります。
- Visual Studio 2010/2012/2013/2015 日本語版
- .NET Framework 3.5 SP1/3.5 Client Profile/4/4 Client Profile/4.5/4.5.1/4.5.2/4.6/4.6.1/4.6.2
本記事はVisual Studio 2015 Enterprise、.NET Framework 4.6環境で画像キャプチャーの取得、動作検証を行っております。
コントロールのインストール
今回紹介するコンポーネントを導入するには、製品を購入するかトライアル版を利用する方法があります。
トライアル版の入手は以下のURLのフォームから申し込みを行います。
製品の購入は以下のURLから手続きを行ってください。
手続きを進めることでCalendarGridまたはMultiRowのインストーラーがダウンロード可能になります。
制限事項などの詳細については、インストーラーに同梱されているリリースノートを参照ください。
導入の詳しい流れについては過去の記事「JPAddressを用いて、さらに優れた住所入力フォームを作成しよう」を参照ください。
コントロールの配置
インストーラーによるインストール作業が終われば、Visual StudioでCalendarGridコントロールが利用可能になります(MultiRowも同様の方法で利用できるため、説明は割愛します)。
新しいプロジェクトの作成
Windows フォームアプリケーションの新しいプロジェクトを作成します。
ツールボックスアイテムの選択
プロジェクトの作成後、上部メニューの「ツール」から「ツールボックスアイテムの選択」をクリックします。
GcCalendarGridのチェック
「.NET Framework コンポーネント」タブの「GcCalendarGrid」にチェックを入れ、右下の「OK」をクリックします。
これでツールボックスにGcCalendarGridが追加されます。
GcCalendarGridの画面配置
既存のコントロールと同様に、ツールボックスから「GcCalendarGrid」をドロップすることで画面に配置できます。
CalendarGridの特徴
MultiRowとの連携を紹介する前に、CalendarGridの特徴を紹介します。
レイアウトをカスタマイズして、複雑なカレンダーを作成できる
1日を表すフィールドを柔軟にカスタマイズできます。
Excelライクなデザイナー画面で行列の追加や結合、スタイルの変更などができるため、以下の画像のように1日のマスが横2列という構成も簡単にできます。
InputManCellを利用した豊富な書式と入力制御
CalendarGridの入力フォームには、同社のInputManの機能を備えたInputManCellが利用できます。InputManは強力な入力コンポーネントですが、今回のサンプルで想定する別の表示形式を自前で実装する場合に、InputManCellと同等の機能を用意するのは大変です。別途InputManを導入するという方法もありますが、MultiRowにもInputManCellが備わっているため、容易に入力フォームに同等の機能を用意できます。
画像、コンボボックスなどの多様に備えたセル
CalendarGridには下画像のようにコンボボックスや、チェックボックス、画像などさまざまな形式に対応したセルが用意されています。
MultiRowと連携した表示形式の切り分け(1)
切り分けの概要
カレンダー形式でデータを表示するアプリケーションで、データの編集内容によってはカレンダー形式より、グリッドで表示した方が良い場合もあります。例えば、1か月の予定を確認する場合はカレンダー形式で表示して、予定を担当者毎に分けて見たい場合は、グリッド形式で表示するなどです。
データ表示用のクラス
CalendarData
CalendarGridにデータを表示するためのクラスCalendarDataを用意します。
/// <summary>
/// カレンダーの一日のデータを表すクラス
/// カレンダー表示用にゲッターを用意
/// </summary>
public class CalendarData
{
/// <summary>
/// 日付
/// </summary>
public DateTime date { set; get; }
/// <summary>
/// その日の打ち合わせ担当者リスト
/// </summary>
public List<Person> personList { get; set; }
/// <summary>
/// 担当者の名前を返す
/// </summary>
public string name1 { get { if (personList.Count > 0) { return personList[0].name; } else return ""; } }
public string name2 { get { if (personList.Count > 1) { return personList[1].name; } else return ""; } }
public string name3 { get { if (personList.Count > 2) { return personList[2].name; } else return ""; } }
}
日付に対して複数の担当者が紐づきます。
最後のname1、name2、name3はCalendarGridのセルに紐づけるためのフィールドです。
MultiRowData
MultiRowにデータを表示するためのクラスMultiRowDataクラスは以下です。
/// <summary>
/// グリッド表示用のデータ
/// </summary>
public class MultiRowData
{
/// <summary>
/// 名前
/// Personクラスのnameプロパティを返す
/// </summary>
public string name { get { return person.name} }
public Person person { get; set; }
public List<DateTime> dateTimeList { get; set; }
/// <summary>
/// 日付を整形して返す
/// </summary>
public string date1 { get { if (dateTimeList.Count > 0) { return dateTimeList[0].ToString("yyyy/MM/dd"); } else return ""; } }
public string date2 { get { if (dateTimeList.Count > 1) { return dateTimeList[1].ToString("yyyy/MM/dd"); } else return ""; } }
public string date3 { get { if (dateTimeList.Count > 2) { return dateTimeList[2].ToString("yyyy/MM/dd"); } else return ""; } }
}
Person
担当者を表すPersonクラスです。フィールドをnameしか持たないクラスですが、実際はそれ以外にもフィールドを持っているという想定です。
/// <summary>
/// 担当者を表すクラス
/// </summary>
public class Person
{
/// <summary>
/// 名前
/// </summary>
public string name { get; set; }
}
カレンダーに表示する
CalendarData形式のデータを用意
まずはCalendarGridに表示するためのCalendarData形式のデータを用意します。
// データを用意
List<CalendarData> dataList = new List<CalendarData>();
CalendarData data = new CalendarData() { date = new DateTime(2017, 1, 5)};
data.personList = new List<Person>();
data.personList.Add(new Person() { name = "山田" });
data.personList.Add(new Person() { name = "佐藤" });
dataList.Add(data);
CalendarData data2 = new CalendarData() { date = new DateTime(2017, 1, 6)};
data2.personList = new List<Person>();
data2.personList.Add(new Person() { name = "田中" });
data2.personList.Add(new Person() { name = "西村" });
data2.personList.Add(new Person() { name = "佐藤" });
dataList.Add(data2);
CalendarData data3 = new CalendarData() { date = new DateTime(2017, 1, 7) };
data3.personList = new List<Person>();
data3.personList.Add(new Person() { name = "山田" });
data3.personList.Add(new Person() { name = "川上" });
data3.personList.Add(new Person() { name = "田中" });
dataList.Add(data3);
// データを用意ここまで
CalendarGridに紐づける
gcCalendarGrid1というName属性を持つCalendarGridコンポーネントが画面に配置されている場合に、上記のデータを表示するコードは以下です。
gcCalendarGrid1.DataSource = dataList; // dateプロパティをカレンダーの日付に紐づける gcCalendarGrid1.DateField = "date"; // テンプレートにリストの項目を紐づける var template = gcCalendarGrid1.Template; template.Content[1, 0].DataField = "name1"; template.Content[2, 0].DataField = "name2"; template.Content[3, 0].DataField = "name3"; gcCalendarGrid1.Template = template; gcCalendarGrid1.FirstDateInView = new DateTime(2017, 1, 1); // 編集の終了を通知 gcCalendarGrid1.EndEdit();
CalendarGridのDataSourceにデータのリストを代入します。
カレンダーに表示する日付のフィールドをCalendarGridのDataFiledに指定し、表示する担当者名をCalendarGridのTemplateのDataFieldに指定します。
最後にEndEditで編集の終了を通知することを忘れないでください。
MultiRowと連携した表示形式の切り分け(2)
グリッドに表示する
続いてMultiRow側で担当者毎のデータを表示します。
データを変換する
データをMultiRowDataの形式に合うように変換します。
// MultiRowDataの形式に変換
List<MultiRowData> multiRowDataList = new List<MultiRowData>();
foreach (var tmpData in dataList)
{
foreach (var tmpPerson in tmpData.personList)
{
if (multiRowDataList.Count(x => x.name == tmpPerson.name) > 0)
{
multiRowDataList.First(x => x.name == tmpPerson.name).dateTimeList.Add(tmpData.date);
}
else
{
List<DateTime> tmpDateTimeList = new List<DateTime>();
tmpDateTimeList.Add(tmpData.date);
multiRowDataList.Add(new MultiRowData() { person = tmpPerson, dateTimeList = tmpDateTimeList });
}
}
}
// MultiRowDataの形式に変換ここまで
MultiRowに表示する
gcMultiRow1.DataSource = multiRowDataList; var multiRowTemplate = gcMultiRow1.Template; multiRowTemplate.Row.Cells[0].DataField = "name"; multiRowTemplate.Row.Cells[1].DataField = "date1"; multiRowTemplate.Row.Cells[2].DataField = "date2"; multiRowTemplate.Row.Cells[3].DataField = "date3"; gcMultiRow1.Template = multiRowTemplate; gcMultiRow1.EndEdit();
特に説明が不要なくらい、CalendarGridと同様の流れです。
それぞれ表示するセルの指定方法だけが異なります。
今まで紹介したソースコードが見やすいように、ソースコードの全文を以下に載せます。詳しくはサンプルコードを参照してください。
ソースコード全文
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CalendarSample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// データを用意
List<CalendarData> dataList = new List<CalendarData>();
CalendarData data = new CalendarData() { date = new DateTime(2017, 1, 5)};
data.personList = new List<Person>();
data.personList.Add(new Person() { name = "山田" });
data.personList.Add(new Person() { name = "佐藤" });
dataList.Add(data);
CalendarData data2 = new CalendarData() { date = new DateTime(2017, 1, 6)};
data2.personList = new List<Person>();
data2.personList.Add(new Person() { name = "田中" });
data2.personList.Add(new Person() { name = "西村" });
data2.personList.Add(new Person() { name = "佐藤" });
dataList.Add(data2);
CalendarData data3 = new CalendarData() { date = new DateTime(2017, 1, 7) };
data3.personList = new List<Person>();
data3.personList.Add(new Person() { name = "山田" });
data3.personList.Add(new Person() { name = "川上" });
data3.personList.Add(new Person() { name = "田中" });
dataList.Add(data3);
// データを用意ここまで
gcCalendarGrid1.DataSource = dataList;
// dateプロパティをカレンダーの日付に紐づける
gcCalendarGrid1.DateField = "date";
// テンプレートにリストの項目を紐づける
var template = gcCalendarGrid1.Template;
template.Content[1, 0].DataField = "name1";
template.Content[2, 0].DataField = "name2";
template.Content[3, 0].DataField = "name3";
gcCalendarGrid1.Template = template;
gcCalendarGrid1.FirstDateInView = new DateTime(2017, 1, 1);
// 編集の終了を通知
gcCalendarGrid1.EndEdit();
// MultiRowDataの形式に変換
List<MultiRowData> multiRowDataList = new List<MultiRowData>();
foreach (var tmpData in dataList)
{
foreach (var tmpPerson in tmpData.personList)
{
if (multiRowDataList.Count(x => x.name == tmpPerson.name) > 0)
{
multiRowDataList.First(x => x.name == tmpPerson.name).dateTimeList.Add(tmpData.date);
}
else
{
List<DateTime> tmpDateTimeList = new List<DateTime>();
tmpDateTimeList.Add(tmpData.date);
multiRowDataList.Add(new MultiRowData() { person = tmpPerson, dateTimeList = tmpDateTimeList });
}
}
}
// MultiRowDataの形式に変換ここまで
gcMultiRow1.DataSource = multiRowDataList;
var multiRowTemplate = gcMultiRow1.Template;
multiRowTemplate.Row.Cells[0].DataField = "name";
multiRowTemplate.Row.Cells[1].DataField = "date1";
multiRowTemplate.Row.Cells[2].DataField = "date2";
multiRowTemplate.Row.Cells[3].DataField = "date3";
gcMultiRow1.Template = multiRowTemplate;
gcMultiRow1.EndEdit();
}
}
/// <summary>
/// カレンダーの一日のデータを表すクラス
/// カレンダー表示用にゲッターを用意
/// </summary>
public class CalendarData
{
/// <summary>
/// 日付
/// </summary>
public DateTime date { set; get; }
/// <summary>
/// その日の打ち合わせ担当者リスト
/// </summary>
public List<Person> personList { get; set; }
/// <summary>
/// 担当者の名前を返す
/// </summary>
public string name1 { get { if (personList.Count > 0) { return personList[0].name; } else return ""; } }
public string name2 { get { if (personList.Count > 1) { return personList[1].name; } else return ""; } }
public string name3 { get { if (personList.Count > 2) { return personList[2].name; } else return ""; } }
}
/// <summary>
/// グリッド表示用のデータ
/// </summary>
public class MultiRowData
{
/// <summary>
/// 名前
/// Personクラスのnameプロパティを返す
/// </summary>
public string name { get { return person.name; } }
public Person person { get; set; }
public List<DateTime> dateTimeList { get; set; }
/// <summary>
/// 日付を整形して返す
/// </summary>
public string date1 { get { if (dateTimeList.Count > 0) { return dateTimeList[0].ToString("yyyy/MM/dd"); } else return ""; } }
public string date2 { get { if (dateTimeList.Count > 1) { return dateTimeList[1].ToString("yyyy/MM/dd"); } else return ""; } }
public string date3 { get { if (dateTimeList.Count > 2) { return dateTimeList[2].ToString("yyyy/MM/dd"); } else return ""; } }
}
/// <summary>
/// 担当者を表すクラス
/// </summary>
public class Person
{
/// <summary>
/// 名前
/// </summary>
public string name { get; set; }
}
}
まとめ
CalendarGridとMultiRowを連携すれば、このように見たいデータに適した表示方法で表示、編集を行うことができます。データが複雑になればなるほど、操作したいデータに合わせた表示形式を切り替えられる利点は大きくなるでしょう。
また、CalendarGridとMultiRowがプログラム上ではほぼ同様の手順で利用できることもお伝えできたと思います。加えて、両コンポーネントで共通して利用できるInputManCellについても、ぜひ把握して提案や、検討に活かしたいポイントです。
CalendarGridやMultiRowのようなコンポーネントを利用するポイントは、自前で作成することと比較してテスト実績があり、テスト工数、バグ修正のコストが減らせることや、仕様に関して線引きの補助となること(コンポーネントでできる範囲を提示しやすい)に加えて、同じ設計思想のコンポーネントを連携させると使い方が似通っていたり、InputManCellのように機能が同等であるということもポイントの1つです。
コンポーネントを利用した方が低コスト、低リスクで開発ができる場合に、うまくコンポーネントを導入する手助けになれば幸いです。

