WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

.NET 6.0 WinForms アプリで Chart

by WebSurfer 4. June 2022 14:44

Visual Studio 2022 で作成する .NET 6.0 の Windows Forms アプリで Chart を使って、先の記事「WPF で Chart を表示」と同じ棒グラフを表示してみました。

.NET 6.0 WinForms アプリに Chart 表示

調べてみると System.Windows.Forms.DataVisualization は .NET Core/.NET ではサポートされてないようです。そこを何とかしようとすると、自力でライブラリに手を加えるなどするしかなさそうですがそれは自分には無理なので、先人が作ってくれたライブラリに頼ることにしました。

で、NuGet を探してみるとこの記事を書いた時点では Maikebing.System.Windows.Forms.DataVisualization と HIC.System.Windows.Forms.DataVisualization という 2 つのパッケージが見つかりました。

ただしいずれも .NET 5.0 用とのこと。一旦はそこで断念したのですが、試しに前者の NuGet パッケージをインストールしてやってみました。その結果が上の画像で、この記事に書いた範囲に限っては一応は期待通りの結果になっています。

詳しく検証はしていませんので .NET Framework 版と同じ機能がサポートされているか、実用上問題ないのか等は分かりませんが、せっかくなのでブログの記事として残しておくことにしました。

プロジェクトの作成に使ったのは Visual Studio Community 2022 のテンプレート「Windows フォームアプリ」で、フレームワークは .NET 6.0 です。

まず Maikebing.System.Windows.Forms.DataVisualization を NuGet からインストールします。この記事を書いた時点では v5.0.1 が最新でしたのでそれをインストールしました。

NuGet パッケージ

後者の Microsoft.Data.SqlClient は SQL Server からデータを取得して DataTable を作成するためのものです。以前は System.Data.SqlClient を使っていたのですが代えてみました。(後述しますが、おかげでトラブりました)

自動生成された Form1.cs のデザイン画面でツールボックスから Button をドラッグ&ドロップし Click イベントのハンドラを生成したら、Form1.cs のコード画面で以下のコードを実装します。先の記事「WPF で Chart を表示」のコードと同じです。これを実行した結果がこの記事の一番上の画像です。

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

namespace WinFormsChart
{
    public partial class Form1 : Form
    {
        private Chart chart;

        public Form1()
        {
            InitializeComponent();

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

            this.Controls.Add(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 (SqlConnection connection = new SqlConnection(connString))
            {
                using (SqlCommand command = new SqlCommand(selectQuery, connection))
                {
                    SqlDataAdapter adapter = new SqlDataAdapter(command);
                    DataTable table = new DataTable();
                    adapter.Fill(table);
                    return table;
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();

            saveFileDialog1.Filter = "BMP形式|*.bmp|JPEG形式|*.jpeg|PNG形式|*.png";
            saveFileDialog1.FilterIndex = 2;
            saveFileDialog1.RestoreDirectory = true;

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                string filename = saveFileDialog1.FileName;
                string ext = Path.GetExtension(filename).ToLower();
                ChartImageFormat format;
                if (ext == ".jpeg")
                {
                    format = ChartImageFormat.Jpeg;
                }
                else if (ext == ".png")
                {
                    format = ChartImageFormat.Png;
                }
                else if (ext == ".bmp")
                {
                    format = ChartImageFormat.Bmp;
                }
                else
                {
                    throw new InvalidOperationException();
                }
                this.chart.SaveImage(filename, format);
            }
        }
    }
}

最後に、この記事の Chart の話とは関係ないことですが、System.Data.SqlClient に代えて Microsoft.Data.SqlClient ���使ってトラブったのでそれを忘れないように書いておきます。

同じ .NET6.0 フレームワークで上と全く同じコードで System.Data.SqlClient の時は何ら問題なかったのに、Microsoft.Data.SqlClient を使うと以下の例外がスローされます。

SqlClient の例外

Microsoft.Data.SqlClient.SqlException A connection was successfully established with the server, but then an error occurred during the login process. (provider: SSL Provider, error: 0 - 信頼されていない機関によって証明書チェーンが発行されました。)

上のエラーメッセージでググってみると Microsoft のドキュメント ログイン フェーズのエラー が見つかって、それには考えられる原因として「SQL Server で TLS 1.2 がサポートされていない」と書いてあります。

確かにその通りで、接続先の SQL Server 2012 のバージョンは 11.0.2100 で TSL 1.2 はサポートしてないです。

別の Microsoft のドキュメント New features in 4.0 によると v4.0 からデフォルトで暗号化を行うよう設定が変わったとのことで、それが影響しているようです。

接続先を LocalDB v13.0.4001 (TLS 1.2 がサポートされている SQL Server 2016 相当)に変更して上の問題は解決できました。

Tags: , ,

CORE

About this blog

2010年5月にこのブログを立ち上げました。その後ブログ2を追加し、ここはプログラミング関係、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  December 2022  >>
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar