wrongwrongな開発日記

しんまいさんの忘備録

【VB】MsgBoxを処理を止めずに出す【.Net】

簡易まとめ

Taskを使えば以下のコードで出来ます。処理を止めずにMsgBoxを出し、メッセージボックスのリザルトを受け取ることも出来ます(後述)。

Task.Run(Sub()
             MsgBox("Async")
         End Sub)

やること

WindowsフォームアプリではMsgBoxを用いてメッセージを伝える場面が有りますが、メッセージを出した場合そのメッセージが消えるまで処理が止まるため困る場面が有ります。
対処法をググると『応答不要のメッセージボックスを出したい』などがヒットしますが、情報が古かったのでTaskを使ったやり方を書きます。

普通にやると

以下のコードでは、MsgBoxのOKを押さなければForm1が表示されません。

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        MsgBox("normal")
    End Sub
End Class
Taskを使う

以下のコードではForm1のロード時にMsgBoxを出し、かつ回答無しでForm1が立ち上がります。

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Task.Run(Sub()
                     MsgBox("Async")
                 End Sub)
    End Sub
End Class

応用

以下は応用です。

別の場所で閉じられるのを待つ

タスクを共有することで、メッセージボックスが閉じられなければ諸々を操作できないようにすることも出来ます。
以下のコードではボタン1を押したときはTaskが完了している(=MsgBoxが閉じられている)かを見てメッセージを、ボタン2を押した場合Taskが完了するまで待ってからメッセージを出しています。

Public Class Form1
    Private tsk As Task = Nothing

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        tsk = Task.Run(Sub()
                           MsgBox("Async")
                       End Sub)
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim str = If(tsk.IsCompleted, "ボックスは閉じています", "ボックスは開いています")
        MsgBox(str)
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        tsk.Wait()
        MsgBox("ボックスが閉じられました")
    End Sub
End Class
回答を受け取る

Taskを使った上で回答を受け取る場合は以下のように行います。
Task.ResultはTask#Waitを呼び出すのと同様にTaskが完了するまで待った上で値を入れ、処理を行ってくれます。

Public Class Form1
    Private tsk As Task(Of MsgBoxResult) = Nothing

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        tsk = Task.Run(Function() As MsgBoxResult
                           Return MsgBox("Async", MsgBoxStyle.OkCancel)
                       End Function)
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        MsgBox(tsk.Result.ToString)
    End Sub
End Class