.NET開発になり、また開発の現場での経費コントロールが厳しさを増したことにより、Windowsアプリでの市販コントロール利用はそれ以前に比べて厳選されるようになってきたと記憶しています。しかしそのようなときでも、SPRAED for .NETは「必要だからこれだけは購入しましょう」と必要経費として認知され続けていたと思います。
その流れの本流であるSPREAD for Windows Formsが便利な新機能を携えて、Windows 8とVisual Studio 2012に対応したのであれば、やはり紹介しないわけにはいきません。
今回は30個以上ある新機能の中から、特に興味をひかれた次の機能に注目したいと思います。
- ルールによる条件付き書式が強化され、データバー、カラースケール、アイコンセットなどが設定できるようになりました。
なお、本稿のサンプルはVisual Studio 2012および.NET Framework 4.5専用になりますので、あらかじめご留意ください。
Windowsフォームアプリで使用する
ツールボックスへの追加
追加コンポーネントをVisual Studioで使用するには、ツールボックスへ登録しておくと便利です。そのためには1度だけツールボックスへの登録操作を行わなければなりません。1度登録してしまえば、次回以降にこの操作は必要ありません。
ツールボックスへの登録を行うには、Visual Studioを起動してWindowsフォームアプリケーションの新規作成を行います。
まず、ツールボックスを右クリックして[タブの追加]を選択し、「GrapeCity Win」タブを追加します。次に、「GrapeCity Win」タブの下を右クリックし、[アイテムの選択]をクリックしてダイアログを表示します。
一覧で「FpSpread」をチェックして[OK]ボタンをクリックすれば、ツールボックスに追加できます。ここでVisual Studioを再起動しておくとよいでしょう。
ウィンドウデザイナでの作業
Windowsフォームアプリケーションの新規作成では、Form1というWindowsフォームが1つだけあるプロジェクトが生成されます。「Form1」では味気ないので、「MainForm」と名前を変更してから作業を進めたいと思います。名前の変更は、ソリューションエクスプローラーで「Form1」を右クリックして[名前の変更]メニューから行いましょう。
次に、ツールボックスにある「FpSpread」アイコンを、デザイナ上のウィンドウにドラッグ&ドロップします。
SPREADをWindowsフォームに配置すると、WindowsフォームにExcelライクなコントロールが配置され、同時にSpreadViewアイコンが非表示コントロール領域に配置されます。
また、コントロールへの最小設定と開発環境に必要なライセンスファイルの配置も自動的に行われます。Visual Basicのプロジェクトでは、ソリューションエクスプローラーで[すべてのファイルの表示]アイコン①を選択すると、追加したファイルを見ることができます。
データの作成
SPREADによる画面作成を行う前に、画面に表示するデータを取得するコードを記述しましょう。今回は、SPREAD for WPFのときに作ったサンプルアプリケーションと同じものを作成してみます。そのためにまずはWPF版のサンプルと同様にModelsフォルダ、ViewModelsフォルダ、Viewsフォルダを作成し、MainPage.vbをViewsフォルダに移動します。
coneco.netを利用するための準備
WPFでも使った、検索用APIがJSONで公開されているconeco.comを利用します。利用に際しては、利用者登録をしてAPIキーを取得しておく必要があります。サンプルコードではこの部分でコンパイルエラーがでるようにしてありますので、取得して行末のセミコロン(;)を削除して対応してください。
APIキーは、次のような手順で取得できますので、そのAPIキーを指定してアクセスする必要があります。
- https://www.coneco.net/api/にアクセスして、メールアドレスとパスワードを設定
- 本登録用URLのお知らせメールに書かれたAPIキー取得用URLをクリック
- APIキー発行完了のお知らせメールにある「あなたのAPIキー」をプログラムにセット
参照設定の追加
次に、coneco.netのAPIを使うために参照設定を追加します。
ソリューションエクスプローラーでプロジェクト名を右クリックして、[参照の追加]メニューでダイアログを表示し、System.Net.HttpとSystem.Runtime.Serializationを追加します。
Modelsフォルダに配置するコード
商品検索結果の形式
coneco.comの製品検索結果は、JSON形式で返却できます。返却されてくるJSON形式に合わせたクラス定義は、次のようになります。
Public Class ResultContext <System.Runtime.Serialization.DataContract()> _ Public Class TResult <System.Runtime.Serialization.DataMember()> _ Public Property Item As List(Of TItem) End Class <System.Runtime.Serialization.DataContract()> _ Public Class TItem <System.Runtime.Serialization.DataMember()> _ Public Property ComId As String : (略) : <System.Runtime.Serialization.DataMember()> _ Public Property Specifications As List(Of TSpecifications) End Class <System.Runtime.Serialization.DataContract()> _ Public Class TSpecifications <System.Runtime.Serialization.DataMember()> _ Public Property Id As String <System.Runtime.Serialization.DataMember()> _ Public Property Title As String <System.Runtime.Serialization.DataMember()> _ Public Property Spec As String End Class End Class
APIの呼び出し
商品検索APIは、次のようなURLにアクセスして行います。
http://api.coneco.net/cws/v1/SearchProducts_json?apikey=xxxx&categoryId=10120&sort=ranking
キーワード検索を行うときは、このURLの後ろに『&freeword=キーワード』のパラメタを付与します。
このようにして組み立てたURLを指定し、GetStringAsyncを実行してJSON形式のデータを受信します。
Public Class ConecoContext Public Property Ranking As String Public Property ComId As String Public Property Name As String Public Property Manufacturer As String Public Property LowestPrice As String Public Property HighestPrice As String Public Property CPU As String Public Property Disk As String Public Property Memory As String Public Property Display As String Public Property ImageUrl As String Public Property Img As Image End Class Public Class ConecoModel Implements INotifyPropertyChanged Public Property Items As New List(Of ConecoContext) : (略) : Private Sub GetItemContext(ByVal result As String) Using Stream As New MemoryStream(System.Text.Encoding.UTF8.GetBytes(result)) Dim serializer As New DataContractJsonSerializer(GetType(ResultContext.TResult)) Dim jsonDataValue As ResultContext.TResult = CType(serializer.ReadObject(Stream), ResultContext.TResult) Me.Items = (From item In jsonDataValue.Item Where item.SellerCount > 0 Order By CType(IIf(item.CategoryRanking.Length = 0, Integer.MaxValue, item.CategoryRanking), Integer) Select New ConecoContext With { : (中略) : }).ToList End Using End Sub : (略) : End Class
このコードにより、Itemsプロパティに画面表示に必要なデータがセットできます。
連結用クラスの作成
ViewModelsフォルダには、MainViewModelクラスを定義します。このクラスが最終的に画面とバインディングします。
Imports System.ComponentModel Imports System.Collections.ObjectModel Public Class MainViewModel Implements INotifyPropertyChanged Private WithEvents Model As New ConecoModel Public ReadOnly Property Items As List(Of ConecoContext) Get Return Me.Model.Items End Get End Property Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _ Implements INotifyPropertyChanged.PropertyChanged Private Sub Model_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _ Handles Model.PropertyChanged RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(e.PropertyName)) End Sub Public Sub GetItemsCommand(ByVal parameter As String) Me.Model.GetItems(parameter) End Sub End Class
データ自動表示
それでは、SPREADに単純にMainViewModelクラスをバインディングしてみましょう。
MainForm.vbでは、ConecoModelと連結したMainViewModelをDataContextに割り当てるコードだけが必要です。
Imports System.ComponentModel Public Class MainForm Private WithEvents ViewModel As New MainViewModel Private Sub Me_Load(sender As Object, e As EventArgs) Handles Me.Load Me.Cursor = Cursors.WaitCursor Me.ViewModel.GetItemsCommand("") End Sub Private Sub ViewModel_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _ Handles ViewModel.PropertyChanged Me.FpSpread1.DataSource = Me.ViewModel.Items Me.Result_Sheet.AutoGenerateColumns = True Me.Cursor = Cursors.Default End Sub End Class
このサンプルでは、.NET Framework 4.5で追加になった非同期待ち合わせのAsync-Awaitを使っているため、「Me.ViewModel.GetItemsCommand("")」の実行直後はまだ値が設定されていません。値が設定されるのは、PropertyChangedイベントでItemsプロパティが変更されたのが通知されてからになります。
そのため遅い回線でサンプルを実行した場合は、画面が表示された後、しばらくしてから検索結果が表示されます。
実行結果
SPREADのデザイン側にはまだ何も設定はしていませんが、この状態でどのような表示になるか確認してみましょう。
SPREADは高機能なので、使うのが大変だという先入観を持ってしまう人もいるかもしれません。しかし、表示用のListの内容をそのまま表示するのであれば、SPREAD自体に設定は不要となります。ですから将来的に複雑な修飾が出来るように、可能であればシンプルな用途のときから、「表といえばSPREAD」というようにSPREADを使って画面をつくっていくのが得策です。
それではこのシンプルな表示から、SPREADならではの修飾を加えていってみましょう。
セル、行、列エディタの実行
SPREADでセルを修飾するには、製品付属の専用デザイナを使用します。
SPREADのデザイナの起動は2つの方法があります。1つはWindowsフォーム上のSPREADコントロールの[FpSpreadタスク]から、もう一つは非表示コントロール領域に配置されたSheetViewの[SheetViewタスク]からです。シートのデザインに特化したのは後者なので、まずはSheetViewタスクから「セル、行、列エディタ」を起動してみましょう。
セル、行、列エディタでの作業
セル、行、列エディタでは、セル単位、行単位、列単位の設定が可能です。今回は列にバインドしてデータ表示を行うので列の設定を行います。
列の設定
最初に修飾する内容としては、ComId列の削除とタイトルの日本語化を行ってみたいと思います。
そのためには列タイトルをクリックして列ごとの設定を行います。
Labelプロパティが列のタイトルなので、Labelプロパティに各列の日本語タイトルを記入していきます。CPU、Disk、Memory、Displayは要素名がタイトルとして使えるのでLabelプロパティはデフォルトのままで問題ありません。列のA~EのLabelプロパティに対して「ランキング」「製品名」「発売元」「最安値」「最高値」をそれぞれ設定します。
次にデータソースのどの要素を割り当てるかをDataFieldプロパティに設定しようとしたのですが、DataFiledプロパティのプロパティ欄には自由に要素名が入力できません。このあたりは改善してほしい点なのですが、現状での対応策として今回はコード側でDataFieldプロパティを指定します。
MainForm.vbのMe_Loadプロシージャの内容を変更しましょう。
Imports System.ComponentModel Imports FarPoint.Win.Spread.Model Public Class MainForm Private WithEvents ViewModel As New MainViewModel Private Sub Me_Load(sender As Object, e As EventArgs) Handles Me.Load Me.Cursor = Cursors.WaitCursor ' Me.Result_Sheet.RowCount = 0 Me.Result_Sheet.ColumnCount = 9 Me.Result_Sheet.AutoGenerateColumns = False Me.Result_Sheet.Columns(0).DataField = "Ranking" Me.Result_Sheet.Columns(1).DataField = "Name" Me.Result_Sheet.Columns(2).DataField = "Manufacturer" Me.Result_Sheet.Columns(3).DataField = "LowestPrice" Me.Result_Sheet.Columns(4).DataField = "HighestPrice" Me.Result_Sheet.Columns(5).DataField = "CPU" Me.Result_Sheet.Columns(6).DataField = "Disk" Me.Result_Sheet.Columns(7).DataField = "Memory" Me.Result_Sheet.Columns(8).DataField = "Display" ' Me.ViewModel.GetItemsCommand("") End Sub Private Sub ViewModel_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _ Handles ViewModel.PropertyChanged Me.FpSpread1.DataSource = Me.ViewModel.Items ' Me.Cursor = Cursors.Default End Sub End Class
AutoGenerateColumnsプロパティがTrueだと、データソースに合わせて列が追加されてしまうため、まずこのプロパティをFalseにします。その後、ColumnsコレクションのDataFieldプロパティに対して要素名を設定します。
実行結果
それでは、ここまでの設定でどのように表示が変わるか確認してみましょう。
想定したとおりのComId欄の削除とタイトル名の日本語化が行えました。
セル型の設定
デザイナを起動して、[ランキング]列タイトルをクリックし、HorizontalAlignmentプロパティの値を「Right」にします。
[最安値]列、[最高値]列については、CellTypeプロパティを「Currency」に設定します。表示フォーマットには、3桁ごとに桁区切りをつけるためにShowSeparatorプロパティに「True」、小数点以下は不要なのでDecimalPlacesプロパティに「0」を設定します。
実行
この状態でどのような表示になるか実行してみましょう。
意図したとおり右寄せ表示になっていますが、最安値と最高値の表示フォーマット設定が反映されていません。
表示フォーマットを反映させる
表示フォーマットが反映されなかった理由は、データをバインディングしたときに要素の変数型を自動的にセル型として設定する機能がSPREADにあるからです。そのため、CellTypeプロパティへの設定したセル型が上書きされて設定した表示フォーマットも消されてしまうからです。
そこでMe_Loadプロシージャにさらに追加設定を行います。
Private Sub Me_Load(sender As Object, e As EventArgs) Handles Me.Load Me.Cursor = Cursors.WaitCursor ' Me.Result_Sheet.RowCount = 0 Me.Result_Sheet.AutoGenerateColumns = False ' Me.Result_Sheet.DataAutoCellTypes = False Me.Result_Sheet.DataAutoSizeColumns = False ' : (略) : ' Me.ViewModel.GetItemsCommand("") End Sub
DataAutoCellTypesプロパティをFalseにすることで、データソースの変数型ではなくSPREADの設定したセル型が使われます。またDataAutoSizeColumnsプロパティをFalseにすることでセル幅の自動設定も抑止できます。これでデザイナでの見た目が実行時にも確保できます。
条件付き書式の適用
ここまでは、前バージョンのSPREAD for Windows Formsでも対応が可能な範囲です。では、いよいよ今回のバージョンの新機能である、条件付き書式を使ったデータバー表示を行ってみましょう。
データバーの設定は、まずDatabarConditionalFormattingRuleに各種設定を行い、その後、該当範囲のセルのConditionalFormattingに設定します。DatabarConditionalFormattingRuleに設定できるのは、例えばデータバーの色になります。その他にも、データバーは最大値の時にセルいっぱいのデータバーを表示するので該当列の最大値が必要ですが、SPREADでは「ConditionalFormattingValue(ConditionalFormattingValueType.AutoMax)」と指定することで自動的に最大値を算出してくれます。
Imports System.ComponentModel Imports FarPoint.Win.Spread Imports FarPoint.Win.Spread.Model : (略) : Private Sub ViewModel_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _ Handles ViewModel.PropertyChanged Me.FpSpread1.DataSource = Me.ViewModel.Items ' ' ◆条件付き書式設定(データバー) Dim dataBarRule As New DatabarConditionalFormattingRule() dataBarRule.AxisPosition = DataBarAxisPosition.Automatic dataBarRule.BorderColor = Color.Blue dataBarRule.NegativeFillColor = Color.Red dataBarRule.Gradient = True dataBarRule.Maximum = New ConditionalFormattingValue(ConditionalFormattingValueType.AutoMax) dataBarRule.Minimum = New ConditionalFormattingValue(ConditionalFormattingValueType.AutoMin) dataBarRule.UseNegativeFillColor = True dataBarRule.UseNegativeBorderColor = False Dim cf As New ConditionalFormatting(New CellRange(0, 3, Me.Result_Sheet.RowCount, 2)) cf.Add(dataBarRule) Me.Result_Sheet.Models.ConditionalFormatting.Add(cf) ' Me.Cursor = Cursors.Default End Sub
実行
対応が終わったので、実行してみましょう。
残念ながら、想定していたようなデータバーは表示できませんでした。
データソースの型の調整
データバーの設定が有効にならなかったのは、データバーがデータソースの変数型がString型であったためです。列のプロパティをCurreny型にしていたとしても、データソースの変数型がString型のままだとデータバーは表示されません。
さっそく、最安値と最高値のデータソースの変数型をString型からDecimal型またはInteger型などの数値型プロパティに変更しましょう。
Public Class ConecoContext Public Property Ranking As Integer Public Property ComId As String Public Property Name As String Public Property Manufacturer As String Public Property LowestPrice As Decimal Public Property HighestPrice As Decimal Public Property CPU As String Public Property Disk As String Public Property Memory As String Public Property Display As String End Class
データバーを表示したいConecoContextクラスのLowestPriceとHighestPriceを、String型からDecimal型に変更しています。
この対応により、無事データバーを表示することができます。
あとは製品名欄や発売元欄に対して列幅を調整するなど、画面全体を業務アプリとしての使用にふさわしい整形をすれば完成です。
まとめ
SPREAD for Windows Formsの豊富な機能から、2つの機能を紹介してみましたがいかがだったでしょうか。WPFに比べて表現力のベースが低いWindowsフォームですが、SPREADを使うことでWPFとは別の表現力を手に入れていれたといってよいでしょう。
その1つが今回紹介したExcelライクな条件付き書式であり、もう1つが今回は紹介しなかったInputManライクなテキスト型セルと日付型セルによる入力サポートです。
業務システム開発では「Excelライクな表示」を求められることが多く、そしてExcelの入力機能以上の入力を求められることが多いのも事実です。
最近はWebベースの業務システムも流行りましたが、だからこそWindowsフォームによるアプリを選択したときの要求水準は高いといえるでしょう。そのような高い要求水準を満たすには、標準コントロールでは荷が重いケースもあります。以前よりは機能が豊富になってきたとはいえ、標準コントロールでは力不足な案件が増えてきており、その要求に応えるアプリの作成には、市販コントロールの採用が重要度を増しています。
過去にSPREADを使ったことがある人もない人も、まずは評価版で最新のSPREAD for Windows Formsをぜひ体感してみてください。