より進化した定番コンポーネント SPREAD
SPREAD for .NET Web Forms Ed.は、Windowsアプリケーション用の定番表計算コンポーネントであるSPREADのWebアプリケーション版です。
今回、このコンポーネントを評価するにあたり、過去の苦い経験が蘇りました。それは、SPREAD for .NET 2.5J Web Forms Ed.が発売されたときのことです。ちょうど大規模なインターネット向けWebアプリケーションの案件があったので、SPREADの利用を前提に提案書を作成して受注しました。しかし、実際に提供するのに先立ち、トライアル版をダウンロードして試してみると、2.5JではFirefox対応が不十分で「Internet ExplorerとFirefox両方に対応して欲しい」というお客様の要望を満たせず、動作速度も遅いという状況でした。そのため、SPREADを前提に作成した提案書のデザインを見ながら、.NETの標準コンポーネントであるRepeaterコントロールとHTML/CSSを駆使して、なんとか完成にこぎつけました。
そんなマイナスイメージがあったSPREAD for .NET Web Forms Ed.ですが、最新バージョンである3.0Jは、2.5Jとはまったく別物でした。3.0Jを試してみると、一部制限はありますがFirefox 2.0にも対応しており、基本的な見た目や操作は問題ありませんでした。また、2.5Jよりも明らかに動作が軽く、満足のいく動作速度が確保でき、「あのとき3.0Jがあれば、あんな苦労はしないで済んだし、もっと多機能でよいデザインの一覧表が搭載できたのに」と、とても複雑な気持ちになりました。チャンスがあれば、3.0Jで作り直したいくらいです。
2.5Jを使ったことのある方も、3.0Jで初めてSPREAD for .NET Web Forms Ed.に触れる方も、ぜひこの機会に手にとって試してみることをお勧めします(トライアル版申し込みページ)。それでは早速、このSPREADを使ってTwitter関連のWebアプリケーションを作成していきながら、その魅力に迫っていきましょう。
SPREAD for .NET Web Forms Ed.利用前の準備
ツールバーにSPREAD for .NET Web Forms Ed.を追加する
SPREAD for .NETをインストールした直後は、Visual Studioのツールボックスにコンポーネントが表示されていません。ツールボックスを右クリックして[アイテムの選択]メニューを選び、表示される画面で「FarPoint.Web.SpreadJ」名前空間の「FpSpread」を選択します。これでツールボックスにFpSpreadが表示されます。
「fp_client」フォルダの設置
SPREAD for .NETが使用するアイコンやスクリプトは、「fp_client」フォルダの中に定義されています。そのため製品に同封されている「fp_client」フォルダを、開発環境のプロジェクトファイルや運用環境に配布しなければなりません。テストのしやすさを考えると、【図2】のようにプロジェクトファイルのルートに配置し、運用環境への配布もプロジェクトファイルの一部として行うのが簡単です。
データセットの内容を簡単に表示する
SPREAD for .NETは多機能であると同時に、簡単に使えるモードも完備しています。例えば、DataSetの内容を一覧表示するのであれば、サンプルソースの「CZ0910FollowerType1」(リスト1)のようなコードだけで、【図3】の実行結果が得られます。
Partial Class _Default Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load If Not Me.IsPostBack Then FpSpread1.ActiveSheetView.OperationMode = _ FarPoint.Web.Spread.OperationMode.ReadOnly Me.FpSpread1.Width = Unit.Percentage(90) End If End Sub Protected Sub Get_Command_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Get_Command.Click Call SetData(Me.UserID_TextBox.Text, Me.Password_TextBox.Text) End Sub Private Sub SetData(ByVal userID As String, ByVal password As String) Using _proc As New Twitter Me.FpSpread1.ActiveSheetView.DataSource = _proc.GetFollowers(userID, password) End Using End Sub End Class
- LoadイベントでPostback以外のときにOperationModeをReadOnlyにし、読み取り専用にして、Widthを90%に設定する
- [Get]ボタンをクリックしたらDataTableを取得してDataSourceに設定し、その内容を表示する
このサンプルソースのDataSetの内容は、前回のSPREAD for .NET Windows Forms Ed.のサンプルと同様、コミュニケーションサービス「Twitter」上で、自分の発言を購読してくれている人の一覧になっています。
表示内容を修飾する
「CZ0910FollowerType1」は、必要最小限のプロパティ設定とコード記述でSPREADを使うことを第一目的としているため、見た目の美しさは考慮していません。また、byte配列に格納している画像ファイルも表示されていません。
サンプルソースに同梱してある「CZ0910FollowerType2」では、画面の修飾と画像ファイルの表示に対応したいと思います。
「CZ0910FollowerType2」では、ページのLoadイベントとOnPreRenderメソッドの2カ所で修飾を行っています。大半の処理はLoadイベントに記載していますが、OnPreRenderメソッドでは数式の設定と画像表示を行っています。
Loadイベントでの処理
Loadイベントでは、次の処理を行っています。
- スキンを適用
- スタイル設定用CSSを自動生成
- 文字の折り返しを禁止
- 列数設定
- 数式指定モードの指定
- シート全体の調整
- 列ヘッダの連結
- 高さや幅変更の抑止
- 各列の定義
スキンを適用
SPREAD for .NETには、罫線や色調を組み合わせた「スキン」と呼ばれるテンプレート機能があります。独自にスキンを作成して指定する事もできますが、標準で定義されているデフォルトスキンにも使いやすいものが揃っています。
Me.FpSpread1.ActiveSheetView.ActiveSkin = FarPoint.Web.Spread.DefaultSkins.Colorful4
スタイル設定用CSSを自動生成
BackColor、ForeColor、FontなどのスタイルをHTML化(レンダリング)するときに、CSSを自動生成して使うように指定すると、同じスタイルをCSS定義にまとめることができるためページサイズが小さくなりページロード時間が短くなります。
Me.FpSpread1.RenderCSSClass = True
文字の折り返しを禁止
テキスト型セルでは、セル内での文字折り返しを禁止するように設定します。そのための指定は、列やセルに直接行うのではなく、テキスト型セルのオブジェクトを生成し、AllowWrapプロパティにFalseを設定してからセルや列に割り当てます。
Dim textCellType As New FarPoint.Web.Spread.TextCellType : textCellType.AllowWrap = False : Me.FpSpread1.ActiveSheetView.Columns(3).CellType = textCellType
列数の設定
シート全体の調整などを行った場合、不要な列があると処理量が多くなるため、なるべく早いタイミングで列数を設定します。
Me.FpSpread1.ActiveSheetView.Columns.Count = 9
数式指定モードを指定
セルに数式を埋め込む場合、他のセルを値として指定する書式には「A1形式」と「R1C1形式」の2つがあります。R1C1形式の方が、列や行の位置を絶対位置でも相対位置でも指定しやすいので、サンプルではR1C1形式を指定しています。
Me.FpSpread1.ActiveSheetView.ReferenceStyle = FarPoint.Web.Spread.Model.ReferenceStyle.R1C1
シート全体の調整
サンプル「CZ0910FollowerType1」ではDataSetの内容に応じてセル型や列幅が自動的に決まりましたが、明示的に修飾を行うときにはこの自動機能をオフにしないと、設定した内容が実行時に有効になりません。
Me.FpSpread1.ActiveSheetView.DataAutoCellTypes = False Me.FpSpread1.ActiveSheetView.AutoGenerateColumns = False Me.FpSpread1.ActiveSheetView.DefaultStyle.VerticalAlign = VerticalAlign.Middle Me.FpSpread1.ActiveSheetView.AllowUserFormulas = False
- DataAutoCellTypesプロパティをFalseにして、セル型自動設定を無効化
- AutoGenerateColumnsプロパティをFalseにして、DataSetの列から自動的に列を生成しないように設定
- VerticalAlignプロパティをMiddleにして、セル高の真ん中に配置
- AllowUserFormulasプロパティをFalseにして、実行時に画面から数式の入力ができないように設定
列ヘッダの連結
サンプル「CZ0909FollowerType2」では、左から2つ目の列ヘッダ(列指定は「0」から始まるので指定値は「1」)から3列を1つのヘッダに連結するデザインになっています。
列ヘッダの連結には、AddColumnHeaderSpanCellメソッドを使用します。
Me.FpSpread1.ActiveSheetView.ColumnHeaderSpanModel.Add(0, 1, 1, 3)
高さや幅変更の抑止
Webアプリケーションにおいて、行の高さや列の幅を利用者が好みに応じて変更できるようにすることは難しい場合もありますが、SPREADではデフォルトで高さや幅の変更が可能な状態になっています。しかし、業務アプリケーションでは固定化して設計時の状態から変更しないことで、使い勝手の相違が生じないようにする場合があります。そのような場合は、ResizableプロパティをFalseにするとよいでしょう。
Me.FpSpread1.ActiveSheetView.RowHeader.Rows.Default.Resizable = False Me.FpSpread1.ActiveSheetView.ColumnHeader.Columns.Default.Resizable = False
各列の定義
ここまで設定できたら、後は各列を順次定義していくだけになります。
'ID列は非表示にする Me.FpSpread1.ActiveSheetView.Columns(0).DataField = "ID" Me.FpSpread1.ActiveSheetView.Columns(0).Visible = False 'アイコン列の設定を行う Me.FpSpread1.ActiveSheetView.ColumnHeader.Cells(0, 1).Text = "ユーザ名" Me.FpSpread1.ActiveSheetView.Columns(1).CellType = imageCellType '名前列の設定を行う Me.FpSpread1.ActiveSheetView.Columns(2).DataField = "Name" Me.FpSpread1.ActiveSheetView.Columns(2).CellType = textCellType Me.FpSpread1.ActiveSheetView.Columns(2).Locked = True 'ID名列の設定を行う Me.FpSpread1.ActiveSheetView.Columns(3).DataField = "ScreenName" Me.FpSpread1.ActiveSheetView.Columns(3).CellType = textCellType Me.FpSpread1.ActiveSheetView.Columns(3).Locked = True 'プロテクション列は非表示にする Me.FpSpread1.ActiveSheetView.Columns(4).DataField = "IsProtected" Me.FpSpread1.ActiveSheetView.Columns(4).Visible = False 'プロテクションだったら○表示する列に計算式を設定する Me.FpSpread1.ActiveSheetView.ColumnHeader.Cells(0, 5).Text = "プロテクト" Me.FpSpread1.ActiveSheetView.Columns(5).CellType = textCellType Me.FpSpread1.ActiveSheetView.Columns(5).Locked = True Me.FpSpread1.ActiveSheetView.Columns(5).HorizontalAlign = HorizontalAlign.Center Me.FpSpread1.ActiveSheetView.Columns(5).Formula = "IF(RC5=""True"",""○"","""")" 'フォロー列は非表示にする Me.FpSpread1.ActiveSheetView.Columns(6).DataField = "IsFollowing" Me.FpSpread1.ActiveSheetView.Columns(6).Visible = False 'フォローしてたら○表示する列に計算式を設定する Me.FpSpread1.ActiveSheetView.ColumnHeader.Cells(0, 7).Text = "フォロー済" Me.FpSpread1.ActiveSheetView.Columns(7).CellType = textCellType Me.FpSpread1.ActiveSheetView.Columns(7).Locked = True Me.FpSpread1.ActiveSheetView.Columns(7).HorizontalAlign = HorizontalAlign.Center Me.FpSpread1.ActiveSheetView.Columns(7).Formula = "IF(RC[-1]=""True"",""○"","""")" '最新の発言列の設定を行う Me.FpSpread1.ActiveSheetView.Columns(8).DataField = "StatusText" Me.FpSpread1.ActiveSheetView.ColumnHeader.Cells(0, 8).Text = "最新の発言" Me.FpSpread1.ActiveSheetView.Columns(8).CellType = textCellType Me.FpSpread1.ActiveSheetView.Columns(8).Locked = True
- データを特定するためのID列は、ユーザーインターフェイスとしては不要なので、VisibleプロパティにFalseを指定
- DataSetのIsProtected項目はそのまま表示しないので、VisibleプロパティにFalseを指定
- (3)の列を参照して、内容がTrueの時には「○」を表示するようにFomulaプロパティに指定。Fomulaプロパティに記述されている「RC5」指定は、同一行の5カラム目(指定値は「0」から始まるのでColumns.Get(4)列のこと)を表しています
- IsFollowing項目の内容がTrueの時には「○」を表示するようにFomulaプロパティを設定では、今までと異なる指定方法「RC[-1]」を採用。これは該当列の1つ前の列を表しています
OnPreRenderメソッドでの処理
OnPreRenderメソッドは、イベントの処理がすべて終わってから呼び出されるサブプロシージャで、ここに図形の描画を設定することで、一覧作成後に常に画像処理が行えます。
Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs) '数式の再計算を行います。 Me.FpSpread1.ActiveSheetView.Recalculate() '画像を表示します Call SetImage() MyBase.OnPreRender(e) End Sub Private Sub SetImage() Dim ds As DataSet = CType(Me.FpSpread1.ActiveSheetView.DataSource, DataSet) With Me.FpSpread1.ActiveSheetView If ds IsNot Nothing Then For rowIndex As Integer = .TopRow To .TopRow + .PageSize - 1 If rowIndex > .RowCount - 1 Then Exit For End If .Cells(rowIndex, 1).CellType = CreateImageFile(ds.Tables(0).Rows(rowIndex)) Next End If End With End Sub Private Function CreateImageFile(ByVal row As DataRow) As FarPoint.Web.Spread.ImageCellType Dim img As Byte() = CType(row.Item("ProfileImage"), Byte()) Dim fileName As String = row.Item("ID").ToString Dim imgfileLogPath As String = "image\" & fileName & ".jpg" Dim imgFilePhyPath As String = System.IO.Path.Combine(Server.MapPath("."), imgfileLogPath) Using imgfile As New System.IO.FileStream(imgFilePhyPath, IO.FileMode.Create) imgfile.Write(img, 0, img.Length) imgfile.Close() End Using Return New FarPoint.Web.Spread.ImageCellType(imgfileLogPath) End Function
- OnPreRenderメソッドからSetImageプロシージャを呼び出し、継承元のOnPreRenderメソッドを呼び出して、本来のPreRender処理を継続します。
- SetImageプロシージャでは、TopRowプロパティとPageSizeプロパティを使って、現在表示している行に対してbyte配列に格納されている画像ファイルを表示します。
- byte配列から直接画像を表示する機能はないので、CreateImageFile関数でbyte配列の内容をサーバ側のimageフォルダに出力し、そのファイル名をセルに渡します。
今回のサンプルはbyte配列からの出力例としたかったため、Twitterから取得した画像ファイルのURLから画像データを取り出し、それをbyte配列に格納して利用しています。しかし、画像ファイルのURLが分かっているのであれば、CreateImageFile関数は次のようなコードで十分です。
Private Function CreateImageFile(ByVal row As DataRow) As FarPoint.Web.Spread.ImageCellType Return New FarPoint.Web.Spread.ImageCellType(row.Item("ProfileImageUrl").ToString) End Function
デザイナを使ってデザインする
サンプル「CZ0910FollowerType2」でコードを明記して指定したデザインは、SPREAD for .NETのデザイナを利用して実現することもできます。デザイナを使えば.aspxの中にプロパティとして記述され、IDEでも一部を除いて表示フォーマットと同じ見た目で表示できます。サンプル「CZ0910FollowerType3」では、デザイナを使った設定にしています。
シートの設定
プロパティウィンドウで、SPREAD for .NETのSheetsプロパティにあるボタンをクリックすると、SheetViewコレクションエディタが起動します。次のプロパティを設定します。
AllowUserFormula | False |
AutoGenerateColumn | False |
ColumnCount | 9 |
DataAutoCellTypes | False |
OperationMode | ReadOnly |
ReferenceStyle | R1C1 |
列の設定
列の設定はSPREADデザイナからサイドメニューの「セル」を選びます。
「セル」は、列ヘッダをクリックして列を選択すれば列の設定プロパティ、行ヘッダをクリックして行を選択すれば行のプロパティ、セルを範囲指定すればセルのプロパティが設定できます。
また、Formulaプロパティに数式を設定するときも、数式エディタを使えば数式の正当性がチェックできるため、修正と実行を繰り返して数式を探る必要がなくなります。
SheetViewコレクションエディタからはシートスキンエディタも表示可能なので、スキンを切り替えながら好みのデザインを探せるので便利です。
コードの追加
型付きデータセットをDataSourceプロパティに指定してあれば、SPREADデザイナの中でDataFieldプロパティを設定できますが、今回のサンプル「CZ0910FollowerType3」は型付きデータセットではないため、ページロードで設定する必要がありますが、サンプル「CZ0910FollowerType2」よりもコード量は少なくなっています。
また、OnPreRenderイベントにてサンプル「CZ0910FollowerType2」と同様に、再計算と画像表示のコードの記述が必要です。
Private Sub Me_Load() 'スタイル設定用CSSを自動生成して使用する Me.FpSpread1.RenderCSSClass = True '行高/列幅を変更できないようにする Me.FpSpread1.ActiveSheetView.RowHeader.Rows.Default.Resizable = False Me.FpSpread1.ActiveSheetView.ColumnHeader.Columns.Default.Resizable = False '列の定義を行う With block 'ID列は非表示にする Me.FpSpread1.ActiveSheetView.Columns(0).DataField = "ID" Me.FpSpread1.ActiveSheetView.Columns(0).Visible = False '名前列の設定を行う Me.FpSpread1.ActiveSheetView.Columns(2).DataField = "Name" 'ID名列の設定を行う Me.FpSpread1.ActiveSheetView.Columns(3).DataField = "ScreenName" 'プロテクション列は非表示にする Me.FpSpread1.ActiveSheetView.Columns(4).DataField = "IsProtected" Me.FpSpread1.ActiveSheetView.Columns(4).Visible = False 'フォロー列は非表示にする Me.FpSpread1.ActiveSheetView.Columns(6).DataField = "IsFollowing" Me.FpSpread1.ActiveSheetView.Columns(6).Visible = False '最新の発言列の設定を行う Me.FpSpread1.ActiveSheetView.Columns(8).DataField = "StatusText" End With End Sub
.NET標準のRepeaterコントロールを使った場合、HTMLで作成した1行分の表示を確認するのにも、実行する必要があります。多少のコーディングは必要ですがSPREADデザイナを使う事で実行せずにデザインを確認しながら見た目を調整できるデザイナの存在は開発の現場では“心強い”のひとことにつきます。
まとめ
SPREAD for .NET Web Forms Ed.は、HTMLやCSSに詳しくない人でもSPREADエディタを使って綺麗な一覧表を作成できます。また、編集中でもデザインが確認できるのも便利です。
HTMLにはtableタグがあるため、Webアプリケーションで一覧表は簡単に作れそうですが、さまざまな要件を満たし、デザイン的にも使いやすいものを作ろうとすると一気に難易度が上がります。この上がった難易度を、また強制的に下げてくれるのがSPREAD for .NET Web Forms Ed.と言えるでしょう。