投稿者 るきお  (社会人) 投稿日時 2018/6/6 07:28:19
できるだけ近い構造で実現しようとするとこのようになります。

Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown

    'ShownはForm1が初めて表示されるときに1回だけ実行されます。 
    'このタイミングでPictureBoxとBitmapを関連付けます。 

    '引数は描画領域の幅と高さ 
    canvas = New Bitmap(PictureBox1.Width, PictureBox1.Height)
    PictureBox1.Image = canvas

End Sub

Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click
    '関連付けられたBitmapに描画します。 
    Dim g As Graphics = Graphics.FromImage(canvas)
    g.DrawLine(Pens.Black, a, b, c, d)

    'Bitmapの内容が変わってもPictureBox1は自動的に気が付いてくれないので、 
    '一旦現状の表示をリセットして関連付けられたBitmapを表示してもらいます。 
    PictureBox1.Invalidate()
End Sub


ゆうさくさんのプログラムでは、canvasとPictureBoxが関連付けられていないため、canvasに描画してもPicturBoxは無反応です。
g.DrawLineのすぐ下に次の行を挿入すると線は描かれます。
PictureBox1.Image = canvas

でも、Form1のPaintイベントにプログラムが書かれているので、ボタンのクリック時ではなく、フォームの描画時に実行されてしまいます。
また、フォームの描画時に毎回canvasを生成してPictureBoxと関連付けるのは非効率です。
これらを改善すると上記のようになります。

なお、下記のような作り方もあります。
Private Lines As New List(Of Rectangle)

Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click
    Lines.Add(New Rectangle(a, b, c, d))
    PictureBox1.Invalidate()
End Sub

Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint

    For Each line As Rectangle In Lines
        e.Graphics.DrawLine(Pens.Black, line.X, line.Y, line.X + line.Width, line.Y + line.Height)
    Next

End Sub


このプログラムはPictureBoxの描画にPictureBoxのPaintイベントを使用しており素直な作りです。
このつくりの良いところは、ボタンを押すたびにまっさらなところから描画を開始するので(といって人間には一瞬のできごとです)、動的に変化する図形を描画しやすいことです。
たとえば、マウスやキーボードなどの操作に追従してグラフィックスが変化していく場合は、こちらの作りの方がやりやすいです。