データグリッドビューのチェックボックスの初期値について

タグの編集
投稿者 氷河  (社会人) 投稿日時 2023/7/10 17:51:10
.C#のNET Framework 4.8を使用しています

質問といたしましては、データグリッドビューのチェックボックスを使用する際の初期値の設定方法がわからず困っています。

現在フォームにBindingSourceを配置し、コードにて以下のように記載し、データを表示しています。
dtはDataTable型の変数でSQLServerから取得したデータが入っています。

                dgvBindingSource = new BindingSource();
                dgvBindingSource.DataSource = dtfusoku;
                dgv.DataSource = dt;

このように表示しているデータグリッドビューの1カラムの1つをチェックボックスに変更したいです。
以下のようにカラムを追加しました。"KANRYO_FLG"というのはchar(1)型のdtに存在するデータです。

            DataGridViewCheckBoxColumn chkColumn = new DataGridViewCheckBoxColumn();
            chkColumn.HeaderText = "完了";
            chkColumn.Width = 60;
            chkColumn.ReadOnly = false;
            chkColumn.Name = "CHECK_FLG";
            chkColumn.DataPropertyName = "CHECK_FLG";
            dgv.Columns.Add(chkColumn);

そして、上記のようにデータをバインドさせたところ、boolean型の有効な値ではありません。というエラーが発生し、質問することに至りました。
"CHECK_FLG"は0か1しか値を取らず、1の時、チェックされた状態で表示するようにしたいと考えております。


DataSourceが使えないので、データグリッドビューにDataTableのデータを場合分けをしてデータグリッドビューに1行1行追加していく必要があるのか、それとも別の方法があるのか教えていただきたいです。
よろしくお願いいたします。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/7/10 18:38:59
DataTable の KANRYO_FLG 列のデータ型 (DataType プロパティ) は
恐らく System.String 型なのですよね。(そして MaxLength プロパティは -1~1 のいずれかと推察)

であれば、DataGridViewCheckBoxColumn に対して、
デザイン時設定もしくはコードから、下記のように設定してみてください。

• ValueType プロパティ … GetType(String)
• TrueValue プロパティ … "1"
• FalseValue プロパティ … "0"
• ThreeState プロパティ … 任意
投稿者 氷河  (社会人) 投稿日時 2023/7/11 10:28:21
>>DataTable の KANRYO_FLG 列のデータ型 (DataType プロパティ) は
>>恐らく System.String 型なのですよね。(そして MaxLength プロパティは -1~1 のいずれかと推察)

そうです。記載漏れで申し訳ございません。

>>であれば、DataGridViewCheckBoxColumn に対して、
>>デザイン時設定もしくはコードから、下記のように設定してみてください。
>>• ValueType プロパティ … GetType(String)
>>• TrueValue プロパティ … "1"
>>• FalseValue プロパティ … "0"
>>• ThreeState プロパティ … 任意

一点だけ、GetType(String)の部分が赤線が出て、
CS0019 Stringは種類です。これは特定のコンテンツは無効になります
というエラーが出ましたが、GetType()と記載したところ初期表示ができるようになりました。ありがとうございます。

もう一点質問がございまして、"1"以外の値を全てfalse扱いにすることは可能でしょうか?
複雑そうならThreeStateプロパティをTrueにして対応したいと思います。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/7/11 13:58:33
>>> "KANRYO_FLG"というのはchar(1)型のdtに存在するデータです。
>>> chkColumn.Name = "CHECK_FLG";
>>> chkColumn.DataPropertyName = "CHECK_FLG";
KANRYO_FLG と CHECK_FLG の両方とも、同じ仕様ですか?
特に、null の許容性が気になります。

SQL Server 側は "0" または "1" であるとお聞きしましたが、
そこから DataTable に保持した後で、該当列の値としてそれ以外の値、
たとえば " " や "" や null や DBNull.Value がありえるのか否か。


> CS0019
あ、ごめんなさい。VB ではなくて C# でしたね。
C# の場合は typeof(string) と書いてください。

> GetType()と記載したところ初期表示ができるようになりました。
GetType() と書いた場合は、this.GetType() と解釈されてしまいます。
結果的に typeof(Form1) などがセットされてしまうことになるかと。


> "1"以外の値を全てfalse扱いにすることは可能でしょうか?
>>> "CHECK_FLG"は0か1しか値を取らず、1の時、チェックされた状態で表示するようにしたい

0、1 以外が含まれる可能性がありえるのか否かは、事前に決定しておく必要がありますね。

後から値の種類が増えると、既に開発済みの範囲において、
else 処理において致命的な事態になりかねません。(C# 側も SQL Server 側も)

可能であれば、未定義値の混入を完全に防ぐため、SQL Server 側にて
ALTER TABLE [TBL] ADD CONSTRAINT [chkTBL_CHECK_FLG] ([CHECK_FLG] IN ('0', '1'));
などの CHECK 制約を含めておいた方が良いかと思います。

こうすると、仕様変更で別の値も保持することになった場合には、
データベース側の CHECK 制約を必然的に見直すことになりますので、
それを利用しているストアドや C# 側も一緒に検査する機会を得やすくなります。


> "1"以外の値を全てfalse扱いにすることは可能でしょうか?
bool 系の処理というのは、0 → false 、非 0 → true が一般的なので、
非1 → false 、1 → true という設計は、なかなか珍しいですね。


たとえば、該当の DataTable に対して、追加で bool 型の「式列」を用意する方法があります。
式列 (Expression Column) とは、Expression プロパティを指定した DataColumn クラスのことです。
https://learn.microsoft.com/ja-jp/dotnet/framework/data/adonet/dataset-datatable-dataview/creating-expression-columns

この場合、DataSet デザイナーでは
 DataType → System.Boolean
 MaxLength → -1
 DefaultValue → false
 Expression → CHECK_FLG='1'
のように設定します。実行時に追加する場合は、
 対象テーブル.Columns.Add("新列名", typeof(bool), "CHECK_FLG='1'").DefaultValue = false;
です。

そのうえで、この新列を DataGridViewCheckBoxColumn にバインドします。
 対象列.ValueType = typeof(bool);
 対象列.ReadOnly = true;
です。IndeterminateValue / FalseValue / TrueValue は null のままで OK。
あるいは明示的に
 対象列.IndeterminateValue = DBNull.Value;
 対象列.FalseValue = false;
 対象列.TrueValue = true;
としても構いません。
※注:Expression プロパティが指定されている場合、その列は ReadOnly になります。

もし、チェックボックス列を、編集可能にしたい場合は、
DataTable 上の CHECK_FLG 列を、string 列ではなく bool 列にしておきましょう。

その場合、SQL Server 側との CHAR(1) とのマッピングは、
DataAdapter や TableAdapter のコマンド、具体的には
SelectCommand / UpdateCommand / InsertCommand / DeleteCommand プロパティで
列名エイリアスや CASE WHEN 式などを用いて割り当てます。


あるいは、SQL Server 側から DataTable にマッピングした後で
自前で .Columns.Add("新列名", typeof(bool)) してから
foreach ループなどで CHECK_FLG 列との値で値を転送する…という手もあります。
投稿者 氷河  (社会人) 投稿日時 2023/7/11 17:25:04
//KANRYO_FLG と CHECK_FLG の両方とも、同じ仕様ですか?
//特に、null の許容性が気になります。

表記間違えておりました、申し訳ございません。nullは許容していません。

//bool 系の処理というのは、0 → false 、非 0 → true が一般的なので、
//非1 → false 、1 → true という設計は、なかなか珍しいですね。

知識不足でした、覚えておくようにいたします。

長文ありがとうございます。データベースの方で制約を追加する方がよさそうだなと感じたので、そちらで対応したいと思います。ありがとうございました!