題材を探しを目的に他の記事を読む
今回は記事として公開されているコードを拝借して別の記事を書きます。
なんとなくグレーな行為ではありますが、それが弊社製品ものであれば問題にはならないでしょう。
Excelライクな表計算グリッドコンポーネントで、グレープシティの主力製品でもある「SPREAD(スプレッド)」。
1994年に初期バージョンが登場して以来、時代の流れとともに対応する環境こそ変わりましたが、多くの方にご愛顧いただいている製品です。その .NET Framework用の最新版は、「SPREAD for WPF 2.0J(以下、SPREADの表記はこのバージョンを意味します)」で、2017年7月にリリースしました。
そのSPREADの利用方法を解説する記事の公開が、題材探しをしていた自分の目に止まりました。これは使えるかも。
サンプルを作る場合に、表示用のデータを用意するのは面倒です。 オープンデータを探したり、Web APIから引っ張ってきたりと工夫しますが、手間がかかります。
公開済みのサンプルからちょっと拝借すればその手間を省けることは間違いありません。
今とりかかっているこの記事は「ComponentOne Studio」のXamarin用コンポーネント「ComponentOne Studio for Xamarin」がテーマです。
前述のSPREADの記事には「MVVM」の文字がありました。
そうなれば、サンプルからModel(モデル)とViewModel(ビューモデル)を転用して、View(ビュー)をXamarin.Formsで作れば、簡単にサンプルができあがることが期待できます。
すべての要素があつまり、拝借する土壌が整いました。
サンプル作成開始
SPREADのサンプルを見ると、グリッド形式にデータを表示し、コンボボックスで変更した値に応じて、データの書式を変更しています。
今回はデータの借用が目的なので、このグリッド部分が表示できれば十分です。 しかしここはXamarinの記事ですので、Android、iOS、UWPの3種類のアプリで、データグリッドを表示することをゴールにします。
まずVisual StudioでXamarin.Forms用のソリューションを作成して開始します。
このあたりは、Xamarinの環境が整っていればさほど難しくありませんし、解説文書も多く公開されていますので割愛します。
Xamarin クロス プラットフォーム開発 – Visual Studio
次に「ComponentOne Studio for Xamarin(以下、C1 Xamarin)」の設定です。
作成したソリューションに、NuGetサーバーからパッケージを追加します。コンポーネントを組み込む際に必要な手順です。
プロジェクトは以下の4つがありますが、図のようにソリューションを対象としてNuGetパッケージを追加し、すべてのプロジェクトに「C1.Xamarin.Forms.Grid」を追加してください。
Xamarin.Forms用のコンポーネントを追加すると、自動的にAndroid、iOSプロジェクトには、それぞれに適したコンポーネントが追加されます。
NuGetの追加が完了したあと、C1 Xamarinのライセンス設定です。ビルド以降の作業で必要になります。
C1 Xamarinを利用する場合のライセンス設定手順や詳細はWebサイトに説明があります。
トライアル版や製品版を使ってお手元で試す場合は、こちらをご参照ください。
ComponentOne Studio for Xamarinのライセンス
ひとつ注意事項です。
Xamarin.Formsでコンポーネントを使う場合、iOSとUWPのプロジェクトに初期化処理を記述する必要があります。iOSプロジェクトのAppDelegate.cs
とUWPプロジェクトのApp.xaml.cs
に以下の行を追加することを忘れないようにします。記述場所は、Xamarin.Formsの初期化処理を目印に探してください。Androidプロジェクトでは不要です。
// iOS 用 AppDelegate.cs global::Xamarin.Forms.Forms.Init(); C1.Xamarin.Forms.Grid.Platform.iOS.FlexGridRenderer.Init();
// UWP 用 App.xaml.cs
Xamarin.Forms.Forms.Init(e);
C1.Xamarin.Forms.Grid.Platform.UWP.FlexGridRenderer.Init();
コードを移植する
ここまでで準備が整いました。次に、SPREADのサンプルからコードを移植します。
移植するコードは、すべて共有ライブラリ(PCL)に記述します。ソリューションエクスプローラーで(移植可能)
と記載されているプロジェクトです。
ここに移植するためのファイルを追加します。
区別しやすいよう、以下のようなフォルダ構造にしました。
- PCLプロジェクト
そのままコピーする
結論から言うと、ModelとViewModelに関しては、名前空間(namespace
)以外のコードをコピーして、そのまま貼り付けるだけです。
Xamarin.Formsは .NET Frameworkと同様の機能を提供していますので、using
で参照する部分もそのまま参照設定されます。
以下が実際に貼り付けたModelのコードです。名前空間以外は、前述のSPREADの記事と同じです。データモデルの定義しているC#で書かれたクラスなので、互換性があるのは当然です。
また、このサンプルではデータをこのクラスで作成して提供しています。表示用データとしてそのまま使えそうです。
using System; using System.Collections.ObjectModel; namespace c1x_FlexGrid { public class CustomerRequest { public string ID { get; set; } public string Title { get; set; } public DateTime OpenDate { get; set; } public string Note { get; set; } } public class CustomerRequestCollection { private ObservableCollection<CustomerRequest> _requests; public CustomerRequestCollection() { _requests = new ObservableCollection<CustomerRequest> { new CustomerRequest(){Title="新機能の使用方法についてご質問",OpenDate=DateTime.Today.AddDays(0) }, // 記事では省略:データの生成部分 }; } public ObservableCollection<CustomerRequest> GetCustomerRequests() { return _requests; } } }
ViewModelのコードCustomerRequestViewModel.cs
も同様にコピーします。ただし、今回はデータを表示するだけなので、利用しないコンボボックスに関わる部分は削除します。
SPREADのサンプルではコンバータークラスの作成に、Xamarin.Formsでは機能が提供されていない
IMultiValueConverter
インタフェースを利用しています。そのため、その部分は別途作り直す必要があります。
今回使わない部分を削除したViewModelのコードは以下です。MVVMパターンの特徴であるINotifyPropertyChanged
インタフェースを実装したシンプルなクラスです。
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; namespace c1x_FlexGrid { public class CustomerRequestViewModel : INotifyPropertyChanged { // 問合せのコレクション private ObservableCollection<CustomerRequest> _requests; public CustomerRequestViewModel() { _requests = (new CustomerRequestCollection()).GetCustomerRequests(); } public ObservableCollection<CustomerRequest> CustomerRequests { get { return _requests; } set { if (_requests != value) { _requests = value; NotifyPropertyChanged("CustomerRequests"); } } } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } }
View(ビュー)を作成
これで表示するデータが揃いましたのでビューを作成します。
XAMLで定義する共通のビューを、前述のようにPCLプロジェクトのViewsフォルダの下に新規に追加します。
そのContentPage
タグの中に、データを表示するFlexGridを定義して設定します。
FlexGridを使うための名前空間の定義を行い、あわせてViewModel用の名前空間も定義します。
xmlns:c1="clr-namespace:C1.Xamarin.Forms.Grid;assembly=C1.Xamarin.Forms.Grid" xmlns:vm="clr-namespace:c1x_FlexGrid"
次に、ViewModelをContentPage
にバインドします。
WPFでは’DataContext’ですが、Xamarin.FormsではBindingContext
であることに注意してください。
<ContentPage.BindingContext> <vm:CustomerRequestViewModel /> </ContentPage.BindingContext>
最後にFlexGridの内容です。
データグリッドに表示するデータのソースは、BindingContext
に指定したViewModelにあります。
ItemsSource
プロパティに、’ObservableCollection’クラスのリストデータセットであるCustomerRequests
を接続します。
データの構造に合わせて列を自動的に作ることもできますが、ヘッダー部分に任意の文字列を表示した場合は、各列(GridColumn
クラス)を定義して、データ項目をBinding
に記述します。
グリッドの幅は、デバイスごとに表示される画面に最大化されるようにHorizontalOptions="FillAndExpand"
を指定しています。
また各列の幅は以下です。スターサイズ機能を利用してデータグリッド全体を表示し、表示領域の幅に応じて各列の幅を比率で自動調整しています。
列名 | Width指定 | 内容 |
---|---|---|
件名 | * | 表示幅を自動計算 |
受付日 | 0.5* | 件名列の半分の幅 |
備考 | Auto | セル内容に応じて幅を算出 |
以下のXAMLコードは、FlexGridに3つの列を定義したXAML全体です。
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:c1="clr-namespace:C1.Xamarin.Forms.Grid;assembly=C1.Xamarin.Forms.Grid" xmlns:vm="clr-namespace:c1x_FlexGrid" x:Class="c1x_FlexGrid.CustomerRequestView"> <ContentPage.BindingContext> <vm:CustomerRequestViewModel /> </ContentPage.BindingContext> <ContentPage.Content> <Grid VerticalOptions="FillAndExpand"> <c1:FlexGrid x:Name="flexgrid" ItemsSource="{Binding CustomerRequests}" HeadersVisibility="Column" AutoGenerateColumns="False" AutoSizeMode="Both" HorizontalOptions="FillAndExpand"> <c1:FlexGrid.Columns> <c1:GridColumn Header="件名" Binding="Title" AllowResizing="True" Width="*"/> <c1:GridColumn Header="受付日" Binding="OpenDate" Format="yyyy/MM/dd" Width="0.5*"/> <c1:GridColumn Header="備考" Binding="Note" Width="Auto"/> </c1:FlexGrid.Columns> </c1:FlexGrid> </Grid> </ContentPage.Content> </ContentPage>
なお、このXAMLに対応するコードビハインドに記載は不要です。
最後に、作成したビューをアプリのエントリーポイントとするために、PCLプロジェクトのApp.xaml.cs
に記述します。
public App() { InitializeComponent(); // ライセンス設定 C1.Xamarin.Forms.Core.LicenseManager.Key = License.Key; // NavigationPageの中に作成したビューを配置する MainPage = new NavigationPage(new c1x_FlexGrid.CustomerRequestView()); }
ViewをXAMLで作成している恩恵
以上で完成しました。
データを表示するだけですが、3種のプラットフォームで動作するサンプルの完成です。
左側がAndroid、右上段がUWPで下段がiOSです。
iOSアプリで横向き表示にした場合でも、前述のスターサイズ機能でグリッド全体を表示するように各列の比率を算出しています。
このように、MVVMデザインパターンで作成したアプリは、ビューとデータを分離できるため使いまわすことが容易です。
WPFとXamarin.Formsは、ビューは同じXAML技術をベースにしています。そのため今回は簡単にサンプルと記事を作ることができました(C#を使って記述することも可能です)。
使い回しの効く技術を習得しておくと、活躍する機会も増えることでしょう。
作成したソリューションはこちらで公開しています。
サンプルで使ったC1 Xamarin のライセンスも含まれますので、NuGetパッケージを復元すれば実行可能です *1。
XAML技術(WPF、UWP、Xamarin)のイベント開催
WPF、UWP、Xamarinと、XAMLを利用する各アプリ開発技術のエキスパートをお迎えし、開発事例を中心としたセッション主体のイベントを行います。
※この記事の投稿時点で、大変ありがたいことに既に満席(100名)となっています。申し訳ありませんが、参加ご希望の方はキャンセル待ちへのご登録をお願いいたします。
*1:NuGetパッケージを利用するには、GrapeCityのNuGetフィードソース( http://nuget.c1.grapecity.com/nuget/ )を、Visual Studioの環境に追加する必要があります。