例えば、表形式コンポーネントだとSPREADが非常に中心的な存在としてありますが、それと共に人気があるのがFlexGridです。VB6時代に提供されたFlexGridは「SPREADほどの高機能はいらない代わりに少しでも軽いコンポーネントが欲しい」という要望に極めてマッチしたコンポーネントで、バージョンアップにより機能が増えてきましたが、現バージョンでも軽快な動作は失われておらず、特に表形式で参照したいようなときは最初に検討するコンポーネントであることに変わりはありません。
また、Windowsフォーム、WPF、Windows Runtime(いわゆるモダンUI)の各々をサポートするエディションが提供されている特徴もあります。
FlexGridの今について
FlexGridは、ComponentOne Studioの一部として入手できます。執筆時点のFlexGridは次のようなエディションがあります。
単独製品 | ComponentOne Studio | |||
---|---|---|---|---|
- | Enterprise | Ultimate | ||
Windowsフォーム | - | for WinForms | ◯ | ◯ |
Silverlight | - | for Silverlight | ◯ | ◯ |
WPF | - | for WPF | ◯ | ◯ |
WinRT | - | for WinRT XAML | ◯ | ◯ |
今回はこの中から、WinForms、WPF、WinRTを使って、Microsoft Azure Mobile Servicesに保存されているデータを取得し一覧表示を行うサンプルを作成して、それぞれの使い勝手を検証したいと思います。
Microsoft Azure Mobile Service側は、AED検索オープンデータとして公開されているものを使います。AED検索オープンデータの詳細は「AED検索サポートページ」を参照してください。
なお、AED検索オープンデータは、Microsoft Azure Mobile Servicesで動作しているのでMobile Service SDKを使ってアクセスしてもいいのですが、https-GETでデータをリクエストするとJSON形式のデータが返信されてくる、いわゆるREST/JSONインターフェースを採用しているので、SDKを使わずに利用してみたいと思います。
エディション間で共通の作業
今回、3つのエディションでサンプルを作成しますが、ロジック部分はほぼ共通的な構造になっています。以下の、NuGetパッケージ追加、プロジェクト構造、ロジック記述は、各サンプル用の新規プロジェクト作成直後に同じように実施する項目になります。
NuGetパッケージ追加
REST/JSONを扱う場合、NuGetから「Json.NET」と「Microsoft HTTP Client Libraries」のNuGetパッケージを追加しておくと便利です。
プロジェクト構成
今回のサンプルでは、見た目とロジックを分離してその間をBindingという疎結合で結びつける方式に対応しているので、プロジェクト構成もModel-ViewModel-Viewとして、Modelにロジック、Viewに見た目を記載します。WPF版のサンプルプロジェクト構造は次のようになります。
ロジック記述
AED位置情報を取得するモデルであるAEDModelには、次のコードを記載します。
Imports System.Collections.ObjectModel Imports System.ComponentModel Imports System.Runtime.CompilerServices Imports System.Net.Http Imports Newtonsoft.Json Namespace Models Public Class AedInfo Public Property Id As Long Public Property LocationName As String Public Property Perfecture As String Public Property City As String Public Property AddressArea As String Public Property Latitude As Single Public Property Longitude As Single Public Property FacilityPlace As String Public Property ScheduleDayType As String Public Property PhotoOfAedUrl As String Public Property FacilityNote As String End Class Public Class AedModel Implements INotifyPropertyChanged Public Property Items As New ObservableCollection(Of AedInfo) Private Const AppUrl As String = "https://aed.azure-mobile.net/api/aedinfo/{0}/{1}" Public Async Function SelectData() As Task Try Dim url As String = String.Format(AppUrl, "神奈川県", "鎌倉市") Dim client = New HttpClient() Dim jsonString = Await client.GetStringAsync(New Uri(url)) Dim json = JsonConvert.DeserializeObject(Of IEnumerable(Of AedInfo))(jsonString) Me.Items.Clear() For Each item In json Me.Items.Add(item) Next Catch ex As Exception Debug.Assert(ex.Message) End Try End Function Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged Protected Sub OnPropertyChanged(<CallerMemberName> Optional propertyName As String = Nothing) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) End Sub End Class End Namespace
今回のサンプルでは、SelectDataメソッドを実行すると、Itemsプロパティに取得した神奈川県鎌倉市のAED位置情報が設定されてきます。
FlexGrid for WPF
共通作業が終わったので、FlexGrid for WPFのサンプルに必要な作業を開始します。
FlexGridの設置
ツールボックスに「WPFコンポーネント」からC1FlexGridを追加し、さらにメインフォームにドラッグ&ドロップで設置します。
<Window x:Class="Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:c1="http://schemas.componentone.com/winfx/2006/xaml" Title="MainWindow" Height="300" Width="300"> <Grid> <c1:C1FlexGrid HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding Items}" Margin="10" IsReadOnly="True" AutoGenerateColumns="True" > </c1:C1FlexGrid> </Grid> </Window>
ItemSourceプロパティにBinding設定を忘れずに指定しましょう。
Binding設定
MainWindow.xamlのコードビハインド側に、ロジックからのItemsをBindingするコードを追記します。直接AEDModel.vbを使うのではなく、間にMainViewModelクラスをはさんでいる点に注意してください。MainViewModelクラスは、Application.vbでMainVM変数にインスタンシング化して格納されています。
Namespace Views Public Class MainWindow Public Sub New() InitializeComponent() Me.DataContext = Application.MainVM SelectData() End Sub Private Async Sub SelectData() Await Application.MainVM.SelectData() End Sub End Class End Namespace
MainWindowクラスがnewされると、DataContextにMainViewModelクラスのインスタンスを設定し、それからSelectDataメソッドを呼び出します。SelectDataメソッドで値が設定されるItemsプロパティの内容は、MainWindow.xamlで指定してあるようにFlexGridにBindingされているので、Itemsプロパティの内容が変化すれば即座にFlexGridの表示に反映されます。
実行
FlexGridには、最小の手順で結果を得られるようにAutoGenerateColumnsという機能があり、AutoGenerateColumnsプロパティをTrueにすることで、Bindingしたプロパティ構造を自動的に列に展開する機能があります。
そのため、事前に定義をしなくても一覧表示が可能です。
表示列の明示的指定
AutoGenerateColumns機能を使うと不要な列を非表示にしたり、列の順番の初期位置を変更したりできません。そのような要望がある場合は、明示的に列と列に表示するプロパティ値を指定します。
<Window x:Class="Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:c1="http://schemas.componentone.com/winfx/2006/xaml" Title="{Binding Items[0].Perfecture}" Height="300" Width="300"> <Grid> <c1:C1FlexGrid HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding Items}" Margin="10" IsReadOnly="True" AutoGenerateColumns="False" > <c1:C1FlexGrid.Columns> <c1:Column Header="設備写真"> <c1:Column.CellTemplate> <DataTemplate> <Image Source="{Binding PhotoOfAedUrl}" /> </DataTemplate> </c1:Column.CellTemplate> </c1:Column> <c1:Column Binding="{Binding LocationName}" Header="施設名" Width="150" /> <c1:Column Binding="{Binding City}" Header="市町村区" Width="50" /> <c1:Column Binding="{Binding AddressArea}" Header="住所" Width="150" /> <c1:Column Binding="{Binding Latitude}" Header="緯度" /> <c1:Column Binding="{Binding Longitude}" Header="経度" /> </c1:C1FlexGrid.Columns> </c1:C1FlexGrid> </Grid> </Window>
<c1:C1FlexGrid.Columns>タグの中に必要な列の<c1:Column>タグを定義してあります。忘れてはいけないのは、AutoGenerateColumnsプロパティをFalseにすることです。
今回は、設備写真の画像URLをImageとして表示するように列属性の変更も行っています。
実行
かなり最適化された一覧表示ができあがりました。
FlexGrid for WinRT XAML
WPF版に引き続き、同様にFlexGrid+XAMLという形式で画面が定義できるWindowsストアアプリでの使い方も確認してみましょう。
NuGetパッケージ追加
Windowsストアアプリのプロジェクトでも「Json.NET」と「Microsoft HTTP Client Libraries」のNuGetパッケージが存在します。
プロジェクト構成
Windowsストアアプリ版のサンプルプロジェクト構造は次のようになります。
AEDModel.vbとMainViewModel.vbはWPF版がそのまま使えるので、既存項目の追加で所定のフォルダに追加します。
FlexGridの設置
ツールボックスに「WindowsおよびWindows Phone XAMLコンポーネント」からC1FlexGridを追加し、さらにメインフォームにドラッグ&ドロップで設置します。
: (中略) : <Grid Grid.Row="1"> <c1:C1FlexGrid HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding Items}" Margin="10" IsReadOnly="True" AutoGenerateColumns="True" > </c1:C1FlexGrid> </Grid> : (中略) :
Binding設定
MainPage.xamlのコードビハインド側に、ロジックからのItemsをBindingするコードを追記します。
: (中略) : Public Sub New() InitializeComponent() Me._navigationHelper = New Common.NavigationHelper(Me) AddHandler Me._navigationHelper.LoadState, AddressOf NavigationHelper_LoadState AddHandler Me._navigationHelper.SaveState, AddressOf NavigationHelper_SaveState Me.DataContext = App.MainVM SelectData() End Sub Private Async Sub SelectData() Await App.MainVM.SelectData() End Sub : (中略) :
MainPageクラスがnewされると、DataContextにMainViewModelクラスのインスタンスを設定し、それからSelectDataメソッドを呼び出します。SelectDataメソッドで値が設定されるItemsプロパティの内容は、MainPage.xamlで指定してあるようにFlexGridにBindingされているので、Itemsプロパティの内容が変化すれば即座にFlexGridの表示に反映されます。
実行
Windowsストアアプリ版でもAutoGenerateColumnsという機能があります。
そのため、事前に定義をしなくても一覧表示が可能です。
表示列の明示的指定
もちろんAutoGenerateColumns機能を使わずに列指定で一覧表示することも可能です。
: (中略) : <c1:C1FlexGrid HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding Items}" Margin="10" IsReadOnly="True" AutoGenerateColumns="False" > <c1:C1FlexGrid.Columns> <c1:Column Header="設備写真"> <c1:Column.CellTemplate> <DataTemplate> <Image Source="{Binding PhotoOfAedUrl}" /> </DataTemplate> </c1:Column.CellTemplate> </c1:Column> <c1:Column Binding="{Binding LocationName}" Header="施設名" Width="300" /> <c1:Column Binding="{Binding City}" Header="市町村区" Width="100" /> <c1:Column Binding="{Binding AddressArea}" Header="住所" Width="300" /> <c1:Column Binding="{Binding Latitude}" Header="緯度" /> <c1:Column Binding="{Binding Longitude}" Header="経度" /> </c1:C1FlexGrid.Columns> </c1:C1FlexGrid> : (中略) :
<c1:C1FlexGrid.Columns>タグの中に必要な列の<c1:Column>タグを定義してあります。忘れてはいけないのは、AutoGenerateColumnsプロパティをFalseにすることです。
今回は、設備写真の画像URLをImageとして表示するように列属性の変更も行っています。
実行
FlexGrid for WinForms
最後にXAMLではなくWindowsフォームでのFlexGridの使い勝手を確認してみましょう。
NuGetパッケージ追加
Windowsフォームのプロジェクトでも「Json.NET」と「Microsoft HTTP Client Libraries」のNuGetパッケージが存在します。
プロジェクト構成
WindowsフォームでもBindingが利用可能なので、プロジェクト構成もModel-ViewModel-Viewとして、Modelにロジック、Viewに見た目を記載します。
AEDModel.vbとMainViewModel.vbはWPF版がそのまま使えるので、既存項目の追加で所定のフォルダに追加します。
FlexGridの設置
ツールボックスに「.NET Frameworkコンポーネント」からC1FlexGridを追加し、さらにメインフォームにドラッグ&ドロップで設置します。
FlexGridのデータソースとしてMainViewModelクラスを指定します。
これでBindingの指定も完了です。
Binding設定
MainForm.vbのコードビハインド側で、SelectDataメソッドを呼び出してItemsをDataSourceに指定するコードを追記します。
Imports CZ1407Win.ViewModels Public Class MainForm Private MainVM As New MainViewModel Public Sub New() InitializeComponent() SelectData() End Sub Private Async Sub SelectData() Await Me.MainVM.SelectData() Me.MainViewModelBindingSource.DataSource = Me.MainVM.Items End Sub End Class
実行
デフォルト状態ではAutoGenerateColumnsがTrueなので、このまま実行してみます。
表示列の明示的指定
列を明示的に指定するときは列エディタを使用します。
実行
設備変更欄に画像を表示するためには、コードビハインド側で明示的に画像URLから画像データに変換するなどの処理が必要になるため、今回は確認を省略したいと思います。
まとめ
FlexGridを使ってWebサービスから取得した値を一覧表示してみましたが、いかががだったでしょうか。AutoGenerateColumnsなどを活用して素早く手軽に一覧表示ができるのは使っていてかなり気持ちが良かったです。これからはSPREADだけではなくFlexGridについても評価の対象にしていきたいと思いました。