none
VB,カスタム(自作)コンボボックスで一部エラーが出ます。  RRS feed

  • 質問

  • VB2010Express, サーバーSQL2000使用です。 カスタムコンボボックスを作成しました、ツールボックスに追加表示され、フォームへのドラッグも正常です。

    しかし、このコード内の(A)で、エラー表示がでます。 

    それで、(B)のように書き換えました。 すると下記のエラー表示がでます。

    「'name' 引数を Null にすることはできません。警告 1 変数 'ItemString1' は、値が割り当てられる前に使用されています。Null 参照の例外が実行時に発生する可能性があります。」

    どのように修正したらよいのでしょうか?

    Yksaila

    以下は、コードです;

    Imports System.ComponentModel
    Public Class MyComboBox
        Inherits ComboBox

        Public ListMember1 As String
        Public ListMember2 As String

        Private Const ListWidth1 As Integer = 30
        Private Const ListWidth2 As Integer = 100

        Public Sub New()

            Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawFixed
            Me.DropDownWidth = ListWidth1 + ListWidth2 + 20

        End Sub
        Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)

            '▼データの内容を取得
            Dim Row As DataRowView
            Dim ItemString1 As String
            Dim ItemString2 As String

            Row = DirectCast(Me.Items(e.Index), DataRowView)
            'ItemString1 = DirectCast(Row(ListMember1), String) ----(B)
            'ItemString2 = DirectCast(Row(ListMember2), String) ----(B)
            ItemString1 = Row(ListMember1)   ’(A)------エラー 1 Option Strict On で 'Object' から 'String' への暗黙的な変換はできません。 
            ItemString2 = Row(ListMember2)   ’(A)------エラー 1 Option Strict On で 'Object' から 'String' への暗黙的な変換はできません。
           
            '▼項目と線を描画
            Dim Rect As RectangleF
            Dim myBrush As Brush
            Dim LineLeft As Integer = e.Bounds.X + ListWidth1

            If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
                myBrush = New SolidBrush(Color.White)
            Else
                myBrush = New SolidBrush(Me.ForeColor)
            End If

            '背景
            e.DrawBackground()

            'コード
            Rect = New RectangleF(e.Bounds.X, e.Bounds.Y, LineLeft, e.Bounds.Height)
            e.Graphics.DrawString(ItemString1, e.Font, myBrush, Rect)

            '区切り線
            e.Graphics.DrawLine(Pens.Black, LineLeft, e.Bounds.Y, LineLeft, e.Bounds.Y + e.Bounds.Height)

            '名前
            Rect = New RectangleF(LineLeft + 1, e.Bounds.Y, e.Bounds.Width - LineLeft - 1, e.Bounds.Height)
            e.Graphics.DrawString(ItemString2, e.Font, myBrush, Rect)
            e.DrawFocusRectangle()
            e.Graphics.Flush()

        End Sub

    End Class

    2012年6月16日 5:31

回答

  •  「null にすることはできません」というメッセージの通り、何かを指定しなければならないところが null(VB では Nothing)なのです。このコードがいつ通るのか。その時、各変数の値がどのようになっているのか、トレースしてみてください。というか、エラーが出てきている行の変数のうちいずれか、なわけですが。


    Jitta@わんくま同盟

    • 回答としてマーク yksaila 2012年7月25日 3:37
    2012年6月16日 11:02
  • jitta さんの意図的に書かなかった事に反してしまうかと思いますが、
    状況変わって無かったらあれなので・・・

    ListMember1 及び ListMember2 に値が入るのはいつですか?
    上記の変数がNothingの状態でOnDrawItemイベントが発生するケースはありませんか?

    • 回答としてマーク yksaila 2012年7月25日 3:37
    2012年6月18日 0:03
  • Jittaさんへ

    ありがとうございます。 "後回しにしないで、まず解決したらどうですか !" という意味に、私は理解しましたので、やってみました。

    最後に、うまく作動したコードを載せます。 欠点・問題点は、あるかもしれませんが。

    >「作る」という作業を何か勘違いされていませんか? ソフトウェアというのは実体がないからか、とても簡単に作れると思っている方が多いように思います。しかし、本当のところは、>とても難しいものなのです。

    いえ、大丈夫です。 勘違いはしていないと、思います。 作成が難しく大変な作業なのは、承知しています。 これを、一般(?)の人が誤解しているのも承知しています。 「普通、これは簡単だろう、2、3行書けば、終わるだろう」 と、一般人(?)が感じることが、逆にソフト作成では非常に大変だということも、経験しています。 私は、本職ではないですが、会社で使用するソフト作成が未経験なわけではありません。 少しは作成しましたので、ソフト作成の大変さが普通の人には理解されにくいのも、経験済みです。 この理解されないという事実は、ソフト作成者にとっては、理不尽と言えるかもしれないですね。

    >この説明書を作る作業を「設計」と呼ぶ場合があります。説明書に書き出す書き出さないは別として、「設計」という作業は必ず必要です。

    設計が重要・かつ不可欠なのも承知しています。 これができたら、ソフト作成はほぼ終わりだということも、どこかで聞いたことがあります。 でも、私はまだ、この段階には達していないかもしれないですが。 

    今後とも、よろしく、ご指導をお願いします。

    Yksaila

    以下は、作成コードです(一応うまくいっています):

    Imports System.ComponentModel

    Public Class MyComboBox
        Inherits ComboBox

        ' Public ListMember1 As String   '以前は、Publicだったけど、Privateで良い? → 不要なので消去、使用しない
        ' Public ListMember2 As String   '以前は、Publicだったけど、Privateで良い? → 不要なので消去、使用しない

        Private Const ListWidth1 As Integer = 50
        Private Const ListWidth2 As Integer = 80

        Public Sub New()

            Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawFixed
            Me.DropDownWidth = ListWidth1 + ListWidth2 + 20

        End Sub
        Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)

            'SQL認証接続
            Dim St As String
            Dim Con As New System.Data.SqlClient.SqlConnection
            Dim SQL As System.Data.SqlClient.SqlCommand
            Dim ServerName As String = "******"   'サーバー名(またはIPアドレス)
            Dim UserID As String = "*****"      'ユーザーID
            Dim Password As String = "*****"   'パスワード
            Dim DatabaseName As String = "******"
            St = "Server=" & ServerName & ";"
            St &= "User ID=" & UserID & ";"
            St &= "Password=" & Password & ";"
            St &= "Initial Catalog=" & DatabaseName
            Con.ConnectionString = St
            SQL = Con.CreateCommand
            Con.Open()

            Dim adapter = New SqlClient.SqlDataAdapter()
            ' Dim foundrows() As Data.DataRow
            'コンボボックス:T_M_Area ----コンボボックス表示準備(CB_Area_ID)
            Dim dsCombo4 = New DataSet
            Dim sqCombo4 As String
            sqCombo4 = "SELECT T_M_Area.Area_ID, T_M_Area.AreaCode, T_M_Area.AreaName FROM T_M_Area ORDER BY T_M_Area.Indication"
            adapter.SelectCommand = New SqlClient.SqlCommand(sqCombo4, Con)
            adapter.SelectCommand.CommandType = CommandType.Text
            adapter.Fill(dsCombo4)
            Dim dtCombo4 As New DataTable
            dtCombo4 = dsCombo4.Tables(0)

            Dim MyComboBox1 As MyComboBox = New MyComboBox
            '自作コンボボックス:MyComboBox1 ----コンボボックス表示準備(MyComboBox1)
            MyComboBox1.DataSource = dtCombo4
            MyComboBox1.DisplayMember = "AreaName"
            MyComboBox1.ValueMember = "Area_ID"
            MyComboBox1.DropDownStyle = ComboBoxStyle.DropDown
            '
            '▼データの内容を取得
            Dim Row As DataRowView
            Dim ItemString1 As String  'ここをIntegerにすると、下の ”ItemString1 = MyComboBox1.ValueMember”がエラーになる。
            Dim ItemString2 As String

            'Try
            Row = DirectCast(Me.Items(e.Index), DataRowView)
            ItemString1 = MyComboBox1.ValueMember
            ItemString2 = MyComboBox1.DisplayMember

            ItemString1 = Row(ItemString1).ToString  '*****
            'ItemString1 = DirectCast(Row(ItemString1), Integer)  'これは、エラー表示になる。
            ItemString2 = DirectCast(Row(ItemString2), String)

            '▼項目と線を描画
            Dim Rect As RectangleF
            Dim myBrush As Brush
            Dim LineLeft As Integer = e.Bounds.X + ListWidth1

            If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
                myBrush = New SolidBrush(Color.White)
            Else
                myBrush = New SolidBrush(Me.ForeColor)
            End If

            '背景
            e.DrawBackground()

            'コード
            Rect = New RectangleF(e.Bounds.X, e.Bounds.Y, LineLeft, e.Bounds.Height)
            e.Graphics.DrawString(ItemString1, e.Font, myBrush, Rect)
            'e.DrawFocusRectangle() '追加? →不要
            'e.Graphics.Flush()   '追加? →不要

            '区切り線
            e.Graphics.DrawLine(Pens.Black, LineLeft, e.Bounds.Y, LineLeft, e.Bounds.Y + e.Bounds.Height)

            '名前
            Rect = New RectangleF(LineLeft + 1, e.Bounds.Y, e.Bounds.Width - LineLeft - 1, e.Bounds.Height)
            e.Graphics.DrawString(ItemString2, e.Font, myBrush, Rect)
            e.DrawFocusRectangle()
            e.Graphics.Flush()

            'Catch ex As Exception
            'End Try

            Con.Close()

            '▼後処理,追加-2012/04/16)
            dtCombo4.Dispose()
            adapter.Dispose()
            SQL.Dispose()
            Con.Dispose()


        End Sub


    End Class





    • 編集済み yksaila 2012年7月31日 7:59
    • 回答としてマーク yksaila 2012年7月31日 10:10
    2012年7月31日 7:54

すべての返信

  •  「null にすることはできません」というメッセージの通り、何かを指定しなければならないところが null(VB では Nothing)なのです。このコードがいつ通るのか。その時、各変数の値がどのようになっているのか、トレースしてみてください。というか、エラーが出てきている行の変数のうちいずれか、なわけですが。


    Jitta@わんくま同盟

    • 回答としてマーク yksaila 2012年7月25日 3:37
    2012年6月16日 11:02
  • jitta さんの意図的に書かなかった事に反してしまうかと思いますが、
    状況変わって無かったらあれなので・・・

    ListMember1 及び ListMember2 に値が入るのはいつですか?
    上記の変数がNothingの状態でOnDrawItemイベントが発生するケースはありませんか?

    • 回答としてマーク yksaila 2012年7月25日 3:37
    2012年6月18日 0:03
  • Jittaさんへ

    回答ありがとうございます。

    急に忙しくなり、中断しています。 ここを開くと、集中してしまい、他の仕事ができなくなります(おろそかになります)ので、開けていませんでした。

    今も、深く読んでいない状況です。 読むと、他へいけなくなりますから。 今やっていることが一段落しましたら、集中して取り組みます。

    復帰は、来週の後半か7月初めに、なるかもしれません。

    その時は、よろしくお願いします。

    YKsaila

    2012年6月24日 2:59
  • aviator_さんへ

    回答ありがとうございます。

    急に忙しくなり、中断しています。 ここを開くと、集中してしまい、他の仕事ができなくなります(おろそかになります)ので、開けていませんでした。

    今も、深く読んでいない状況です。 読むと、他へいけなくなりますから。 今やっていることが一段落しましたら、集中して取り組みます。

    復帰は、来週の後半か7月初めに、なるかもしれません。

    その時は、よろしくお願いします。

    YKsaila

    2012年6月24日 2:59
  • Jittaさん、aviator_さんへ

    今上記コードを読んでみますと、ListMember1 及び ListMember2 には何も指定されてないのが、分かります(なんとなく)。

    では、どのようにししたら良いのかは、まだ自分には不明です。 もう少し進歩したら出来るでしょう、多分?

    このコーナーは、質問スレッド ”VB、テキストボックスやコンボボックスへの指示を一括ですませたいのですが、うまくいきません” の関連で書いたものです。

    先のスレッド(長くなって、前篇・後編となりました)の回答は、自分なりに得られましたので、ここでの問題解決は次の機会にします。 時間が経てば、解決できるようになるでしょう。

    ありがとうございました。

    YKsaila

    2012年7月25日 3:37
  • ここでの問題解決は次の機会にします。 時間が経てば、解決できるようになるでしょう。

     ん~~~「作る」という作業を何か勘違いされていませんか?

     今のお仕事でも感じるのですが、ソフトウェアというのは実体がないからか、とても簡単に作れると思っている方が多いように思います。しかし、本当のところは、とても難しいものなのです。

     プラモデルを作ったことはありますか?プラモデルには、必ず組み立て説明書があります。いや、原型を作る人にはそんなものはないですけどね。たいていの作る作業には、「説明書」があるんです。ソフトウェアの場合、その説明書は「仕様書」と呼ばれます。仕様書には、どんな入力、出力が有り、何をどうしたらどうなると言うことが書かれています。プログラムは、その説明書に沿って作ります。

     この説明書を作る作業を「設計」と呼ぶ場合があります。説明書に書き出す書き出さないは別として、「設計」という作業は必ず必要です。この、「設計」という作業をせずに、プログラムを書こうとしているように思われます。

     「今上記コードを読んでみますと、ListMember1 及び ListMember2 には何も指定されてないのが、分かります(なんとなく)。」ということですが、次のことを明らかにして下さい。

    • ListMember1 とは何を表すものなのか。
    • ListMember1 を、どの様に使うのか。
    • ListMember1 が決まるのは何時か。
    • ListMember1 を決めるのは誰か。

     これらが決まると、どこで、どうやって設定しなければならないか、決まります。プログラムを作る作業というのは、こう言うものです。つまり、欲しい結果に対して、結果を得るために必要な項目を並べる。項目が決まる条件を調べる。条件を「欲しい結果」としてもう一度。…この繰り返しです。そしてこれは設計でもあります。つまり、アプリケーションを作る作業のほとんどは、設計することです。設計をせずに部品を並べても、それらしい形になるかもしれませんが、完成品ができるわけではありません。

     なお、Visual Studio を初めとする開発用ツールのキャッチコピーに「簡単に」という言葉があります。これは、「書く作業」が簡単になると言うことです。プログラムを作ることの本質である、欲しいものを揃える作業が簡単になるわけではありません。これを間違えている人が多くて、困る。(もちろん、揃える作業と書く作業合わせて「プログラムを作る」なのですが)


    Jitta@わんくま同盟

    2012年7月28日 5:02
  • Jittaさんへ

    ありがとうございます。 "後回しにしないで、まず解決したらどうですか !" という意味に、私は理解しましたので、やってみました。

    最後に、うまく作動したコードを載せます。 欠点・問題点は、あるかもしれませんが。

    >「作る」という作業を何か勘違いされていませんか? ソフトウェアというのは実体がないからか、とても簡単に作れると思っている方が多いように思います。しかし、本当のところは、>とても難しいものなのです。

    いえ、大丈夫です。 勘違いはしていないと、思います。 作成が難しく大変な作業なのは、承知しています。 これを、一般(?)の人が誤解しているのも承知しています。 「普通、これは簡単だろう、2、3行書けば、終わるだろう」 と、一般人(?)が感じることが、逆にソフト作成では非常に大変だということも、経験しています。 私は、本職ではないですが、会社で使用するソフト作成が未経験なわけではありません。 少しは作成しましたので、ソフト作成の大変さが普通の人には理解されにくいのも、経験済みです。 この理解されないという事実は、ソフト作成者にとっては、理不尽と言えるかもしれないですね。

    >この説明書を作る作業を「設計」と呼ぶ場合があります。説明書に書き出す書き出さないは別として、「設計」という作業は必ず必要です。

    設計が重要・かつ不可欠なのも承知しています。 これができたら、ソフト作成はほぼ終わりだということも、どこかで聞いたことがあります。 でも、私はまだ、この段階には達していないかもしれないですが。 

    今後とも、よろしく、ご指導をお願いします。

    Yksaila

    以下は、作成コードです(一応うまくいっています):

    Imports System.ComponentModel

    Public Class MyComboBox
        Inherits ComboBox

        ' Public ListMember1 As String   '以前は、Publicだったけど、Privateで良い? → 不要なので消去、使用しない
        ' Public ListMember2 As String   '以前は、Publicだったけど、Privateで良い? → 不要なので消去、使用しない

        Private Const ListWidth1 As Integer = 50
        Private Const ListWidth2 As Integer = 80

        Public Sub New()

            Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawFixed
            Me.DropDownWidth = ListWidth1 + ListWidth2 + 20

        End Sub
        Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)

            'SQL認証接続
            Dim St As String
            Dim Con As New System.Data.SqlClient.SqlConnection
            Dim SQL As System.Data.SqlClient.SqlCommand
            Dim ServerName As String = "******"   'サーバー名(またはIPアドレス)
            Dim UserID As String = "*****"      'ユーザーID
            Dim Password As String = "*****"   'パスワード
            Dim DatabaseName As String = "******"
            St = "Server=" & ServerName & ";"
            St &= "User ID=" & UserID & ";"
            St &= "Password=" & Password & ";"
            St &= "Initial Catalog=" & DatabaseName
            Con.ConnectionString = St
            SQL = Con.CreateCommand
            Con.Open()

            Dim adapter = New SqlClient.SqlDataAdapter()
            ' Dim foundrows() As Data.DataRow
            'コンボボックス:T_M_Area ----コンボボックス表示準備(CB_Area_ID)
            Dim dsCombo4 = New DataSet
            Dim sqCombo4 As String
            sqCombo4 = "SELECT T_M_Area.Area_ID, T_M_Area.AreaCode, T_M_Area.AreaName FROM T_M_Area ORDER BY T_M_Area.Indication"
            adapter.SelectCommand = New SqlClient.SqlCommand(sqCombo4, Con)
            adapter.SelectCommand.CommandType = CommandType.Text
            adapter.Fill(dsCombo4)
            Dim dtCombo4 As New DataTable
            dtCombo4 = dsCombo4.Tables(0)

            Dim MyComboBox1 As MyComboBox = New MyComboBox
            '自作コンボボックス:MyComboBox1 ----コンボボックス表示準備(MyComboBox1)
            MyComboBox1.DataSource = dtCombo4
            MyComboBox1.DisplayMember = "AreaName"
            MyComboBox1.ValueMember = "Area_ID"
            MyComboBox1.DropDownStyle = ComboBoxStyle.DropDown
            '
            '▼データの内容を取得
            Dim Row As DataRowView
            Dim ItemString1 As String  'ここをIntegerにすると、下の ”ItemString1 = MyComboBox1.ValueMember”がエラーになる。
            Dim ItemString2 As String

            'Try
            Row = DirectCast(Me.Items(e.Index), DataRowView)
            ItemString1 = MyComboBox1.ValueMember
            ItemString2 = MyComboBox1.DisplayMember

            ItemString1 = Row(ItemString1).ToString  '*****
            'ItemString1 = DirectCast(Row(ItemString1), Integer)  'これは、エラー表示になる。
            ItemString2 = DirectCast(Row(ItemString2), String)

            '▼項目と線を描画
            Dim Rect As RectangleF
            Dim myBrush As Brush
            Dim LineLeft As Integer = e.Bounds.X + ListWidth1

            If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
                myBrush = New SolidBrush(Color.White)
            Else
                myBrush = New SolidBrush(Me.ForeColor)
            End If

            '背景
            e.DrawBackground()

            'コード
            Rect = New RectangleF(e.Bounds.X, e.Bounds.Y, LineLeft, e.Bounds.Height)
            e.Graphics.DrawString(ItemString1, e.Font, myBrush, Rect)
            'e.DrawFocusRectangle() '追加? →不要
            'e.Graphics.Flush()   '追加? →不要

            '区切り線
            e.Graphics.DrawLine(Pens.Black, LineLeft, e.Bounds.Y, LineLeft, e.Bounds.Y + e.Bounds.Height)

            '名前
            Rect = New RectangleF(LineLeft + 1, e.Bounds.Y, e.Bounds.Width - LineLeft - 1, e.Bounds.Height)
            e.Graphics.DrawString(ItemString2, e.Font, myBrush, Rect)
            e.DrawFocusRectangle()
            e.Graphics.Flush()

            'Catch ex As Exception
            'End Try

            Con.Close()

            '▼後処理,追加-2012/04/16)
            dtCombo4.Dispose()
            adapter.Dispose()
            SQL.Dispose()
            Con.Dispose()


        End Sub


    End Class





    • 編集済み yksaila 2012年7月31日 7:59
    • 回答としてマーク yksaila 2012年7月31日 10:10
    2012年7月31日 7:54
  • 本題とは関係ないんだけれど、

        ' Public ListMember1 As String   '以前は、Publicだったけど、Privateで良い? → 不要なので消去、使用しない

        ' Public ListMember2 As String   '以前は、Publicだったけど、Privateで良い? → 不要なので消去、使用しない

    こういったコメントは、ToDoやHackを使うと後で探しやすくなりますよ。

    http://msdn.microsoft.com/ja-jp/library/zce12xx2(v=vs.100).aspx

    2012年7月31日 8:57