Syncfusion SfCalendarを使う(Xamarin Forms)
1. はじめに
Xamarin Formsで、Syncfusion SfCalendarを使って以下のようなサンプル実装を行いました。
- 月カレンダー形式で予定を表示する
- 日をクリックすると、対象日のスケジュール詳細(件名)が表示される
- スワイプもしくはボタンクリックで前後の月に移動できる
- Prismを使ってMVVMアーキテクチャとする
2. 実装手順
2.1. VS 2017でプロジェクト作成
Visual Studio 2017でPrism Blank App(Xamarin.Forms)プロジェクトを作成。
プロジェクト名は「UseSfCalendarWithPrism」としました。
2.2. Nugetパッケージ管理でSyncfusion SfCalendarを追加
XamarinNugetパッケージ管理で「Syncfusion.Xamarin.SfCalendar」をインストール。
2.3. 実装
で、実装は以下に置きました。。。。
以下にサンプル実装のポイントを・・・
ポイント1 カレンダーの月変更イベントをViewModelにバインド
カレンダーの月変更イベントは SfCalendar.MonthChanged です。
MVVMとしているのでイベントをViewMode(MainPageViewModel)で受け取りたいです。
その為、Prismの「EventToCommandBehavior」を利用して、イベントをView→ViewModelにコマンドとして伝播させています。
[MainPage.xaml] <ContentPage ...省略 xmlns:b="clr-namespace:Prism.Behaviors;assembly=Prism.Forms" /> <SfCal:SfCalendar x:Name="calendar" ShowInlineEvents="True" MinDate="{Binding MinDate}" MaxDate="{Binding MaxDate}" BlackoutDates="{Binding BlackoutDates}" DataSource="{Binding CalendarEventCollection}" SelectionMode="{Binding SelectionMode, Mode=OneWay,Converter={StaticResource SelectionModeConverter}}"> <SfCal:SfCalendar.Behaviors> <b:EventToCommandBehavior EventName="MonthChanged" Command="{Binding MonthChangedCommand}" EventArgsParameterPath="args.CurrentValue" /> </SfCal:SfCalendar.Behaviors> </SfCal:SfCalendar>
[MainPageViewModel.cs] public class MainPageViewModel : ViewModelBase { ...省略 public ICommand MonthChangedCommand => new Command<DateTime>((currentDate) => { this.UpdateEvents(currentDate); }); }
ポイント2 カレンダーにバインドするイベントコレクション作成
SfCalendarに表示するイベントは「SfCalendar.DataSourceプロパティ」に設定しますが、PrismでViewModelにバインドしているので「MainPageViewModel.CalendarEventCollectionプロパティ」にデータバインドしています。
カレンダーの月変更イベントに対して当該月+前後一週間のイベントをバインドデータに設定しています。
[MainPageViewModel.cs] public class MainPageViewModel : ViewModelBase { /// <summary> /// イベントを更新します。 /// </summary> /// <remarks> /// 今月のイベントを表示するために、対象月+前後一週間のイベントをコレクションに設定します。 /// 1ヶ月のカレンダーの前後に 前月・次月 の日付が表示されるため、前後1週間のイベントを設定します。 /// </remarks> /// <param name="calendarDate"></param> private void UpdateEvents(DateTime calendarDate) { // バインド対象のthis.CalendarEventCollectionを直接、繰り返しAdd()するとパフォーマンスが著しく落ちるのでテンポラリにデータコレクションを用意して差し替える CalendarEventCollection newCalendarEventCollection = new CalendarEventCollection(); DateTime dt = new DateTime(calendarDate.Year, calendarDate.Month, 1); int thisMonthLastDay = dt.AddMonths(1).AddDays(-1).Day; for (int i = -7; i < thisMonthLastDay+7; i++) { // イベントはサンプルなので適当に2日に1回散歩と仕事、毎日のランチを設定 DateTime eventDt = dt.AddDays(i); if (eventDt.Day % 2 == 1) { //this.calendarEventCollection.Add( newCalendarEventCollection.Add( new CalendarInlineEvent() { Subject = $"{eventDt.Day}日 散歩", StartTime = eventDt.AddHours(10), EndTime = eventDt.AddHours(11), Color = Color.Green }); } //this.calendarEventCollection.Add( newCalendarEventCollection.Add( new CalendarInlineEvent() { Subject = $"{eventDt.Day}日 ランチ", StartTime = eventDt.AddHours(12), EndTime = eventDt.AddHours(13), Color = Color.Orange }); if(eventDt.Day % 2 == 0) { //this.calendarEventCollection.Add( newCalendarEventCollection.Add( new CalendarInlineEvent() { Subject = $"{eventDt.Day}日 仕事", StartTime = eventDt.AddHours(10), EndTime = eventDt.AddHours(19), Color = Color.Blue }); } } this.CalendarEventCollection.Clear(); this.CalendarEventCollection = newCalendarEventCollection; } }
つまずいた点
2018/3/28現在版 Syncfusion SfCalendar(android)に不具合がありました。
イベントを設定しているのに画面上で、対象日をクリックすると「No Appointments」と表示されてしまう不具合でした。
twitterでつぶやいたところSyncfusionの方よりリプライを頂き、即座にパッチアッセンブリを頂き不具合の修正を確認できました。
アップデートとしては2018年3月末の「2018 Vol 1 SP1」で対応されるとのことです。
SfCalendarへの要望
表示形式が「YearViewとMonthView」の2つなのですが、Weeklyとかandroidのカレンダーみたいな形式とか、色々なバリエーションがあればもっと嬉しいなぁ、と思いました。
※今日のブログ、雑ですね。。。まあ、動くソースをgithubに置いたので、「おかしいぞ!分からんぞ!」と思った方はコメント頂ければと思いますm( )m