トップ回答者
DataGridViewのテキストボックスでの和暦表示について

質問
-
おはようございます。
http://social.msdn.microsoft.com/Forums/ja-JP/0f1b2a50-42f9-42eb-8564-213fef0dea72/datagridviewcelltemplate?forum=vbexpressja
にて、DataGridViewのテキストボックスでの和暦表示をご教授いただきました。
今回、使用していて気付いたのですが、和暦テキストボックスがDataGridViewの最初の列になる場合に
エラーとなってしまいます。エラーの内容は下記の通りです。
System.ArgumentOutOfRangeException:指定された引数は、有効な値の範囲内にありません。
パラメーター名:rowIndexデバッグで追っていくと、
clsDGVWarekiTextBoxCell.ToYYYYMMDD
でエラーが発生します。どうしてもエラーの理由がわからないので、和暦表示のテキストボックスの前に列を作り、幅を最小にして
対応しています。(非表示にしてもエラーになってしまうため。)どうか、アドバイスお願いします。
回答
-
実際にコンパイル可能でそのエラーが出るからプログラミングって難しいですよねー。ValueはMe.Valueって書くとわかりやすいですね。
SurferOnWwwさんも指摘されていますが、dtを無視してなぜかMe.Valueを見に行っているのが原因です。
Paintはヘッダも含めてすべてのセルで呼び出されますが、Paint引数で渡されるrowIndexと、自分のインスタンスのプロパティのRowIndexが一致するとは限らないようです。つまり、このときrowIndexは1とかが渡されてきても、Paintを実行しているのはRowIndex=-1である可能性がある。そのとき、ToYYYYMMDDでMe.Valueを参照したら当然エラーになります。
- 回答としてマーク TI-cb400 2014年9月4日 7:11
-
ToYYYYMMDDのバグです。
DataGridViewのSelectionModeによってエラーになったりならなかったりするようで、初期状態だとエラーにならなかったようです。
あと、他の所にもSelectionModeの影響があったので修正です。#Me.Valueを参照してしまっているのは別関数に切り出した時に変更し忘れたのだと思う。
Imports System.Globalization Imports System.Windows.Forms Public Class Form1 Inherits Form Public Sub New() Me.InitializeComponent() Dim dt As New DataTable dt.Columns.Add("Column1", GetType(DateTime)) dt.Rows.Add(DateTime.Now()) Dim grid As New DataGridView() Dim dgvclm As New DataGridViewTextBoxColumn() dgvclm.DataPropertyName = "Column1" dgvclm.CellTemplate = New DGVWarekiTextBoxCell() grid.Columns.Add(dgvclm) grid.DataSource = dt grid.Dock = DockStyle.Fill Me.Controls.Add(grid) dgvclm.SortMode = DataGridViewColumnSortMode.NotSortable grid.SelectionMode = DataGridViewSelectionMode.FullColumnSelect 'grid.SelectionMode = DataGridViewSelectionMode.FullRowSelect End Sub Friend Class DGVWarekiTextBoxCell Inherits DataGridViewTextBoxCell Shared Sub New() jpcul = New CultureInfo("ja-jp", True) jpcul.DateTimeFormat.Calendar = New JapaneseCalendar() End Sub Private Shared jpcul As CultureInfo Protected Overrides Function GetFormattedValue(ByVal value As Object _ , ByVal rowIndex As Integer _ , ByRef cellStyle As DataGridViewCellStyle _ , ByVal valueTypeConverter As System.ComponentModel.TypeConverter _ , ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter _ , ByVal context As DataGridViewDataErrorContexts) As Object If value Is Nothing OrElse value Is DBNull.Value Then Return String.Empty End If Dim dt As DateTime = CType(value, DateTime) Try Return dt.ToString("ggyy年MM月dd日", jpcul) Catch Me.ErrorText = "日付が和暦に変換できません" Return dt.ToLongDateString() End Try End Function Public Overrides Function ParseFormattedValue(ByVal formattedValue As Object _ , ByVal cellStyle As DataGridViewCellStyle _ , ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter _ , ByVal valueTypeConverter As System.ComponentModel.TypeConverter) As Object Dim ret As Object Me.ErrorText = String.Empty '編集で入力された文字列をDateTimeに変換 Dim dt As DateTime Dim str As String = CType(formattedValue, String).Trim() If (String.IsNullOrEmpty(str)) Then ret = DBNull.Value ElseIf ((Char.IsNumber(str.Chars(0)) AndAlso DateTime.TryParseExact(str, "yyyy/M/d", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AllowWhiteSpaces, dt)) _ OrElse DateTime.TryParse(str, jpcul, DateTimeStyles.AllowWhiteSpaces, dt)) Then ret = dt Else Const errmsg As String = "日付形式で入力をして下さい" & vbCrLf & "2009/1/1 又はH21/1/1" 'Dim ex As New ApplicationException(errmsg) 'MyBase.RaiseDataError(New DataGridViewDataErrorEventArgs(ex, Me.ColumnIndex, Me.RowIndex, DataGridViewDataErrorContexts.Parsing)) Me.ErrorText = errmsg '@2014/9/4 'SelectionModeがFullRowSelect,FullColumnSelectの場合に '起動直後にCells(0,0)に日付に変換できない文字を入れるとRowIndexに-1が入った状態になっている 'その状態でGetValueを行うとエラーになる 'ret = MyBase.GetValue(RowIndex) If (RowIndex >= 0) Then ret = MyBase.GetValue(RowIndex) Else ret = DBNull.Value End If End If Return ret End Function Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer _ , ByVal initialFormattedValue As Object _ , ByVal dataGridViewCellStyle As DataGridViewCellStyle) '編集する時は元データを西暦で表示 '2014/9/4 'ここでRowIndexが-1はありえないと思うけど念のため If (rowIndex >= 0) Then Dim value As Object = MyBase.GetValue(rowIndex) If value Is Nothing OrElse value Is DBNull.Value Then value = String.Empty Else value = ToYYYYMMDD(CType(value, DateTime)) End If End If MyBase.InitializeEditingControl(rowIndex, Value, dataGridViewCellStyle) End Sub Protected Overrides Sub Paint(ByVal graphics As System.Drawing.Graphics, ByVal clipBounds As System.Drawing.Rectangle _ , ByVal cellBounds As System.Drawing.Rectangle, ByVal rowIndex As Integer _ , ByVal cellState As DataGridViewElementStates, ByVal value As Object _ , ByVal formattedValue As Object, ByVal errorText As String _ , ByVal cellStyle As DataGridViewCellStyle, ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle _ , ByVal paintParts As DataGridViewPaintParts) If ((cellState And DataGridViewElementStates.Selected) = DataGridViewElementStates.Selected) _ AndAlso value IsNot Nothing AndAlso value IsNot DBNull.Value Then 'AndAlso rowIndex >= 0 Then '選択されているセルは西暦表示させる formattedValue = ToYYYYMMDD(CType(value, DateTime)) End If MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts) End Sub Private Function ToYYYYMMDD(ByVal dt As DateTime) As String '@2014/9/4 'dtを使わずにMe.Valueを間違えて使ってたバグ 'SelectionModeがFullRowSelect,FullColumnSelectの場合にMe.RowIndex=1になっていることがあって、Me.Valueがないことがある 'Return CType(Value, DateTime).ToString("yyyy/MM/dd") Return CType(dt, DateTime).ToString("yyyy/MM/dd") End Function End Class End Class
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク TI-cb400 2014年9月4日 7:11
すべての返信
-
前のスレッドを見ましたけど、結局最終的にどうしたのか分かりません。
clsDGVWarekiTextBoxCell.ToYYYYMMDD というのも意味不明です。その前のスレッド、その前の前のスレッドと、ずっと遡って行けば分かるかもしれませんが、それを回答者に求めるのは間違ってます。
今のコードがどうなっているのか、書いてください。
【追伸】
それから、質問者さんの開発環境も書いてください。(前のスレッドを見れば分かるとは言わないでくださいね)
- 編集済み SurferOnWww 2014年9月4日 1:29 追伸追記
-
ご回答有難うございます。
前回の質問のスレッド自体も間違えておりました。
下記のコードを利用しております。
Public Class ExDataGridViewWarekiTextBoxColumn
Inherits System.Windows.Forms.DataGridViewTextBoxColumn
Public Sub New()
MyBase.New()
Me.CellTemplate = New clsDGVWarekiTextBoxCell
End Sub
End ClassImports System.Globalization
Imports System.Windows.Forms
Public Class clsDGVWarekiTextBoxCell
Inherits DataGridViewTextBoxCell
Shared Sub New()
jpcul = New CultureInfo("ja-jp", True)
jpcul.DateTimeFormat.Calendar = New JapaneseCalendar()
End Sub
Private Shared jpcul As CultureInfo
Protected Overrides Function GetFormattedValue(ByVal value As Object _
, ByVal rowIndex As Integer _
, ByRef cellStyle As DataGridViewCellStyle _
, ByVal valueTypeConverter As System.ComponentModel.TypeConverter _
, ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter _
, ByVal context As DataGridViewDataErrorContexts) As Object
If value Is Nothing OrElse value Is DBNull.Value Then
Return String.Empty
End If
Dim dt As DateTime = CType(value, DateTime)
Try
Return dt.ToString("ggyy年MM月dd日", jpcul)
Catch
Me.ErrorText = "日付が和暦に変換できません"
Return dt.ToLongDateString()
End Try
End Function
Public Overrides Function ParseFormattedValue(ByVal formattedValue As Object _
, ByVal cellStyle As DataGridViewCellStyle _
, ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter _
, ByVal valueTypeConverter As System.ComponentModel.TypeConverter) As Object
Dim ret As Object
Me.ErrorText = String.Empty
'編集で入力された文字列をDateTimeに変換
Dim dt As DateTime
Dim str As String = CType(formattedValue, String).Trim()
If (String.IsNullOrEmpty(str)) Then
ret = DBNull.Value
ElseIf ((Char.IsNumber(str.Chars(0)) AndAlso DateTime.TryParseExact(str, "yyyy/M/d", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AllowWhiteSpaces, dt)) _
OrElse DateTime.TryParse(str, jpcul, DateTimeStyles.AllowWhiteSpaces, dt)) Then
ret = dt
Else
Const errmsg As String = "日付形式で入力をして下さい" & vbCrLf & "2009/1/1 又はH21/1/1"
'Dim ex As New ApplicationException(errmsg)
'MyBase.RaiseDataError(New DataGridViewDataErrorEventArgs(ex, Me.ColumnIndex, Me.RowIndex, DataGridViewDataErrorContexts.Parsing))
Me.ErrorText = errmsg
ret = MyBase.GetValue(RowIndex)
End If
Return ret
End Function
Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer _
, ByVal initialFormattedValue As Object _
, ByVal dataGridViewCellStyle As DataGridViewCellStyle)
If rowIndex = -1 Then
Exit Sub
Else
'編集する時は元データを西暦で表示
Dim value As Object = MyBase.GetValue(rowIndex)
If value Is Nothing OrElse value Is DBNull.Value Then
value = String.Empty
Else
value = ToYYYYMMDD(CType(value, DateTime))
End If
MyBase.InitializeEditingControl(rowIndex, value, dataGridViewCellStyle)
End If
End Sub
Protected Overrides Sub Paint(ByVal graphics As System.Drawing.Graphics, ByVal clipBounds As System.Drawing.Rectangle _
, ByVal cellBounds As System.Drawing.Rectangle, ByVal rowIndex As Integer _
, ByVal cellState As DataGridViewElementStates, ByVal value As Object _
, ByVal formattedValue As Object, ByVal errorText As String _
, ByVal cellStyle As DataGridViewCellStyle, ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle _
, ByVal paintParts As DataGridViewPaintParts)
If ((cellState And DataGridViewElementStates.Selected) = DataGridViewElementStates.Selected) _
AndAlso value IsNot Nothing AndAlso value IsNot DBNull.Value Then
'選択されているセルは西暦表示させる
formattedValue = ToYYYYMMDD(CType(value, DateTime))
End If
MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)
End Sub
Private Function ToYYYYMMDD(ByVal dt As DateTime) As String
Return CType(Value, DateTime).ToString("yyyy/MM/dd")
End Function
End Class
で、一番下の
Function ToYYYYMMDD
のところで、エラーとなっていまいます。現状の対処としては、質問の最後のところでも記載をしましたが、上記のコードにて
DataGridViewのColumnTypeで和暦表示用のテキストボックスが使用できるようになったので、
こちらを使用しているのですが、このテキストボックスがDataGridViewの最初の列になると
エラーになってしまうので、別の列が最初の列になるように順序を変えて、表示をするようにしております。よろしく御願い致します。
-
> で、一番下の
> Function ToYYYYMMDD
> のところで、エラーとなっていまいます。そのコードは正しいのでしょうか? Value は何処から来てるのですか? 引数の dt はどうしたんですか? そもそもそのコードのその場所で "System.ArgumentOutOfRangeException:指定された引数は、有効な値の範囲内にありません。" というエラーが起こるとは思えませんが?
そこを見ただけで自分の頭がコンパイルエラーになって思考停止してしまいました。(正直に言えば、それ以上見る気がしなくなりました。)
たぶん間違っているんだと思いますが、もしそうなら、少なくともコードは一字一句間違えないようにしてください。
【追伸】
それから、質問者さんの開発環境も書いてください。(前のスレッドを見れば分かるとは言わないでくださいね)
- 編集済み SurferOnWww 2014年9月4日 2:22 追伸追加
-
実際にコンパイル可能でそのエラーが出るからプログラミングって難しいですよねー。ValueはMe.Valueって書くとわかりやすいですね。
SurferOnWwwさんも指摘されていますが、dtを無視してなぜかMe.Valueを見に行っているのが原因です。
Paintはヘッダも含めてすべてのセルで呼び出されますが、Paint引数で渡されるrowIndexと、自分のインスタンスのプロパティのRowIndexが一致するとは限らないようです。つまり、このときrowIndexは1とかが渡されてきても、Paintを実行しているのはRowIndex=-1である可能性がある。そのとき、ToYYYYMMDDでMe.Valueを参照したら当然エラーになります。
- 回答としてマーク TI-cb400 2014年9月4日 7:11
-
ToYYYYMMDDのバグです。
DataGridViewのSelectionModeによってエラーになったりならなかったりするようで、初期状態だとエラーにならなかったようです。
あと、他の所にもSelectionModeの影響があったので修正です。#Me.Valueを参照してしまっているのは別関数に切り出した時に変更し忘れたのだと思う。
Imports System.Globalization Imports System.Windows.Forms Public Class Form1 Inherits Form Public Sub New() Me.InitializeComponent() Dim dt As New DataTable dt.Columns.Add("Column1", GetType(DateTime)) dt.Rows.Add(DateTime.Now()) Dim grid As New DataGridView() Dim dgvclm As New DataGridViewTextBoxColumn() dgvclm.DataPropertyName = "Column1" dgvclm.CellTemplate = New DGVWarekiTextBoxCell() grid.Columns.Add(dgvclm) grid.DataSource = dt grid.Dock = DockStyle.Fill Me.Controls.Add(grid) dgvclm.SortMode = DataGridViewColumnSortMode.NotSortable grid.SelectionMode = DataGridViewSelectionMode.FullColumnSelect 'grid.SelectionMode = DataGridViewSelectionMode.FullRowSelect End Sub Friend Class DGVWarekiTextBoxCell Inherits DataGridViewTextBoxCell Shared Sub New() jpcul = New CultureInfo("ja-jp", True) jpcul.DateTimeFormat.Calendar = New JapaneseCalendar() End Sub Private Shared jpcul As CultureInfo Protected Overrides Function GetFormattedValue(ByVal value As Object _ , ByVal rowIndex As Integer _ , ByRef cellStyle As DataGridViewCellStyle _ , ByVal valueTypeConverter As System.ComponentModel.TypeConverter _ , ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter _ , ByVal context As DataGridViewDataErrorContexts) As Object If value Is Nothing OrElse value Is DBNull.Value Then Return String.Empty End If Dim dt As DateTime = CType(value, DateTime) Try Return dt.ToString("ggyy年MM月dd日", jpcul) Catch Me.ErrorText = "日付が和暦に変換できません" Return dt.ToLongDateString() End Try End Function Public Overrides Function ParseFormattedValue(ByVal formattedValue As Object _ , ByVal cellStyle As DataGridViewCellStyle _ , ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter _ , ByVal valueTypeConverter As System.ComponentModel.TypeConverter) As Object Dim ret As Object Me.ErrorText = String.Empty '編集で入力された文字列をDateTimeに変換 Dim dt As DateTime Dim str As String = CType(formattedValue, String).Trim() If (String.IsNullOrEmpty(str)) Then ret = DBNull.Value ElseIf ((Char.IsNumber(str.Chars(0)) AndAlso DateTime.TryParseExact(str, "yyyy/M/d", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AllowWhiteSpaces, dt)) _ OrElse DateTime.TryParse(str, jpcul, DateTimeStyles.AllowWhiteSpaces, dt)) Then ret = dt Else Const errmsg As String = "日付形式で入力をして下さい" & vbCrLf & "2009/1/1 又はH21/1/1" 'Dim ex As New ApplicationException(errmsg) 'MyBase.RaiseDataError(New DataGridViewDataErrorEventArgs(ex, Me.ColumnIndex, Me.RowIndex, DataGridViewDataErrorContexts.Parsing)) Me.ErrorText = errmsg '@2014/9/4 'SelectionModeがFullRowSelect,FullColumnSelectの場合に '起動直後にCells(0,0)に日付に変換できない文字を入れるとRowIndexに-1が入った状態になっている 'その状態でGetValueを行うとエラーになる 'ret = MyBase.GetValue(RowIndex) If (RowIndex >= 0) Then ret = MyBase.GetValue(RowIndex) Else ret = DBNull.Value End If End If Return ret End Function Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer _ , ByVal initialFormattedValue As Object _ , ByVal dataGridViewCellStyle As DataGridViewCellStyle) '編集する時は元データを西暦で表示 '2014/9/4 'ここでRowIndexが-1はありえないと思うけど念のため If (rowIndex >= 0) Then Dim value As Object = MyBase.GetValue(rowIndex) If value Is Nothing OrElse value Is DBNull.Value Then value = String.Empty Else value = ToYYYYMMDD(CType(value, DateTime)) End If End If MyBase.InitializeEditingControl(rowIndex, Value, dataGridViewCellStyle) End Sub Protected Overrides Sub Paint(ByVal graphics As System.Drawing.Graphics, ByVal clipBounds As System.Drawing.Rectangle _ , ByVal cellBounds As System.Drawing.Rectangle, ByVal rowIndex As Integer _ , ByVal cellState As DataGridViewElementStates, ByVal value As Object _ , ByVal formattedValue As Object, ByVal errorText As String _ , ByVal cellStyle As DataGridViewCellStyle, ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle _ , ByVal paintParts As DataGridViewPaintParts) If ((cellState And DataGridViewElementStates.Selected) = DataGridViewElementStates.Selected) _ AndAlso value IsNot Nothing AndAlso value IsNot DBNull.Value Then 'AndAlso rowIndex >= 0 Then '選択されているセルは西暦表示させる formattedValue = ToYYYYMMDD(CType(value, DateTime)) End If MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts) End Sub Private Function ToYYYYMMDD(ByVal dt As DateTime) As String '@2014/9/4 'dtを使わずにMe.Valueを間違えて使ってたバグ 'SelectionModeがFullRowSelect,FullColumnSelectの場合にMe.RowIndex=1になっていることがあって、Me.Valueがないことがある 'Return CType(Value, DateTime).ToString("yyyy/MM/dd") Return CType(dt, DateTime).ToString("yyyy/MM/dd") End Function End Class End Class
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク TI-cb400 2014年9月4日 7:11