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

前のセクションのすべての例で使用した C1OlapPage コントロールは、すべての必要な UI を含み、コードをほとんどまたはまったく必要としません。このセクションで作成する OLAP アプリケーションでは、C1OlapPage を使用しません。代わりに、C1OlapGridC1OlapChart、およびいくつかの標準 .NET コントロールを使用して、完全なカスタム UI を作成します。

このアプリケーションの完全なソースコードは、C1Olap でインストールされる "CustomUI" のサンプルに含まれています。

次の図は、アプリケーションをデザインビュー内に示しています。

パネルがフォームの上端にドッキングされており、アプリケーションのタイトルを示しています。垂直方向のツールストリップコントロールがフォームの右側にドッキングされており、3つのボタンのグループを備えています。上端のグループでは、定義済みの3つのビュー、営業担当者別、製品別、国別の売上高から1つを選択できます。次のグループでは、データに対して製品価格に基づいてフィルタ(高価、中程度、安価)を適用できます。最後のボタンは、レポート作成機能を備えています。

フォームの残りの領域のうち、左側には C1OlapGrid、右側には C1OlapChart を示す分割コンテナが存在します。これらは、現在選択されているビューを表示するコントロールです。

フォームは、レポートの生成に使用する C1OlapPrintDocument コンポーネントも含みます。このコンポーネントは、フォームの下のトレイ領域だけに表示され、上の図には表示されません。C1OlapPrintDocument は、設計時に設定されたその OlapGrid プロパティと OlapChart プロパティにより、ページ上の OLAP コントロールに接続されます。

さらに、フォームには C1OlapPanel コントロールがあります。これは、Visible プロパティが false に設定されているため、ユーザーはコントロールを見ることができません。この不可視のコントロールは、グリッドとチャートのデータソースとして使用され、また、データのフィルタ処理と要約を処理します。グリッドとグラフの両方で、その DataSource プロパティが C1OlapPanel に設定されています。

すべてのコントロールが揃ったら、それらをすべて結合するコードを追加して、アプリケーションを動作させます。

最初に、データを取得し、C1OlapPanel に割り当てます。

コード
コードのコピー
private void Form1_Load(object sender, EventArgs e)
{
    // データを読み込みます
    var da = new OleDbDataAdapter("select * from Invoices", 
      GetConnectionString());
    var dt = new DataTable();
    da.Fill(dt);
 
    // アプリケーションを動作させる C1OlapPanel にデータを割り当てます
    this.c1OlapPanel1.DataSource = dt;
 
    // どの製品も SalesPerson ビューで開始します
    _btnSalesperson.PerformClick();
    _btnAllPrices.PerformClick();
}

コードは、DataAdapter を使用して NorthWind データベースからデータを取得し、結果の DataTable を C1OlapPanel.DataSource プロパティに割り当てます。次にコードは、PerformClick メソッドを使用して、2つのボタンのクリックをシミュレーションし、現在のビューとフィルタを初期化します。

現在のビューを選択するボタンのイベントハンドラは、次のようになります。

コード
コードのコピー
void _btnSalesperson_Click(object sender, EventArgs e)
{
    CheckButton(sender);
    BuildView("Salesperson");
}
void _btnProduct_Click(object sender, EventArgs e)
{
    CheckButton(sender);
    BuildView("ProductName");
}
void _btnCountry_Click(object sender, EventArgs e)
{
    CheckButton(sender);
    BuildView("Country");
}

すべてのハンドラは、下記に示す BuildView ヘルパーメソッドを使用します。

コード
コードのコピー
// ボタンがクリックされた後にビューをリビルドします
void BuildView(string fieldName)
{
    // olap エンジンを取得します
    var olap = c1OlapPanel1.OlapEngine;
 
    // 完了するまで更新を停止します
    olap.BeginUpdate();
 
    // 注文日付の書式を設定して、年別にグループ化します
    var f = olap.Fields["OrderDate"];
    f.Format = "yyyy";
 
    // すべてのフィールドをクリアします
    olap.RowFields.Clear();
    olap.ColumnFields.Clear();
    olap.ValueFields.Clear();
 
    // ビューを構築します
    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 が出力テーブルを更新します。

アプリケーションを実行する前に、フィルタ処理を実装するコードを見ておきましょう。イベントハンドラは次のようになります。

コード
コードのコピー
void _btnExpensive_Click(object sender, EventArgs e)
{
    CheckButton(sender);
    SetPriceFilter("Expensive Products (price > $50)", 50, double.MaxValue);
}
void _btnModerate_Click(object sender, EventArgs e)
{
    CheckButton(sender);
    SetPriceFilter("Moderately Priced Products ($20 < price < $50)", 20, 50);
}
void _btnInexpensive_Click(object sender, EventArgs e)
{
    CheckButton(sender);
    SetPriceFilter("Inexpensive Products (price < $20)", 0, 20);
}
void _btnAllProducts_Click(object sender, EventArgs e)
{
    CheckButton(sender);
    SetPriceFilter("All Products", 0, double.MaxValue);
}

すべてのハンドラは、下記に示す SetPriceFilter ヘルパーメソッドを使用します。

コード
コードのコピー
// フィルタを製品価格に適用します
void SetPriceFilter(string footerText, double min, double max)
{
    // olap エンジンを取得します
    var olap = c1OlapPanel1.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();
 
    // レポートのフッターを設定します
    c1OlapPrintDocument1.FooterText = footerText;
}

前のように、コードが C1OlapEngine に対する参照を取得して、直ちに BeginUpdate を呼び出します。

次に、データのフィルタ処理に使用される[UnitPrice]フィールドに対する参照を取得します。[UnitPrice]フィールドがエンジンの FilterFields コレクションに追加され、フィルタが現在のビューに適用されます。

この細部の処理は重要です。フィールドがどのビューコレクション(RowFieldsValueFieldsFilterFields)にも含まれない場合、そのフィールドがビューに含まれることはなくなり、また、その Filter プロパティによる一切の影響を受けなくなります。

コードは、ビューに含まれる必要のある値の範囲を指定する2つの条件を設定することにより、[UnitPrice]フィールドの Filter プロパティの設定に進みます。範囲は、"min" パラメータと "max" パラメータによって定義されます。条件を使用する代わりに、包める値のリストを提供することもできます。通常、数値を扱う場合には条件の方が便利であり、文字列値や列挙ではリストの方が便利です。

最後にコードは、EndUpdate を呼び出し、C1OlapPrintDocument の FooterText プロパティを設定します。これにより、フッターが任意のレポートで自動的に表示されるようになります。

上記のメソッドは、以下に示す CheckButton と呼ぶ別のヘルパーを使用します。

コード
コードのコピー
// どのボタンが押されたかを示します
void CheckButton(object pressedButton)
{
    var btn = pressedButton as ToolStripButton;
    btn.Checked = true;
 
    var items = btn.Owner.Items;
    var index = items.IndexOf(btn);
    for (int i = index + 1; i < items.Count; i++)
    {
        if (!(items[i] is ToolStripButton)) break;
        ((ToolStripButton)items[i]).Checked = false;
    }
    for (int i = index - 1; i > 0 && !(items[i] is ToolStripSeparator); i--)
    {
        if (!(items[i] is ToolStripButton)) break;
        ((ToolStripButton)items[i]).Checked = false;
    }
}

このメソッドにより、ツールストリップのボタンがラジオボタンのように動作します。ボタンの1つをオンにすると、同じグループの他のすべてのボタンがオフになります。

これで、アプリケーションを使用する準備がほぼ整いました。ここで次のように実行して、アプリケーションのさまざまなビューやフィルタ処理機能をテストできます。

このビューでは、すべての製品の売上高が年別および国別にグループ化して表示されます。300,000 ドル弱の値がチャートにどのように表示されているか注目してください。

[$$$ 高額]ボタンをクリックすると、フィルタが適用されて、直ちにビューが変化します。今度は、80,000 ドル弱の値がチャートにどのように表示されているか注目してください。高額の値が売上高の3分の1を占めています。

アプリケーションを構成するコードのうち最後に残っているのは、レポート作成です。ユーザーは、あらかじめ OlapGrid からデータをコピーしておき、それを Excel に貼り付け、結果を印刷または保存することができます。これをもっと簡単に行うために、アプリケーション内から直接 PDF ファイルを印刷または作成できるようにします。

これを行うには、クリックを処理するためのコードを[レポート]ボタンに追加します。このコードは非常にシンプルです。

void _btnReport_Click(object sender, EventArgs e)
{
    using (var dlg = new C1.Win.Olap.C1OlapPrintPreviewDialog())
    {
        dlg.Document = c1OlapPrintDocument1;
        dlg.StartPosition = FormStartPosition.Manual;
        dlg.Bounds = this.Bounds;
        dlg.ShowDialog(this);
    }
}

.NET で印刷を実行したことがある場合、これは見慣れたコードです。これは、最初に C1OlapPrintPreviewDialog のインスタンス化を行います。標準の PrintPreviewDialog に似たクラスですが、PDF へのエクスポート機能などの拡張機能をいくつか備えています。

コードでは、ダイアログボックスの Document プロパティを設定し、その位置を初期化し、ダイアログボックスを表示します。アプリケーションを実行し、[レポート]ボタンをクリックすると、次のようなダイアログボックスが表示されます。

このダイアログボックスから、ユーザーは、ページレイアウトを変更したり、ドキュメントを PDF に印刷またはエクスポートしたりできます。