WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

WPF で Chart を表示

by WebSurfer 2022年2月8日 12:33

ASP.NET Web アプリで Chart を使う方法を先の記事「Chart (ASP.NET Web Forms 用)」や「MVC で Chart を利用する方法」に書きましたが、それらに表示した棒グラフを同様に Chart を使って WPF アプリで表示する方法を書きます。

WPF アプリに Chart 表示

この記事でプロジェクトの作成に使ったのは Visual Studio Community 2022 のテンプレート「WPF アプリ (.NET Framework)」で、フレームワークは .NET Framework 4.8 です。

プロジェクトを作成したら、ソリューションエクスプローラーの「参照」を左クリック ⇒[参照の追加(R)...]をクリックして表示される「参照マネージャー」」ダイアログで以下の項目を参照に追加します。

  • WindowsFormIntegration
  • System.Windows.Forms
  • System.Windows.Forms.DataVisualization

上の 2 つが WPF アプリで Windows Forms 用のコントロールを使うために必要なもの、最後のものが Chart コントロールを使うためのものです。

次に、自動生成された MainWindow.xaml の XAML のコードに以下の画像の赤枠のコードを追加します。赤枠部分に Windows Froms 用のコントロール(この記事の例では Chart)を配置することができます。

XAML

Microsoft のドキュメント「チュートリアル: WPF での XAML を使用した Windows フォーム コントロールのホスト」のように XAML 上で Windows Forms 用コントロールを配置することができますが、この記事では MainWindow.xaml.cs で動的に Chart コントロールを作って配置することにします。

MainWindow.xaml.cs のコードは以下の通りです。これを実行した結果がこの記事の一番上の画像です。

using System.Windows;
using System.Data;
using System.Windows.Forms.DataVisualization.Charting;
using System.Data.SqlClient;

namespace WpfChart
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly Chart chart;

        public MainWindow()
        {
            InitializeComponent();

            this.chart = new Chart
            {
                Name = "chart1",
                Width = 600,
                DataSource = CreateDataTable().DefaultView
            };

            this.windowsFormsHost.Child = this.chart;

            Legend legend = new Legend()
            {
                DockedToChartArea = "ChartArea1",
                IsDockedInsideChartArea = false,
                Name = "Legend1"
            };

            chart.Legends.Add(legend);

            Series series = new Series()
            {
                Name = "三吉",
                ChartType = SeriesChartType.StackedColumn,
                CustomProperties = "DrawingStyle=Cylinder",
                IsValueShownAsLabel = true,
                Label = "#PERCENT{P1}",
                Legend = "Legend1",
                XValueMember = "Month",
                YValueMembers = "三吉"
            };
            chart.Series.Add(series);

            series = new Series()
            {
                Name = "春日",
                ChartType = SeriesChartType.StackedColumn,
                CustomProperties = "DrawingStyle=Cylinder",
                IsValueShownAsLabel = true,
                Label = "#PERCENT{P1}",
                Legend = "Legend1",
                XValueMember = "Month",
                YValueMembers = "春日"
            };
            chart.Series.Add(series);

            series = new Series()
            {
                Name = "東雲",
                ChartType = SeriesChartType.StackedColumn,
                CustomProperties = "DrawingStyle=Cylinder",
                IsValueShownAsLabel = true,
                Label = "#PERCENT{P1}",
                Legend = "Legend1",
                XValueMember = "Month",
                YValueMembers = "東雲"
            };
            chart.Series.Add(series);

            series = new Series()
            {
                Name = "府中",
                ChartType = SeriesChartType.StackedColumn,
                CustomProperties = "DrawingStyle=Cylinder",
                IsValueShownAsLabel = true,
                Label = "#PERCENT{P1}",
                Legend = "Legend1",
                XValueMember = "Month",
                YValueMembers = "府中"
            };
            chart.Series.Add(series);

            series = new Series()
            {
                Name = "広島",
                ChartType = SeriesChartType.StackedColumn,
                CustomProperties = "DrawingStyle=Cylinder",
                IsValueShownAsLabel = true,
                Label = "#PERCENT{P1}",
                Legend = "Legend1",
                XValueMember = "Month",
                YValueMembers = "広島"
            };
            chart.Series.Add(series);

            ChartArea chartArea = new ChartArea()
            {
                Name = "ChartArea1",
                AxisY = new Axis() { Title = "売上高" },
                AxisX = new Axis() { Title = "売上月" }
            };
            chart.ChartAreas.Add(chartArea);
        }

        private DataTable CreateDataTable()
        {
            string connString = @"・・・接続文字列・・・";
            string selectQuery = @"SELECT Month, 
                SUM(CASE WHEN Name = N'三吉' THEN Sales ELSE 0 END) AS 三吉,
                SUM(CASE WHEN Name = N'春日' THEN Sales ELSE 0 END) AS 春日,
                SUM(CASE WHEN Name = N'東雲' THEN Sales ELSE 0 END) AS 東雲,
                SUM(CASE WHEN Name = N'府中' THEN Sales ELSE 0 END) AS 府中,
                SUM(CASE WHEN Name = N'広島' THEN Sales ELSE 0 END) AS 広島
                FROM Shop GROUP BY Month";

            using (var connection = new SqlConnection(connString))
            {
                using (var command = new SqlCommand(selectQuery, connection))
                {
                    var adapter = new SqlDataAdapter(command);
                    var table = new DataTable();
                    adapter.Fill(table);
                    return table;
                }
            }
        }
    }
}

Tags: ,

.NET Framework

Windows Forms 用 Chart Samples

by WebSurfer 2021年11月30日 14:28

Chart Samples は Microsoft のサイトから Windows Forms 用と ASP.NET Web Forms 用の両方を入手できたのですが、そのページは現在リンク切れとなっており復活しそうもありません。Windows Forms アプリ用だけは別の入手先を見つけましたので、それを以下に書いておきます。

Windows Forms 用 Chart Samples

Windows Forms 用 Chart Samples は 2021/11/30 現在以下の GitHub のページからダウンロードできます。

Microsoft Chart for Windows Forms Samples Environment

上のページの右の方にある Latest というリンクをクリッ��するとダウンロードページに遷移しますので、そこで[Source code (zip)]をクリックすれば Samples-Environments-for-Microsoft-Chart-Controls-1.0.1.zip という名前の .zip ファイルがダウンロードされます。

ダウンロードした .zip ファイル

その zip ファイルの中に src というフォルダがあってそれに完全な Windows Forms アプリのソリューションとしてサンプルが含まれています。

それを適当なフォルダに解凍し、Visual Studio で WinFormsChartSamples.sln を開いて実行すれば、基本の解説、いろいろなタイプのサンプルのデモ、それを作るための C# および VB.NET サンプルコード等が満載の Windows Forms アプリが動くはずです。それがこの記事の一番上の画像です。

GitHub のページには "This is a backup of the Microsoft Chart for Windows Forms Samples Environment (Microsoft Chart Controls for Microsoft .NET Framework 3.5) ..." という記述がありますが、Visual Studio 2022 でソリューションを開いて[対象のフレームワーク(G)]みると .NET Framework 4 となってました。(3.5 というのは間違い?)

なお、ビルドする際、プロジェクトルート直下の MainForm.resx と Utilities\SampleMain フォルダの MainForm.resx に対して以下のエラーが出るかもしれません。

"ファイル MainForm.resx を処理できませんでした。インターネットまたは制限付きゾーン内にあるか、ファイルに Web のマークがあるためです。これらのファイルを処理するには、Web のマークを削除してください"

その場合は、エクスプローラーで対象のファイルのプロパティを開き、下の画像の赤枠で示したセキュリティの部分の[許可する(K)]にチェックを入れて[OK]をクリックすれば解決するはずです。

MainForm.resx のプロパティ

Microsoft のサイトからサンプルを入手した場合の設定方法はなどは先の記事は「Chart Samples」に書きました。今となっては役に立たなかもしれませんが、復活するかもしれないので記事は残しておきます。

Tags: , ,

.NET Framework

MVC で Chart を利用する方法

by WebSurfer 2018年5月23日 16:51

ASP.NET Web Forms アプリ用のサーバーコントロールである Chart を MVC アプリで利用する方法を書きます。

MVC アプリで Chart 利用

一般的に、Web Forms 用のサーバーコントロールは、MVC でも ViewState とポストバックを使わない範囲であれば利用できます。

Chart の場合、要求を受けてグラフの画像ファイルを生成するという操作には ViewState とポストバックは不要ですので、MVC でも利用できます。

問題は Chart が生成した画像ファイルを、どのようにブラウザが取得して表示できるかということです。

ASP.NET Web Forms アプリの場合、Chart が生成した画像ファイルはサーバーの c:\TempImageFiles フォルダに一時保存されます。そして、.aspx ページ上で Chart を配置した位置に img 要素がレンダリングされ、その src 属性に画像ファイルを取得するための HTTP ハンドラ設定されます。

ブラウザがページを受信すると、ブラウザは img 要素の src 属性に設定された HTTP ハンドラをサーバーに要求します。要求を受けたサーバーは HTTP ハンドラを使って一時保存された画像ファイルを取得してブラウザに送信し、ブラウザは受信した画像を img 要素の位置に表示するという仕組みになっています。詳しくは、先の記事「Chart (ASP.NET Web Forms 用)」を見てください。

MVC アプリでも .aspx 形式の View を使う場合は Web Forms アプリと同等なことができると思いますが(未検証・未確認です)、最近の主流らしい Razor 形式の View の場合は img 要素のレンダリングが問題です。

ではどうするかと言うと、Web Forms アプリのような HTTP ハンドラは利用せず、Controller のアクションメソッドで画像をダウンロードするようにし、img 要素は自分で View に書いて、その src 属性にアクションメソッドの url を設定してやります。

アクションメソッドでは、動的に Chart を生成し、Chart.SaveImage メソッドを使って画像データを MemoryStream に保存し、Controller.File メソッド (Byte[], String) で画像のバイト列を応答ストリームに書き出すようにします。

先の記事「Chart」と同じ SQL Server のデータから、同じグラフ画像を生成してダウンロードさせるアクションメソッドのサンプルを以下に書いておきます。このアクションメソッドの url を img 要素の src 属性に設定した結果が上の画像です。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using AdventureWorksLT;
using Mvc5App.Extensions;
using System.ComponentModel.DataAnnotations;

// Chart を利用するコードのため以下を追加する
using System.Web.UI.DataVisualization.Charting;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;

namespace Mvc5App.Controllers
{
  public class HomeController : Controller
  {        
    public ActionResult Chart()
    {
      SqlDataSource sds = new SqlDataSource()
      {
        ID = "SqlDataSource1",
        ConnectionString = @"接続文字列",
        SelectCommand = @"SELECT 
        Month, 
        SUM(CASE WHEN Name=N'三吉' THEN Sales ELSE 0 END) AS 三吉, 
        SUM(CASE WHEN Name=N'春日' THEN Sales ELSE 0 END) AS 春日, 
        SUM(CASE WHEN Name=N'東雲' THEN Sales ELSE 0 END) AS 東雲, 
        SUM(CASE WHEN Name=N'府中' THEN Sales ELSE 0 END) AS 府中, 
        SUM(CASE WHEN Name=N'広島' THEN Sales ELSE 0 END) AS 広島 
        FROM Shop GROUP BY Month"
      };

      Chart chart = new Chart()
      {
        ID = "Chart1",
        Width = 600,
        DataSource = sds.Select(DataSourceSelectArguments.Empty)
                
        // 注:以下のようにするとエラー
        // DataSourceID = "SqlDataSource1"
      };

      Legend legend = new Legend()
      {
        DockedToChartArea = "ChartArea1",
        IsDockedInsideChartArea = false,
        Name = "Legend1"
      };
      chart.Legends.Add(legend);

      Series series = new Series()
      {
        Name = "三吉",
        ChartType = SeriesChartType.StackedColumn,
        CustomProperties = "DrawingStyle=Cylinder",
        IsValueShownAsLabel = true,
        Label = "#PERCENT{P1}",
        Legend = "Legend1",
        XValueMember = "Month",
        YValueMembers = "三吉"
      };
      chart.Series.Add(series);

      series = new Series()
      {
        Name = "春日",
        ChartType = SeriesChartType.StackedColumn,
        CustomProperties = "DrawingStyle=Cylinder",
        IsValueShownAsLabel = true,
        Label = "#PERCENT{P1}",
        Legend = "Legend1",
        XValueMember = "Month",
        YValueMembers = "春日"
      };
      chart.Series.Add(series);

      series = new Series()
      {
        Name = "東雲",
        ChartType = SeriesChartType.StackedColumn,
        CustomProperties = "DrawingStyle=Cylinder",
        IsValueShownAsLabel = true,
        Label = "#PERCENT{P1}",
        Legend = "Legend1",
        XValueMember = "Month",
        YValueMembers = "東雲"
      };
      chart.Series.Add(series);

      series = new Series()
      {
        Name = "府中",
        ChartType = SeriesChartType.StackedColumn,
        CustomProperties = "DrawingStyle=Cylinder",
        IsValueShownAsLabel = true,
        Label = "#PERCENT{P1}",
        Legend = "Legend1",
        XValueMember = "Month",
        YValueMembers = "府中"
      };
      chart.Series.Add(series);

      series = new Series()
      {
        Name = "広島",
        ChartType = SeriesChartType.StackedColumn,
        CustomProperties = "DrawingStyle=Cylinder",
        IsValueShownAsLabel = true,
        Label = "#PERCENT{P1}",
        Legend = "Legend1",
        XValueMember = "Month",
        YValueMembers = "広島"
      };
      chart.Series.Add(series);

      ChartArea chartArea = new ChartArea()
      {
        Name = "ChartArea1",
        AxisY = new Axis() { Title = "売上高" },
        AxisX = new Axis() { Title = "売上月" }
      };
      chart.ChartAreas.Add(chartArea);

      using (var ms = new MemoryStream())
      {
        chart.SaveImage(ms, ChartImageFormat.Png);

        // キャッシュを許可するか否か、許可する場合は有効期限を
        // 指定しておくべき。
        // 以下のコードはキャッシュを許可しない場合の例。応答ヘ
        // ッダーは次のようになる。
        //    Cache-Control: no-cache
        //    Pragma: no-cache
        //    Expires: -1
        Response.Cache.SetCacheability(HttpCacheability.NoCache);
        Response.Cache.SetExpires(DateTime.Now.ToUniversalTime());
        Response.Cache.SetMaxAge(new TimeSpan(0, 0, 0, 0));

        return File(ms.ToArray(), "image/png");

        // File の第 3 引数を以下のように設定すると応答ヘッダに
        // Content-Disposition: attachment; filename=chart.png
        // が含まれるようになる。
        // return File(ms.ToArray(), "image/png", "chart.png");
      }
    }
  }
}

先の記事「Chart (ASP.NET Web Forms 用)」で書きました Web Forms アプリでは、Visual Studio によって自動的に web.config に HTTP ハンドラの定義や appSettings の設定が追加されますが、それらは一切不要です。

ただし、System.Web.DataVisualization の参照への追加が必要です。using 句を追加するだけではダメです。

参照の追加

Tags:

MVC

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar