トップ回答者
DataGridViewColumn の columnName としてフィールド名を自動的に割り当てるには

質問
-
id, name というフィールドをもつ DataTable をデータ ソースからフォームに
ドラッグして生成される DataGridView の「列の編集」を以下に示します。
図 (1)
左側「選択された列」の "name" を選択すると、
右側「バインド列のプロパティ」の (Name) が "dataGridViewTextBoxColumn2" になっています。
このままでは、
this.dataGridView1.Rows[0].Cells["name"].Value
として "name" セルにアクセスした場合、以下のようなエラーを出してしまいます。
図 (2)これはメッセージ通り、DataGridViewColumn の columnName として "name"
をもつ列がないからです (下記リスト(1) 参照)。
リスト (1) DataGridViewCellCollection のインデクサCode Snippetpublic class DataGridViewCellCollection : BaseCollection, IList
{
public DataGridViewCell this[string columnName]
{
get
{
DataGridViewColumn dataGridViewColumn = null;
if (this.owner.DataGridView != null)
{
dataGridViewColumn = this.owner.DataGridView.Columns[columnName];
}
if (dataGridViewColumn == null)
{
throw new ArgumentException(SR.GetString(SR.DataGridViewColumnCollection_ColumnNotFound, columnName),
"columnName");
}
return (DataGridViewCell) this.items[dataGridViewColumn.Index];
}図(1) で確認できる通り、"name" に相当する列は columnName として
"dataGridViewTextBoxColumn2" がドラッグ・ドロップ時に自動的に割り当てられています。
この自動的に割り当てられる命名を回避して、DataPropertyName と同じように、フィールド名が設定される方法はないものでしょうか?
回答
-
custar さんからの引用 そもそも、何故 DataPropertyName だけにフィールド名が割り当てられて、
(column)Name には割り当てられないのか.....Name プロパティの値は、IDE が生成する Form デザイナコードのコントロール識別子と同じになるので、識別子として使用できない文字(空白など)が含まれる可能性が高い列名を、Name の値には使いたくなかったからではないでしょうかね(DataGridView としては、同じデータソース列を複数個追加することもできますし)。
# Name の値としては、空白が含まれたり重複したりしても大丈夫ですが、もしそのようなコードを IDE が生成すれば、混乱の元になると思います。
custar さんの方法がシンプルで良さそうに思いますが、次のような拡張メソッドを考えてみました。
これを使用すると、Cells["name"].Value の箇所が Cells2("name").Value になります。
# 三輪の牛さんの方法も良さそうですね。ただ、実行し忘れたりしそうで少しだけ心配です
Code Snippetpublic static class DataGridViewRowExtensions
{
/// <summary>
/// セルのコレクションから DataPropertyName が一致する
/// セルを取得します。
/// </summary>
/// <param name="dataPropertyName">
/// セルを取得する DataGridViewColumn.DataPropertyName の値。
/// </param>
public static DataGridViewCell Cells2(
this DataGridViewRow row,
string dataPropertyName)
{
foreach (DataGridViewColumn col in row.DataGridView.Columns)
{
if (string.Equals(
col.DataPropertyName, dataPropertyName,
StringComparison.OrdinalIgnoreCase))
return row.Cells[col.Index];
}
throw new ArgumentException(
string.Format("'{0}' には '{1}' という列は見つかりません。",
!string.IsNullOrEmpty(row.DataGridView.Name)
? row.DataGridView.Name : "(DataGridView)",
dataPropertyName),
"dataPropertyName");
}
}
すべての返信
-
こんな感じでどうでしょうか?
Code Snippetprivate void columnsDataGridView_DataBindingComplete(
object sender, DataGridViewBindingCompleteEventArgs e)
{
foreach (DataGridViewColumn col in this.columnsDataGridView.Columns)
{
if (col.Name != col.DataPropertyName)
{
col.Name = col.DataPropertyName;
}
}
}
binding 直後に DataPropertyName を (column)Name に代入する。
もっといい案がありましたらお教えください。p.s.
----
そもそも、何故 DataPropertyName だけにフィールド名が割り当てられて、
(column)Name には割り当てられないのか.....
-
custar さんからの引用 そもそも、何故 DataPropertyName だけにフィールド名が割り当てられて、
(column)Name には割り当てられないのか.....Name プロパティの値は、IDE が生成する Form デザイナコードのコントロール識別子と同じになるので、識別子として使用できない文字(空白など)が含まれる可能性が高い列名を、Name の値には使いたくなかったからではないでしょうかね(DataGridView としては、同じデータソース列を複数個追加することもできますし)。
# Name の値としては、空白が含まれたり重複したりしても大丈夫ですが、もしそのようなコードを IDE が生成すれば、混乱の元になると思います。
custar さんの方法がシンプルで良さそうに思いますが、次のような拡張メソッドを考えてみました。
これを使用すると、Cells["name"].Value の箇所が Cells2("name").Value になります。
# 三輪の牛さんの方法も良さそうですね。ただ、実行し忘れたりしそうで少しだけ心配です
Code Snippetpublic static class DataGridViewRowExtensions
{
/// <summary>
/// セルのコレクションから DataPropertyName が一致する
/// セルを取得します。
/// </summary>
/// <param name="dataPropertyName">
/// セルを取得する DataGridViewColumn.DataPropertyName の値。
/// </param>
public static DataGridViewCell Cells2(
this DataGridViewRow row,
string dataPropertyName)
{
foreach (DataGridViewColumn col in row.DataGridView.Columns)
{
if (string.Equals(
col.DataPropertyName, dataPropertyName,
StringComparison.OrdinalIgnoreCase))
return row.Cells[col.Index];
}
throw new ArgumentException(
string.Format("'{0}' には '{1}' という列は見つかりません。",
!string.IsNullOrEmpty(row.DataGridView.Name)
? row.DataGridView.Name : "(DataGridView)",
dataPropertyName),
"dataPropertyName");
}
} -
三輪の牛 さん、情報ありがとうございます。
三輪の牛 さんからの引用 アドインについては Visual Studio 付属のユーザーズガイドが役に立ちます。
付属って事は、購入した物に付いているのですか? 私のは試用版....
- Visual Studio .NET 2002 必要システム および パッケージ内容 -
TH01 さんからの引用 # Name の値としては、空白が含まれたり重複したりしても大丈夫ですが、もし
そのようなコードを IDE が生成すれば、混乱の元になると思います。
なるほど、万人向けにはそうですね。
馴れて来たら自分で設定できるようにしておいて欲しかったなぁ。そういうオ
プションがないのかな、と思いましたが、詳しい方が自作されているところを
見ると、ないようですね。
TH01 さんからの引用 次のような拡張メソッドを考えてみました。これを使用すると、
Cells ["name"].Value の箇所が
Cells2("name").Value になります。
これどう使うのでしょう?TH01 さんからの引用 # 三輪の牛さんの方法も良さそうですね。ただ、実行し忘れたりしそうで少しだけ心配です
私の印象では、これが後々楽そうなんですが。
実行し忘れたらテストで引っ掛かるので、問題ないと思います。
また、何らかの更新の催促を仕込めないかとも考えてしまいます。 -
custar さんからの引用
Code Snippetprivate void columnsDataGridView_DataBindingComplete(
object sender, DataGridViewBindingCompleteEventArgs e)
{
foreach (DataGridViewColumn col in this.columnsDataGridView.Columns)
{
if (col.Name != col.DataPropertyName)
{
col.Name = col.DataPropertyName;
}
}
}私は毎回引っ掛かりそうなので、これを実装した DataGridView を継承させて
ツールボックスに登録しておくかもしれません。# そんなことできるのかな?
-
DataGridViewRowExtensions クラスをソースのどこかにコピペしておき、
Cells["name"].Value と書く代わりに
Cells2("name").Value と書く
という意味でした。Cells のインデクサは Name を見ますが、Cells2 拡張メソッドは DataGridViewRowExtensions クラスでの実装の通り、DataPropertyName を調べます。
# custar さんは Visual Studio 2008 でしたよね。ツールボックスへの登録は、ツールボックス上で右クリックしたメニューにある [アイテムの選択] でできます。
-
TH01 さんからの引用 Cells["name"].Value と書く代わりに
Cells2("name").Value と書く
えぇぇえ!?Code Snippet
string s1 = this.columnsDataGridView.Rows[0].Cells["name"].Value;
string s2 = this.columnsDataGridView.Rows[0].Cells2("name").Value;という記述において、Rows[0]. の後に Intellisense で Cell2 が現れました。ナンデ?
分からん。知らないことが起きてる!
多分 Cell2 の第1引数に this が入っているのがトリックの種だろうと思いま
すが、何なんですか、これ?それとも DataGridViewRow + Extensions という命名規則に何か裏があるのか....