OLAP for WPF /Silverlight
カスタムユーザーインタフェースの作成
C1Olap クイックスタート > カスタムユーザーインタフェースの作成

前のセクションのすべての例で使用した C1OlapPage コントロールは、すべての必要な UI を含み、コードをほとんどまたはまったく必要としません。このセクションで作成する OLAP アプリケーションでは、C1OlapPage を使用しません。代わりに、C1OlapGridC1OlapChart、およびいくつかの標準 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" に設定して売上高を年別にグループ化し、エンジンの RowFieldsColumnFields、および 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 コレクションに追加され、フィルタが現在のビューに適用されます。

この細部の処理は重要です。フィールドがどのビューコレクション(RowFieldsColumnFieldsValueFieldsFilterFields)にも含まれない場合、そのフィールドがビューに含まれることはなくなり、また、ビューはその 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を占めています。