SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

現役エンジニア直伝! 「現場」で使えるコンポーネント活用術(SPREAD)

「SPREAD for Windows Forms 7.0J」の新機能に迫る

グレープシティのフラグシップコンポーネントがWindows 8/Visual Studio 2012に対応

  • X ポスト
  • このエントリーをはてなブックマークに追加

 グレープシティのコンポーネントといえば何が思い浮かぶかというと、InputManとSpread/OCXと答える人も多いと思います。何の気なしにSpread/OCXとOCXまで含めて製品名を答えてしまうくらい、Visual Basic 6.0までの開発ではActive XコントロールであるSpread/OCXは必須コントロールの座につき続けていました。

  • X ポスト
  • このエントリーをはてなブックマークに追加

 .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」タブの下を右クリックし、[アイテムの選択]をクリックしてダイアログを表示します。

図1 ツールボックスへの追加
図1 ツールボックスへの追加

 一覧で「FpSpread」をチェックして[OK]ボタンをクリックすれば、ツールボックスに追加できます。ここでVisual Studioを再起動しておくとよいでしょう。

ウィンドウデザイナでの作業

 Windowsフォームアプリケーションの新規作成では、Form1というWindowsフォームが1つだけあるプロジェクトが生成されます。「Form1」では味気ないので、「MainForm」と名前を変更してから作業を進めたいと思います。名前の変更は、ソリューションエクスプローラーで「Form1」を右クリックして[名前の変更]メニューから行いましょう。

 次に、ツールボックスにある「FpSpread」アイコンを、デザイナ上のウィンドウにドラッグ&ドロップします。

図2 FpSpreadを配置
図2 FpSpreadを配置

 SPREADをWindowsフォームに配置すると、WindowsフォームにExcelライクなコントロールが配置され、同時にSpreadViewアイコンが非表示コントロール領域に配置されます。

 また、コントロールへの最小設定と開発環境に必要なライセンスファイルの配置も自動的に行われます。Visual Basicのプロジェクトでは、ソリューションエクスプローラーで[すべてのファイルの表示]アイコン①を選択すると、追加したファイルを見ることができます。

図3 自動的に追加されるファイル
図3 自動的に追加されるファイル

データの作成

 SPREADによる画面作成を行う前に、画面に表示するデータを取得するコードを記述しましょう。今回は、SPREAD for WPFのときに作ったサンプルアプリケーションと同じものを作成してみます。そのためにまずはWPF版のサンプルと同様にModelsフォルダ、ViewModelsフォルダ、Viewsフォルダを作成し、MainPage.vbをViewsフォルダに移動します。

coneco.netを利用するための準備

 WPFでも使った、検索用APIがJSONで公開されているconeco.comを利用します。利用に際しては、利用者登録をしてAPIキーを取得しておく必要があります。サンプルコードではこの部分でコンパイルエラーがでるようにしてありますので、取得して行末のセミコロン(;)を削除して対応してください。

 APIキーは、次のような手順で取得できますので、そのAPIキーを指定してアクセスする必要があります。

  1. https://www.coneco.net/api/にアクセスして、メールアドレスとパスワードを設定
  2. 本登録用URLのお知らせメールに書かれたAPIキー取得用URLをクリック
  3. APIキー発行完了のお知らせメールにある「あなたのAPIキー」をプログラムにセット

参照設定の追加

 次に、coneco.netのAPIを使うために参照設定を追加します。

図4 参照設定の追加
図4 参照設定の追加

 ソリューションエクスプローラーでプロジェクト名を右クリックして、[参照の追加]メニューでダイアログを表示し、System.Net.HttpとSystem.Runtime.Serializationを追加します。

Modelsフォルダに配置するコード

商品検索結果の形式

 coneco.comの製品検索結果は、JSON形式で返却できます。返却されてくるJSON形式に合わせたクラス定義は、次のようになります。

リスト1 製品検索結果の定義(ResultContext.vbから抜粋)
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形式のデータを受信します。

リスト2 製品検索結果の定義(ConecoModel.vbから抜粋)
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クラスを定義します。このクラスが最終的に画面とバインディングします。

リスト3 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に割り当てるコードだけが必要です。

リスト4 MainForm.vbの内容
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のデザイン側にはまだ何も設定はしていませんが、この状態でどのような表示になるか確認してみましょう。

図5 実行結果
図5 実行結果

 SPREADは高機能なので、使うのが大変だという先入観を持ってしまう人もいるかもしれません。しかし、表示用のListの内容をそのまま表示するのであれば、SPREAD自体に設定は不要となります。ですから将来的に複雑な修飾が出来るように、可能であればシンプルな用途のときから、「表といえばSPREAD」というようにSPREADを使って画面をつくっていくのが得策です。

 それではこのシンプルな表示から、SPREADならではの修飾を加えていってみましょう。

セル、行、列エディタの実行

 SPREADでセルを修飾するには、製品付属の専用デザイナを使用します。

 SPREADのデザイナの起動は2つの方法があります。1つはWindowsフォーム上のSPREADコントロールの[FpSpreadタスク]から、もう一つは非表示コントロール領域に配置されたSheetViewの[SheetViewタスク]からです。シートのデザインに特化したのは後者なので、まずはSheetViewタスクから「セル、行、列エディタ」を起動してみましょう。

図6 SheetViewタスクからのデザイナ実行
図6 SheetViewタスクからのデザイナ実行

セル、行、列エディタでの作業

 セル、行、列エディタでは、セル単位、行単位、列単位の設定が可能です。今回は列にバインドしてデータ表示を行うので列の設定を行います。

列の設定

 最初に修飾する内容としては、ComId列の削除とタイトルの日本語化を行ってみたいと思います。

 そのためには列タイトルをクリックして列ごとの設定を行います。

図7 列のプロパティ
図7 列のプロパティ

 Labelプロパティが列のタイトルなので、Labelプロパティに各列の日本語タイトルを記入していきます。CPU、Disk、Memory、Displayは要素名がタイトルとして使えるのでLabelプロパティはデフォルトのままで問題ありません。列のA~EのLabelプロパティに対して「ランキング」「製品名」「発売元」「最安値」「最高値」をそれぞれ設定します。

 次にデータソースのどの要素を割り当てるかをDataFieldプロパティに設定しようとしたのですが、DataFiledプロパティのプロパティ欄には自由に要素名が入力できません。このあたりは改善してほしい点なのですが、現状での対応策として今回はコード側でDataFieldプロパティを指定します。

 MainForm.vbのMe_Loadプロシージャの内容を変更しましょう。

リスト5 MainForm.vbの変更
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プロパティに対して要素名を設定します。

実行結果

 それでは、ここまでの設定でどのように表示が変わるか確認してみましょう。

図8 実行結果
図8 実行結果

 想定したとおりのComId欄の削除とタイトル名の日本語化が行えました。

セル型の設定

 デザイナを起動して、[ランキング]列タイトルをクリックし、HorizontalAlignmentプロパティの値を「Right」にします。

 [最安値]列、[最高値]列については、CellTypeプロパティを「Currency」に設定します。表示フォーマットには、3桁ごとに桁区切りをつけるためにShowSeparatorプロパティに「True」、小数点以下は不要なのでDecimalPlacesプロパティに「0」を設定します。

図9 列の修飾設定
図9 列の修飾設定

実行

 この状態でどのような表示になるか実行してみましょう。

図10 実行結果
図10 実行結果

 意図したとおり右寄せ表示になっていますが、最安値と最高値の表示フォーマット設定が反映されていません。

表示フォーマットを反映させる

 表示フォーマットが反映されなかった理由は、データをバインディングしたときに要素の変数型を自動的にセル型として設定する機能がSPREADにあるからです。そのため、CellTypeプロパティへの設定したセル型が上書きされて設定した表示フォーマットも消されてしまうからです。

 そこでMe_Loadプロシージャにさらに追加設定を行います。

リスト6 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にすることでセル幅の自動設定も抑止できます。これでデザイナでの見た目が実行時にも確保できます。

図11 実行結果
図11 実行結果

条件付き書式の適用

 ここまでは、前バージョンのSPREAD for Windows Formsでも対応が可能な範囲です。では、いよいよ今回のバージョンの新機能である、条件付き書式を使ったデータバー表示を行ってみましょう。

 データバーの設定は、まずDatabarConditionalFormattingRuleに各種設定を行い、その後、該当範囲のセルのConditionalFormattingに設定します。DatabarConditionalFormattingRuleに設定できるのは、例えばデータバーの色になります。その他にも、データバーは最大値の時にセルいっぱいのデータバーを表示するので該当列の最大値が必要ですが、SPREADでは「ConditionalFormattingValue(ConditionalFormattingValueType.AutoMax)」と指定することで自動的に最大値を算出してくれます。

リスト7 ViewModel_PropertyChangedプロシージャの変更
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

実行

 対応が終わったので、実行してみましょう。

図12 データバー設定後の実行結果
図12 データバー設定後の実行結果

 残念ながら、想定していたようなデータバーは表示できませんでした。

データソースの型の調整

 データバーの設定が有効にならなかったのは、データバーがデータソースの変数型がString型であったためです。列のプロパティをCurreny型にしていたとしても、データソースの変数型がString型のままだとデータバーは表示されません。

 さっそく、最安値と最高値のデータソースの変数型をString型からDecimal型またはInteger型などの数値型プロパティに変更しましょう。

リスト8 プロパティの型変更
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型に変更しています。

 この対応により、無事データバーを表示することができます。

 あとは製品名欄や発売元欄に対して列幅を調整するなど、画面全体を業務アプリとしての使用にふさわしい整形をすれば完成です。

図13 型の調整後の実行結果
図13 型の調整後の実行結果

まとめ

 SPREAD for Windows Formsの豊富な機能から、2つの機能を紹介してみましたがいかがだったでしょうか。WPFに比べて表現力のベースが低いWindowsフォームですが、SPREADを使うことでWPFとは別の表現力を手に入れていれたといってよいでしょう。

 その1つが今回紹介したExcelライクな条件付き書式であり、もう1つが今回は紹介しなかったInputManライクなテキスト型セルと日付型セルによる入力サポートです。

 業務システム開発では「Excelライクな表示」を求められることが多く、そしてExcelの入力機能以上の入力を求められることが多いのも事実です。

 最近はWebベースの業務システムも流行りましたが、だからこそWindowsフォームによるアプリを選択したときの要求水準は高いといえるでしょう。そのような高い要求水準を満たすには、標準コントロールでは荷が重いケースもあります。以前よりは機能が豊富になってきたとはいえ、標準コントロールでは力不足な案件が増えてきており、その要求に応えるアプリの作成には、市販コントロールの採用が重要度を増しています。

 過去にSPREADを使ったことがある人もない人も、まずは評価版で最新のSPREAD for Windows Formsをぜひ体感してみてください。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/6993 2016/03/29 17:40

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング