WebSurfer's Home

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

DataGridView 新規追加行の未入力検証

by WebSurfer 2022年10月9日 13:25

Windows Forms アプリの GataGridView の新規追加行に未入力のままフォーカスを移動したり[データの保存]ボタンをクリックした時にスローされる NoNullAllowedException に対処する方法を書きます。

NoNullAllowedException

NoNullAllowedException というのは、DataColumn.AllowDBNull プロパティが false に設定されている列に null 値を挿入しようとした場合にスローされる例外です。Visual Studio のデータソース構成ウィザードを使って型付 DataSet / DataTable を作ると、元の DB の列が NULL 不可になっている場合に false に設定されます。

DataGridView 上で当該列を空白のままにしてフォーカスを移動したり[データの保存]ボタンをクリックしたりすると DataTable の当該 Column に null 値を挿入しようとするので NoNullAllowedException がスローされます。

その際、エラーメッセージを表示するダイアログが、上の画像のものとは違って、下の画像のような「DataGridView の既定のエラーダイアログ」であれば、DataGridView.DataError イベントを処理することで対応できます。

DataGridView の既定のエラーダイアログ

具体例は Microsoft のドキュメント「DataGridView.DataError イベント」や「ユーザーがDataGridViewのセルに正しくない値を入力した時に発生するエラーを捕捉する」を見てください。下に載せたサンプルコードにも実装してあります。

しかしながら、DataError イベントをハンドルしても NoNullAllowedException を補足できないケースがあるのが問題です。

その補足できないケースというのは、自分が調べた限りですが、(1) BindingNavigator 上の[新規追加]ボタンを続けて 2 回クリック、(2) 新規追加行に未入力のまま BindingNavigator 上の[最初に移動][前に戻る][データの保存]ボタンをクリックした場合です。(他にもあるかも)

その場合は、この記事の一番上の画像のような、例のおなじみのエラーメッセージのダイアログが表示されます。

これを何とかしようとすると try - catch 句を追加して NoNullAllowedException を補足するということになると思います。

(他にもっとスマートな手段があるかもしれませんが分かりませんでした。DataGridView.RowValidating イベントをハンドルして対応できないかと考えたのですが、上に書いた「補足できないケース」ではイベントが発生しません)

どこに try - catch 句を追加するかですが、データソース構成ウィザードを使って型付 DataSet / DataTable を作り、それをデザイン画面で「データソース」ウィンドウから Form にドラッグ&ドロップして作ったアプリのコードにはその場所がありません。(Program.cs の Application.Run(new Form1()); で try - catch するのはやりすぎと思うので対象外)

そこで考えたのが、BindingNavigator の AddNewItem, DeleteItem, MoveFirstItem, MoveLastItem, MoveNextItem, MoveProviousItem プロパティの設定を以下のように (なし) に変更し(デフォルトでは当該 ToolStripButton が設定されている)、

BindingNavigator の設定変更

AddNewItem, DeleteItem, MoveFirstItem, MoveLastItem, MoveNextItem, MoveProviousItem に設定されていた各 ToolStripButton の Click イベントのハンドラを追加し、

Click イベントのハンドラ設定

その各ハンドラの中で BindingSource の AddNew, RemoveCurrent, MoveFirst, MoveLast, MoveNext, MoveProvious を実行するようにして try - catch 句を使うということです。

BindingNavigation の操作やマウスやキーボードを使っての BindingSource のポジションの変更に伴って BindingNavigator 上の ToolStripButton の Enabled プロパティの true/false の設定を変更する必要がありますが、それは BindingSource.PositionChanged イベントのハンドラで行います。

ただし、ここまでの設定だけでは[データの保存]ボタンをクリックした場合に対応できません。そこは、自動生成されたクリックイベントのハンドラの中の BindingSource.EndEdit(); というコードに try - catch を追加して NoNullAllowedException を補足して対処します。

以下にサンプルコードを書きます。例として、下の画像の SQL Server データベースを使います。

SQL Server データベース

まず、上の Product テーブルのレコード一覧表示・編集を行う Windows Forms + DataGridView アプリを作ります。それは Microsoft のドキュメント「新しいデータ ソースの追加」のように「データソース構成ウィザード」を使って型付 DataSet / DataTable を作り、それをデザイン画面で「データソース」ウィンドウから Form にドラッグ&ドロップすれば、自力ではコードを一行も書くことなく簡単に作成できます。

その後、上に述べたように、自動生成されたコードに手を加えてたのが下のサンプルコードです。

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

namespace WindowsFormsPkUnique
{
    public partial class Form3 : Form
    {
        public Form3()
        {
            InitializeComponent();

            // DataGridView.DataError イベントのハンドラ設定
            this.productDataGridView.DataError += 
                                  ProductDataGridView_DataError;

            // BindingSource.PositionChanged イベントのハンドラ設定
            this.productBindingSource.PositionChanged += 
                                  ProductBindingSource_PositionChanged;
        }

        private void Form3_Load(object sender, EventArgs e)
        {
            this.productTableAdapter.Fill(this.productDataSet.Product);
        }

        // DataGridView.DataError イベントを処理。これで補足できない
        // ケースがあるのが問題
        private void ProductDataGridView_DataError(object sender, 
            DataGridViewDataErrorEventArgs e)
        {
            if (e.Exception != null)
            {
                MessageBox.Show(this,
                    $"Index {e.RowIndex} の行でエラーが発生しました。\n\n" +
                    $"説明: {e.Exception.Message}",

                    "エラーが発生しました",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        // BindingSource の Position の変更に伴って、BindingNavigator の
        // 各ボタンの Enabled プロパティの true/false 設定を変更する
        private void ProductBindingSource_PositionChanged(object sender, 
            EventArgs e)
        {
            int count = productBindingSource.Count;
            int position = productBindingSource.Position;
            if (count <= 1)
            {
                bindingNavigatorMoveFirstItem.Enabled = false;
                bindingNavigatorMovePreviousItem.Enabled = false;
                bindingNavigatorMoveNextItem.Enabled = false;
                bindingNavigatorMoveLastItem.Enabled = false;
                if (count == 0)
                    bindingNavigatorDeleteItem.Enabled = false;
                else
                    bindingNavigatorDeleteItem.Enabled = true;
            }
            else
            {
                bindingNavigatorDeleteItem.Enabled = true;

                if (position == 0)
                {
                    bindingNavigatorMoveFirstItem.Enabled = false;
                    bindingNavigatorMovePreviousItem.Enabled = false;
                    bindingNavigatorMoveNextItem.Enabled = true;
                    bindingNavigatorMoveLastItem.Enabled = true;
                }
                else if (position == count - 1)
                {
                    bindingNavigatorMoveFirstItem.Enabled = true;
                    bindingNavigatorMovePreviousItem.Enabled = true;
                    bindingNavigatorMoveNextItem.Enabled = false;
                    bindingNavigatorMoveLastItem.Enabled = false;
                }
                else
                {
                    bindingNavigatorMoveFirstItem.Enabled = true;
                    bindingNavigatorMovePreviousItem.Enabled = true;
                    bindingNavigatorMoveNextItem.Enabled = true;
                    bindingNavigatorMoveLastItem.Enabled = true;
                }
            }
        }

        // BindingNavigator の[データの保存]ボタンクリックのハンドラ
        private void productBindingNavigatorSaveItem_Click(object sender, 
            EventArgs e)
        {
            this.Validate();            

            try
            {
                // EndEdit を try に含めないと NoNullAllowedException が
                // catch できない
                this.productBindingSource.EndEdit();

                this.tableAdapterManager.UpdateAll(this.productDataSet);
            }
            catch (NoNullAllowedException ex)
            {
                MessageBox.Show(this,
                    ex.Message + "\n\nデータを修正してください。",
                    "「データの保存」ボタン操作エラー",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            catch (SqlException sqlEx)  // オマケの重複チェック
            {
                if (sqlEx.Number == 2601)
                {
                    MessageBox.Show(this,
                        $"Unique 制約違反です。\n\n説明: {sqlEx.Message}",
                        "エラーが発生しました",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    throw;
                }               
            }            
        }

        // BindingNavigator の[最初に移動]ボタンクリックのハンドラ
        private void bindingNavigatorMoveFirstItem_Click(object sender, 
            EventArgs e)
        {
            try
            {
                productBindingSource.MoveFirst();
            }
            catch (NoNullAllowedException ex)
            {
                MessageBox.Show(this,
                    ex.Message + "\n\nデータを修正してください。",
                    "「最初に移動」ボタン操作エラー",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        // BindingNavigator の「前に戻る」ボタンクリックのハンドラ
        private void bindingNavigatorMovePreviousItem_Click(object sender, 
            EventArgs e)
        {
            try
            {
                productBindingSource.MovePrevious();
            }
            catch (NoNullAllowedException ex)
            {
                MessageBox.Show(this,
                    ex.Message + "\n\nデータを修正してください。",
                    "「前に戻る」ボタン操作エラー",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        // BindingNavigator の「次に移動」ボタンクリックのハンドラ
        private void bindingNavigatorMoveNextItem_Click(object sender, 
            EventArgs e)
        {
            try
            {
                productBindingSource.MoveNext();
            }
            catch (NoNullAllowedException ex)
            {
                MessageBox.Show(this,
                    ex.Message + "\n\nデータを修正してください。",
                    "「次に移動」ボタン操作エラー",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        // BindingNavigator の「最後に移動」ボタンクリックのハンドラ
        private void bindingNavigatorMoveLastItem_Click(object sender, 
            EventArgs e)
        {
            try
            {
                productBindingSource.MoveLast();
            }
            catch (NoNullAllowedException ex)
            {
                MessageBox.Show(this,
                    ex.Message + "\n\nデータを修正してください。",
                    "「最後に移動」ボタン操作エラー",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        // BindingNavigator の[新規追加]ボタンクリックのハンドラ
        private void bindingNavigatorAddNewItem_Click(object sender, 
            EventArgs e)
        {
            try
            {
                productBindingSource.AddNew();
            }
            catch (NoNullAllowedException ex)
            {
                MessageBox.Show(this,
                    ex.Message + "\n\nデータを修正してください。",
                    "「新規追加」ボタン操作エラー",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        // BindingNavigator の[削除]ボタンクリックのハンドラ
        private void bindingNavigatorDeleteItem_Click(object sender, 
            EventArgs e)
        {
            productBindingSource.RemoveCurrent();
        }
    }
}

上のコードには一つオマケで重複入力の検証を追加しています。上の SQL Server のデータベースの画像にあるように ProductName には Unique 制約がかかっていますが、それも検証してエラーメッセージを MessageBox を使って出すようにしています。

SQL Server ですから複数のユーザーが同時にアクセスするのが前提です。なので、重複しているか否かは実際に INSERT する時でないと分かりません。それは、INSERT 操作を行ったとき SqlException がスローされ、エラーの種類を表す番号が 2601 であることで判断できます。

その具体的な例は上のコードの productBindingNavigatorSaveItem_Click メソッドを見てください。


以上ですが、厳しく検証したわけではありませんので、上のコードはあくまで参考程度にお願いします。ひょっとしたら検証漏れがあるかもしれません。

Tags: , , ,

Validation

PostgreSQL とデータソース構成ウィザード

by WebSurfer 2022年10月5日 16:14

PostgreSQL の既存のデータベースから Visual Studio 2022 のデータソース構成ウィザードを利用して型付 DataSet / DataTable + TableAdapter を作ることができます。それを使って、DB のレコードの一覧表示・編集ができる Windows Forms + DataGridView アプリを容易に作成できます。

Windows Forms + GataGridView アプリ

SQL Server の場合は当たり前の話なので何をいまさらと言われるかもしれませんが、先日初めて PostgreSQL をインストールしたので試してみた次第です。

(ASP.NET MVC5 アプリで Entity Framework 6 を使って PostgreSQL の既存の DB の CRUD を行う場合については、先の記事「PostgreSQL で EF6 DB First」に書きましたので、興味があれば見てください)

この記事を書いた時の環境は以下の通りです。

  • PostgreSQL 14.4
  • Visual Studio Community 2022 17.3.5
  • Npgsql PostgreSQL Integration 4.1.12
  • Npgsql 6.0.7
  • .NET Framework 4.8
  • Windows フォームアプリケーション (.NET Framework)

Visual Studio で PostgreSQL に対してデータソース構成ウィザードが使えるようにするには Npgsql PostgreSQL Integration という拡張機能の追加が必要です。下の画像のバージョン 4.1.12 は Visual Studio 2022 用にリリースされたものだそうです。

Npgsql PostgreSQL Integration

拡張機能の追加後、Microsoft のドキュメント「新しいデータ ソースの追加」のようにデータソース構成ウィザードを起動すれば、「データ接続の選択」で PostgreSQL Database を選択できるようになります。

データ接続の選択

以下のように PostgreSQL への接続情報を設定して接続できれば、

接続情報を設定

そのあとは SQL Server とほぼ同様な手順で DataSet(xsd ファイル)を作成できます。

DataSet(xsd ファイル)

xsd ファイルが作成できると、デザイン画面でデータソースウィンドウに DataSet / DataTable が表示されるので (下の画像で MovieDataSet / Movie)、DataTable (Movie) の DataGridView を選択してから Form にドラッグ&ドロップします。

データソースウィンドウの DataSet / DataTable

上の画像はドラッグ&ドロップして必要なコードがすべて生成された後、DataGridView.Dock プロパティを Fill に設定したものです。

次に NuGet から Npgsql をインストールします。

NuGet から Npgsql をインストール

その後ソリューションをビルドして実行すればこの記事の一番上の画像のようなアプリが動きます。DataGridView を編集した結果も期待通り DB に反映されます。

ただ、微妙なところがあって、なぜか Npgsql のインストールのタイミングが問題で、自分の環境で試した時は以下の順番で行う必要がありましたので注意してください。

  1. データソース構成ウィザードを起動し型付 DataSet / DataTable + TableAdapter を生成
  2. 「データソース」ウィンドウから作成した DataTable を Form にドラッグ&ドロップ
  3. NuGet から Npgsql をインストール
  4. ソリューションをビルド

想像ですが、データソース構成ウィザードが使う Npgsql と NuGet からインストールする Npgsql やその他の関係 dll とのバージョンの不整合が問題ではないかと思われます。

Tags: , ,

.NET Framework

.NET 6.0 で Windows Forms アプリ作成

by WebSurfer 2021年12月4日 14:22

2021 年 11 月にリリースされた Visual Studio Community 2022 のテンプレートを使って .NET 6.0 版の Windows Forms アプリを作ってみました。Visual Studio のバージョンはこの記事を書いた時点で最新版の 17.0.2、SDK は 6.0.100、ランタイムは 6.0.0 です。

.NET 6.0 版の Windows Forms アプリ

まず一つ問題があって、プロジェクト作成直後はデザイン画面が表示されません。下の画像のようにソリューションエクスプローラーに表示されるアイコンは C# のクラスファイスのもので、ここからデザイナ画面を表示することもできません。また、Form1.resx ファイルも存在しません。

初期画面

Developer Community に VS 2022 - WinForms .NET Designer does not automatically show the design surface when creating a new project という報告が上がっていて年内には改善されるとのことです。その記事に workaround が紹介されていますが自分の環境ではダメでした。

自分が試した限りですが、自動生成された Form1.cs を削除し、ソリューションエクスプローラーを操作して「新しい項目の追加」ダイアログから[フォーム (Windows フォーム)]を選んで新たにフォームを追加すればデザイナ画面は表示されました。Form1.resx も生成されました。

ただし、それでだけで全て OK かどうかは分かりません。実際、他の問題として、v17.0.1 の時 Form1.resx に画像を含めると開かないということがありました (v17.0.2 で改善されたのかその問題は出なくなりましたが)。年内に fix すると言っているので、待てるのであればそれを待った方が良いかもしれません。

以下は、自動生成された Form1.cs を削除してから新たに追加するという方法でデザイナ画面の表示と Form1.resx の生成を行ってから進めた時の話です。

SQL Server データベースから Visual Studio 2022 のウィザードを利用して型付 DataSet / DataTable + TableAdapter を作り、テーブルのレコード一覧を DataGridView に表示し、ユーザーが DataGridView に表示されたデータを編集してからデーターベースに編集結果を反映するという Windows Forms 定番のアプリを作ります。

Microsoft のドキュメント「新しいデータ ソースの追加」には ".NET Core 開発ではサポートされていません" と書いてありますが、型付 DataSet / DataTable + TableAdapter を作ることは可能です。ただし、その記事に書いてあるように[データ ソース]ウィンドウからドラッグ&ドロップしてコードを自動生成させることはできませんので、そこは自力でコードを書くことになります。

まず、型付 DataSet / DataTable + TableAdapter を作ります。ソリューションエクスプローラーでプロジェクトを右クリック ⇒[追加(D)]⇒[新しい項目(W)...]で表示されるメニューの中に DataSet という項目がありますのでそれを使います。(注: 上に紹介した Microsoft のドキュメントのように[プロジェクト(P)]⇒[新しいデータソースの追加(N)...]と操作するとサポートされてないというメッセージが出てその先に進めません)

SQL Server サンプルデータベース Northwind の Products, Catagories, Suppliers テーブルから NorthwindDataSet.xsd という名前で DataSet を作ってみました。この記事で使うのは下の画像の中の Products + ProductsTableAdapter です。

型付 DataSet / DataTable + TableAdapter

ここまでは Windows Forms プロジェクトを作成したデフォルトの状態で進めることができます。しかし、ビルドしようとすると SqlConnection, SqlCommand, SqlDataAdapter, SqlTransaction 等が System.Data.SqlClient に見つからないというエラーになって失敗します。

SqlConnection, SqlCommand 等は .NET Core 3.1 でも .NET 5.0 でもデフォルトでは含まれておらず NuGet で System.Data.SqlClient をインストールする必要がありました。.NET 6.0 でも同じことのようです。

NuGet パッケージのインストール

上の画像の System.Data.Common の方は無くてもビルドは通りますが、SystemDBNull とか System.Data.DbType 等が含まれているとのことなので念のため追加しておきました。

この後、.NET Framework であれば作成した DataTable を[データ ソース]ウィンドウからフォームにドラッグ&ドロップするだけで完全な Windows Forms アプリが自動生成されますが、.NET Core 3.1 や .NET 6.0 ではここから先は自力でコードを書くことになります。

一番実装が面倒そうなのが BindingNavigator 周りだと思いますが、それをデザイン画面で実装しようとしても、そもそもツールボックスに BindingNavigator がありません。

どうも特定の OS に依存するアプリを .NET Core 3.1 や .NET 6.0 で作る場合のサポートは限られているということのようです。Windows OS に依存する Windows Forms アプリなら最初から .NET Framework ベースで作るのが正解のようです。

しかし、ツールボックスに BindingNavigator が無いからと言って .NET 6.0 アプリで使えないというわけではないようです。Visual Studio のデザイナが対応してないだけで、.NET Framework ベースで作ったアプリと同じコードを書けば同じように動くはずです。

ということで、既存の .NET Framework ベースで作ったアプリから BindingNavigator 他のコードを移植してみました。

まず、BindingNavigator が使う .png 画像を既存のアプリから取得して Form1.resx にコピーします。

BindingNavigator が使う .png 画像

.NET 5.0 以前では画像は base64 形式に変換されて .resx ファイル内に埋め込まれたのですが、.NET 6.0 ではプロジェクトルート直下に Resources という名前のフォルダが作られ、その中に画像ファイルが格納される点が異なります。

Resources フォルダの画像ファイル

その後、既存の .NET Framework アプリからコードを移植します。以下がその例で、この記事の一番上の画像がその実行結果です。

namespace WinFormsApp2
{
    public partial class Form1 : Form
    {
        private NorthwindDataSet northwindDataSet;
        private System.Windows.Forms.BindingSource productsBindingSource;
        private NorthwindDataSetTableAdapters.ProductsTableAdapter productsTableAdapter;
        private NorthwindDataSetTableAdapters.TableAdapterManager tableAdapterManager;
        private System.Windows.Forms.BindingNavigator productsBindingNavigator;
        private System.Windows.Forms.ToolStripButton bindingNavigatorAddNewItem;
        private System.Windows.Forms.ToolStripLabel bindingNavigatorCountItem;
        private System.Windows.Forms.ToolStripButton bindingNavigatorDeleteItem;
        private System.Windows.Forms.ToolStripButton bindingNavigatorMoveFirstItem;
        private System.Windows.Forms.ToolStripButton bindingNavigatorMovePreviousItem;
        private System.Windows.Forms.ToolStripSeparator bindingNavigatorSeparator;
        private System.Windows.Forms.ToolStripTextBox bindingNavigatorPositionItem;
        private System.Windows.Forms.ToolStripSeparator bindingNavigatorSeparator1;
        private System.Windows.Forms.ToolStripButton bindingNavigatorMoveNextItem;
        private System.Windows.Forms.ToolStripButton bindingNavigatorMoveLastItem;
        private System.Windows.Forms.ToolStripSeparator bindingNavigatorSeparator2;
        private System.Windows.Forms.ToolStripButton productsBindingNavigatorSaveItem;
        private System.Windows.Forms.DataGridView productsDataGridView;

        public Form1()
        {
            InitializeComponent();

            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = 
                new System.ComponentModel.ComponentResourceManager(typeof(Form1));
            this.northwindDataSet = new NorthwindDataSet();
            this.productsBindingSource = new System.Windows.Forms.BindingSource(this.components);
            this.productsTableAdapter = new NorthwindDataSetTableAdapters.ProductsTableAdapter();
            this.tableAdapterManager = new NorthwindDataSetTableAdapters.TableAdapterManager();
            this.productsBindingNavigator = new System.Windows.Forms.BindingNavigator(this.components);
            this.bindingNavigatorAddNewItem = new System.Windows.Forms.ToolStripButton();
            this.bindingNavigatorCountItem = new System.Windows.Forms.ToolStripLabel();
            this.bindingNavigatorDeleteItem = new System.Windows.Forms.ToolStripButton();
            this.bindingNavigatorMoveFirstItem = new System.Windows.Forms.ToolStripButton();
            this.bindingNavigatorMovePreviousItem = new System.Windows.Forms.ToolStripButton();
            this.bindingNavigatorSeparator = new System.Windows.Forms.ToolStripSeparator();
            this.bindingNavigatorPositionItem = new System.Windows.Forms.ToolStripTextBox();
            this.bindingNavigatorSeparator1 = new System.Windows.Forms.ToolStripSeparator();
            this.bindingNavigatorMoveNextItem = new System.Windows.Forms.ToolStripButton();
            this.bindingNavigatorMoveLastItem = new System.Windows.Forms.ToolStripButton();
            this.bindingNavigatorSeparator2 = new System.Windows.Forms.ToolStripSeparator();
            this.productsBindingNavigatorSaveItem = new System.Windows.Forms.ToolStripButton();
            this.productsDataGridView = new System.Windows.Forms.DataGridView();
            ((System.ComponentModel.ISupportInitialize)(this.northwindDataSet)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.productsBindingSource)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.productsBindingNavigator)).BeginInit();
            this.productsBindingNavigator.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.productsDataGridView)).BeginInit();
            this.SuspendLayout();

            // 
            // northwindDataSet
            // 
            this.northwindDataSet.DataSetName = "NorthwindDataSet";
            this.northwindDataSet.SchemaSerializationMode = 
                System.Data.SchemaSerializationMode.IncludeSchema;
            // 
            // productsBindingSource
            // 
            this.productsBindingSource.DataMember = "Products";
            this.productsBindingSource.DataSource = this.northwindDataSet;
            // 
            // productsTableAdapter
            // 
            this.productsTableAdapter.ClearBeforeFill = true;
            // 
            // tableAdapterManager
            // 
            this.tableAdapterManager.BackupDataSetBeforeUpdate = false;
            this.tableAdapterManager.ProductsTableAdapter = this.productsTableAdapter;
            this.tableAdapterManager.UpdateOrder = 
                NorthwindDataSetTableAdapters.TableAdapterManager.UpdateOrderOption.InsertUpdateDelete;
            // 
            // productsBindingNavigator
            // 
            this.productsBindingNavigator.AddNewItem = this.bindingNavigatorAddNewItem;
            this.productsBindingNavigator.BindingSource = this.productsBindingSource;
            this.productsBindingNavigator.CountItem = this.bindingNavigatorCountItem;
            this.productsBindingNavigator.DeleteItem = this.bindingNavigatorDeleteItem;
            this.productsBindingNavigator.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.bindingNavigatorMoveFirstItem,
            this.bindingNavigatorMovePreviousItem,
            this.bindingNavigatorSeparator,
            this.bindingNavigatorPositionItem,
            this.bindingNavigatorCountItem,
            this.bindingNavigatorSeparator1,
            this.bindingNavigatorMoveNextItem,
            this.bindingNavigatorMoveLastItem,
            this.bindingNavigatorSeparator2,
            this.bindingNavigatorAddNewItem,
            this.bindingNavigatorDeleteItem,
            this.productsBindingNavigatorSaveItem});
            this.productsBindingNavigator.Location = new System.Drawing.Point(0, 0);
            this.productsBindingNavigator.MoveFirstItem = this.bindingNavigatorMoveFirstItem;
            this.productsBindingNavigator.MoveLastItem = this.bindingNavigatorMoveLastItem;
            this.productsBindingNavigator.MoveNextItem = this.bindingNavigatorMoveNextItem;
            this.productsBindingNavigator.MovePreviousItem = this.bindingNavigatorMovePreviousItem;
            this.productsBindingNavigator.Name = "productsBindingNavigator";
            this.productsBindingNavigator.PositionItem = this.bindingNavigatorPositionItem;
            this.productsBindingNavigator.Size = new System.Drawing.Size(1136, 25);
            this.productsBindingNavigator.TabIndex = 0;
            this.productsBindingNavigator.Text = "bindingNavigator1";
            // 
            // bindingNavigatorAddNewItem
            //
#nullable disable
            this.bindingNavigatorAddNewItem.DisplayStyle = 
                System.Windows.Forms.ToolStripItemDisplayStyle.Image;
            this.bindingNavigatorAddNewItem.Image = 
                ((System.Drawing.Image)(resources.GetObject("bindingNavigatorAddNewItem.Image")));
            this.bindingNavigatorAddNewItem.Name = "bindingNavigatorAddNewItem";
            this.bindingNavigatorAddNewItem.RightToLeftAutoMirrorImage = true;
            this.bindingNavigatorAddNewItem.Size = new System.Drawing.Size(23, 22);
            this.bindingNavigatorAddNewItem.Text = "新規追加";
            // 
            // bindingNavigatorCountItem
            // 
            this.bindingNavigatorCountItem.Name = "bindingNavigatorCountItem";
            this.bindingNavigatorCountItem.Size = new System.Drawing.Size(29, 22);
            this.bindingNavigatorCountItem.Text = "/ {0}";
            this.bindingNavigatorCountItem.ToolTipText = "項目の総数";
            // 
            // bindingNavigatorDeleteItem
            // 
            this.bindingNavigatorDeleteItem.DisplayStyle = 
                System.Windows.Forms.ToolStripItemDisplayStyle.Image;
            this.bindingNavigatorDeleteItem.Image = 
                ((System.Drawing.Image)(resources.GetObject("bindingNavigatorDeleteItem.Image")));
            this.bindingNavigatorDeleteItem.Name = "bindingNavigatorDeleteItem";
            this.bindingNavigatorDeleteItem.RightToLeftAutoMirrorImage = true;
            this.bindingNavigatorDeleteItem.Size = new System.Drawing.Size(23, 22);
            this.bindingNavigatorDeleteItem.Text = "削除";
            // 
            // bindingNavigatorMoveFirstItem
            // 
            this.bindingNavigatorMoveFirstItem.DisplayStyle = 
                System.Windows.Forms.ToolStripItemDisplayStyle.Image;
            this.bindingNavigatorMoveFirstItem.Image = 
                ((System.Drawing.Image)(resources.GetObject("bindingNavigatorMoveFirstItem.Image")));
            this.bindingNavigatorMoveFirstItem.Name = "bindingNavigatorMoveFirstItem";
            this.bindingNavigatorMoveFirstItem.RightToLeftAutoMirrorImage = true;
            this.bindingNavigatorMoveFirstItem.Size = new System.Drawing.Size(23, 22);
            this.bindingNavigatorMoveFirstItem.Text = "最初に移動";
            // 
            // bindingNavigatorMovePreviousItem
            // 
            this.bindingNavigatorMovePreviousItem.DisplayStyle = 
                System.Windows.Forms.ToolStripItemDisplayStyle.Image;
            this.bindingNavigatorMovePreviousItem.Image = 
                ((System.Drawing.Image)(resources.GetObject("bindingNavigatorMovePreviousItem.Image")));
            this.bindingNavigatorMovePreviousItem.Name = "bindingNavigatorMovePreviousItem";
            this.bindingNavigatorMovePreviousItem.RightToLeftAutoMirrorImage = true;
            this.bindingNavigatorMovePreviousItem.Size = new System.Drawing.Size(23, 22);
            this.bindingNavigatorMovePreviousItem.Text = "前に戻る";
            // 
            // bindingNavigatorSeparator
            // 
            this.bindingNavigatorSeparator.Name = "bindingNavigatorSeparator";
            this.bindingNavigatorSeparator.Size = new System.Drawing.Size(6, 25);
            // 
            // bindingNavigatorPositionItem
            // 
            this.bindingNavigatorPositionItem.AccessibleName = "位置";
            this.bindingNavigatorPositionItem.AutoSize = false;
            this.bindingNavigatorPositionItem.Font = new System.Drawing.Font("Yu Gothic UI", 9F);
            this.bindingNavigatorPositionItem.Name = "bindingNavigatorPositionItem";
            this.bindingNavigatorPositionItem.Size = new System.Drawing.Size(50, 23);
            this.bindingNavigatorPositionItem.Text = "0";
            this.bindingNavigatorPositionItem.ToolTipText = "現在の場所";
            // 
            // bindingNavigatorSeparator1
            // 
            this.bindingNavigatorSeparator1.Name = "bindingNavigatorSeparator1";
            this.bindingNavigatorSeparator1.Size = new System.Drawing.Size(6, 25);
            // 
            // bindingNavigatorMoveNextItem
            // 
            this.bindingNavigatorMoveNextItem.DisplayStyle = 
                System.Windows.Forms.ToolStripItemDisplayStyle.Image;
            this.bindingNavigatorMoveNextItem.Image = 
                ((System.Drawing.Image)(resources.GetObject("bindingNavigatorMoveNextItem.Image")));
            this.bindingNavigatorMoveNextItem.Name = "bindingNavigatorMoveNextItem";
            this.bindingNavigatorMoveNextItem.RightToLeftAutoMirrorImage = true;
            this.bindingNavigatorMoveNextItem.Size = new System.Drawing.Size(23, 22);
            this.bindingNavigatorMoveNextItem.Text = "次に移動";
            // 
            // bindingNavigatorMoveLastItem
            // 
            this.bindingNavigatorMoveLastItem.DisplayStyle = 
                System.Windows.Forms.ToolStripItemDisplayStyle.Image;
            this.bindingNavigatorMoveLastItem.Image = 
                ((System.Drawing.Image)(resources.GetObject("bindingNavigatorMoveLastItem.Image")));
            this.bindingNavigatorMoveLastItem.Name = "bindingNavigatorMoveLastItem";
            this.bindingNavigatorMoveLastItem.RightToLeftAutoMirrorImage = true;
            this.bindingNavigatorMoveLastItem.Size = new System.Drawing.Size(23, 22);
            this.bindingNavigatorMoveLastItem.Text = "最後に移動";
            // 
            // bindingNavigatorSeparator2
            // 
            this.bindingNavigatorSeparator2.Name = "bindingNavigatorSeparator2";
            this.bindingNavigatorSeparator2.Size = new System.Drawing.Size(6, 25);
            // 
            // productsBindingNavigatorSaveItem
            // 
            this.productsBindingNavigatorSaveItem.DisplayStyle = 
                System.Windows.Forms.ToolStripItemDisplayStyle.Image;
            this.productsBindingNavigatorSaveItem.Image = 
                ((System.Drawing.Image)(resources.GetObject("productsBindingNavigatorSaveItem.Image")));
            this.productsBindingNavigatorSaveItem.Name = "productsBindingNavigatorSaveItem";
            this.productsBindingNavigatorSaveItem.Size = new System.Drawing.Size(23, 22);
            this.productsBindingNavigatorSaveItem.Text = "データの保存";
            this.productsBindingNavigatorSaveItem.Click += ProductsBindingNavigatorSaveItem_Click;
#nullable enable
            // 
            // productsDataGridView
            // 
            //this.productsDataGridView.AutoGenerateColumns = false;
            this.productsDataGridView.ColumnHeadersHeightSizeMode = 
                System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.productsDataGridView.DataSource = this.productsBindingSource;
            this.productsDataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
            this.productsDataGridView.Location = new System.Drawing.Point(0, 25);
            this.productsDataGridView.Name = "productsDataGridView";
            this.productsDataGridView.RowTemplate.Height = 21;
            //this.productsDataGridView.Size = new System.Drawing.Size(1136, 643);
            this.productsDataGridView.TabIndex = 1;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.Controls.Add(this.productsDataGridView);
            this.Controls.Add(this.productsBindingNavigator);
            this.Name = "Form1";
            this.Text = "Northwind";
            this.Load += Form1_Load;
            ((System.ComponentModel.ISupportInitialize)(this.northwindDataSet)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.productsBindingSource)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.productsBindingNavigator)).EndInit();
            this.productsBindingNavigator.ResumeLayout(false);
            this.productsBindingNavigator.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)(this.productsDataGridView)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        private void Form1_Load(object? sender, EventArgs e)
        {
            this.productsTableAdapter.Fill(this.northwindDataSet.Products);
        }

        private void ProductsBindingNavigatorSaveItem_Click(object? sender, EventArgs e)
        {
            this.Validate();
            this.productsBindingSource.EndEdit();
            this.tableAdapterManager.UpdateAll(this.northwindDataSet);
        }
    }
}

既存の .NET Framework アプリのコードと違うところは、DataGridView の AutoGenerateColumns プロパティをデフォルトの true として各列を DataTable から自動生成させていることろです。ひょっとしたらそれによる予期せぬ副作用があるかもしれません。

もう一つ、接続文字列が TableAdapter のコードの 中にハードコーディングされているところが .NET Framework アプリと違います。.NET Framework アプリの場合、接続文字列は設定ファイルに格納され、TableAdapter はそれから読んでくるのですが、.NET 6.0 版はそこのところにも手を加える必要があります。

こんな手間をかけるなら、最初から .NET Framework 版で作ってコードはすべて Visual Studio のデザイナで自動生成させればいいと言われそうですが、確かにその通りだと思いました。

Tags: , ,

CORE

About this blog

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

Calendar

<<  2024年3月  >>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar