前のセクションのすべての例で使用した C1OlapPage コントロールは、すべての必要な UI を含み、コードをほとんどまたはまったく必要としません。このセクションで作成する OLAP アプリケーションでは、C1OlapPage を使用しません。代わりに、C1OlapGrid、C1OlapChart、およびいくつかの標準 Silverlight コントロールを使用して、完全なカスタム UI を作成します。
このアプリケーションの完全なソースコードは、OLAP for Silverlight and WPF でインストールされる "CustomUI" のサンプルに含まれています。
次の図は、アプリケーションをデザインビュー内に示しています。
グリッドレイアウトは、2行4列で構成されています。上端の行全体を満たす TextBlock があり、アプリケーションのタイトルを示しています。左端の列に垂直方向の StackPanel コントロールがあり、2つのグループのボタンが含まれています。上端のグループでは、定義済みの3つのビュー、営業担当者別、製品別、国別の売上高から1つを選択できます。次のグループでは、データに対して製品価格に基づいてフィルタ(高価、中程度、安価)を適用できます。
残りの列には、それぞれ空の C1OlapGrid、GridSplitter、および空の C1OlapChart があります。これらは、現在選択されているビューを表示するコントロールです。
すべてのコントロールが揃ったら、それらをすべて結合するコードを追加して、アプリケーションを動作させます。
コードで C1OlapPanel を宣言します。前の例では、エンドユーザーから C1OlapPanel パーツが見えます。しかし、このサンプルでは、それを背後で使用するため、ユーザーからは見えなくなります。この不可視のコントロールは、グリッドとチャートのデータソースとして使用され、また、データのフィルタ処理と要約を処理します。グリッドとチャートの両方で、その DataSource プロパティが C1OlapPanel に設定されています。
C1OlapPanel _olapPanel = new C1OlapPanel();
下記のコードは、最初に Northwind データを XML データスキーマファイルから読み込みます。Data for Silverlight を使用します。これは、データを読み込むために、よく知られた DataSet オブジェクトと DataTable オブジェクトを提供します。また、Zip for Silverlight をクライアント上で使用して、zip 形式で圧縮された XML ファイルをアンパックします。その結果として得られた DataTable を C1OlapPanel.DataSource プロパティに割り当てます。また、C1OlapPanel コントロールを C1OlapGrid に、C1OlapChart コントロールを DataSource プロパティに割り当てます。最後に、現在のビューとフィルタを初期化する2つのボタンのクリックをシミュレートします。
C# |
コードのコピー
|
---|---|
public MainPage() { InitializeComponent(); var ds = new DataSet(); var asm = Assembly.GetExecutingAssembly(); using (var s = asm.GetManifestResourceStream("CustomUI.Resources.nwind.zip")) { var zip = new C1ZipFile(s); using (var zr = zip.Entries[0].OpenReader()) { // データを読み込みます ds.ReadXml(zr); } } // olap グリッド/チャートをパネルに連結します _olapChart.DataSource = _olapPanel; _olapGrid.DataSource = _olapPanel; // olap パネルをデータに連結します _olapPanel.DataSource = ds.Tables[0].DefaultView; // どの製品も SalesPerson ビューで開始します _btnSalesperson_Click(this, null); _btnAllPrices_Click(this, null); } 現在のビューを選択するボタンのイベントハンドラは、次のようになります。 void _btnSalesperson_Click(object sender, RoutedEventArgs e) { BuildView("SalesPerson"); } void _btnProduct_Click(object sender, RoutedEventArgs e) { BuildView("ProductName"); } void _btnCountry_Click(object sender, RoutedEventArgs e) { BuildView("Country"); } All handlers use a BuildView helper method given below: // ボタンがクリックされた後、ビューをリビルドします void BuildView(string fieldName) { // olap エンジンを取得します var olap = _olapPanel.OlapEngine; // 完了するまで更新を停止します olap.BeginUpdate(); // すべてのフィールドをクリアします olap.RowFields.Clear(); olap.ColumnFields.Clear(); olap.ValueFields.Clear(); // 注文日付の書式を設定して、年別にグループ化します var f = olap.Fields["OrderDate"]; f.Format = "yyyy"; // ビューを構築します olap.ColumnFields.Add("OrderDate"); olap.RowFields.Add(fieldName); olap.ValueFields.Add("ExtendedPrice"); // 更新を復元します olap.EndUpdate(); } |
BuildView メソッドは、C1OlapPanel によって提供される C1OlapEngine オブジェクトへの参照を取得し、直ちに BeginUpdate メソッドを呼び出して、新しいビューが完全に定義されるまで更新を停止します。これは、パフォーマンスの向上のために実行されます。
次に、コードで[OrderDate]フィールドの書式を "yyyy" に設定して売上高を年別にグループ化し、エンジンの RowFields、ColumnFields、および ValueFields コレクションをクリアし、さらに表示するフィールドを追加することによってビューをリビルドします。呼び出し元によって渡される "fieldName" パラメータには、この例のビューの間で変化するフィールドの名前だけが含まれます。
これがすべて完了すると、コードが EndUpdate を呼び出して、C1OlapPanel が出力テーブルを更新します。
アプリケーションを実行する前に、フィルタ処理を実装するコードを見ておきましょう。イベントハンドラは次のようになります。
C# |
コードのコピー
|
---|---|
void _btnExpensive_Click(object sender, RoutedEventArgs e) { SetPriceFilter("Expensive Products (price > $50)", 50, double.MaxValue); } void _btnModerate_Click(object sender, RoutedEventArgs e) { SetPriceFilter("Moderately Priced Products ($20 < price < $50)", 20, 50); } void _btnInexpensive_Click(object sender, RoutedEventArgs e) { SetPriceFilter("Inexpensive Products (price < $20)", 0, 20); } void _btnAllPrices_Click(object sender, RoutedEventArgs e) { SetPriceFilter("All Products", 0, double.MaxValue); } |
すべてのハンドラは、下記に示す SetPriceFilter ヘルパーメソッドを使用します。
C# |
コードのコピー
|
---|---|
// 製品価格にフィルタを適用します void SetPriceFilter(string footerText, double min, double max) { // olap エンジンを取得します var olap = _olapPanel.OlapEngine; // 完了するまで更新を停止します olap.BeginUpdate(); // ビュー内の単価フィールドがアクティブであることを確認します var field = olap.Fields["UnitPrice"]; olap.FilterFields.Add(field); // フィルタをカスタマイズします var filter = field.Filter; filter.Clear(); filter.Condition1.Operator = C1.Olap.ConditionOperator.GreaterThanOrEqualTo; filter.Condition1.Parameter = min; filter.Condition2.Operator = C1.Olap.ConditionOperator.LessThanOrEqualTo; filter.Condition2.Parameter = max; // 更新を復元します olap.EndUpdate(); } |
前のように、コードが C1OlapEngine に対する参照を取得して、直ちに BeginUpdate を呼び出します。
次に、データのフィルタ処理に使用される[UnitPrice]フィールドに対する参照を取得します。[UnitPrice]フィールドがエンジンの FilterFields コレクションに追加され、フィルタが現在のビューに適用されます。
この細部の処理は重要です。フィールドがどのビューコレクション(RowFields、ColumnFields、ValueFields、FilterFields)にも含まれない場合、そのフィールドがビューに含まれることはなくなり、また、ビューはその Filter プロパティによる一切の影響を受けなくなります。
コードは、ビューに含まれる必要のある値の範囲を指定する2つの条件を設定することにより、[UnitPrice]フィールドの Filter プロパティの設定に進みます。範囲は、"min" パラメータと "max" パラメータによって定義されます。条件を使用する代わりに、包める値のリストを提供することもできます。通常、数値を扱う場合には条件の方が便利であり、文字列値や列挙ではリストの方が便利です。
最後に、コードが EndUpdate を呼び出します。
最後に、C1OlapGrid 内の列をソートするときは必ず C1OlapChart を更新します。これにより、データ値が同じ順序で表示されます。
C# |
コードのコピー
|
---|---|
void _olapGrid_SortedColumn(object sender, C1.Silverlight.FlexGrid.CellRangeEventArgs e) { _olapChart.UpdateChart(); } |
これで、アプリケーションを使用する準備が整います。次のように実行して、アプリケーションのさまざまなビューやフィルタ処理機能をテストできます。
このビューでは、すべての製品の売上高が年別および国別にグループ化して表示されます。300,000 ドル弱の値がチャートにどのように表示されているか注目してください。
[$$$ 高額]ボタンをクリックすると、フィルタが適用されて、直ちにビューが変化します。今度は、80,000 ドル弱の値がチャートにどのように表示されているか注目してください。高額の値が売上高の3分の1を占めています。