[VB.NET] ワーカースレッドから コントロール(UI スレッド)へのアクセス その1

2013年8月29日

 たとえばワーカースレッドを作って、ワーカースレッド上で重い処理を走らせ、その結果をコントロールに表示させようとします。

Private Sub Button1_Click(...
    Dim t = New Threading.Thread(AddressOf worker1)
    t.Start()
End Sub

Sub worker1()
    ' 重い処理(略)

    ' 重い処理の結果を書く
    Button1.Text = Now.ToString ' エラーになる
End Sub

 ところが、これはエラーになります。コントロールへのアクセスは UI スレッドからしかアクセスできないためです。

System.InvalidOperationException が発生しました。
有効ではないスレッド間の操作:
コントロールが作成されたスレッド以外のスレッドからコントロール 'Button1' がアクセスされました。

 これを回避するためには、ワーカースレッドから UI スレッドに処理をお願い(Invoke)する必要があります。

 ところが、この UI スレッドにお願いする方法が、使用するアプリケーションプラットホームによって書き方が異なります。
 以下列挙。

  1. Windwos Forms の場合

     Me.BeginInvoke、または Me.Invoke を使用します。
     Control クラスのメソッドのようなので、Button.Invoke でも可能ですが、Me(=Form)でいいと思います。

    Sub worker1()
        Me.BeginInvoke( _
            Sub()
                Button1.Text = Date.Now.ToString
            End Sub)
    End Sub
    
  2. WPF の場合

     Application.Current.Dispatcher.BeginInvoke、または Application.Current.Dispatcher.Invoke を使用します。

    Sub worker1()
        Application.Current.Dispatcher.BeginInvoke( _
            Sub()
                Button1.Content = Date.Now.ToString
            End Sub)
    End Sub
    
  3. Windows Phone(Silverlight系)の場合

     Deployment.Current.Dispatcher.BeginInvoke を使います。 Silverlight 系は Invoke はないみたいですね。

    Sub worker1()
        Deployment.Current.Dispatcher.BeginInvoke( _
            Sub()
                Button1.Content = Date.Now.ToString
            End Sub)
    End Sub
    
  4. WinRT(ストアアプリ系)の場合

     Me.Dispatcher.RunAsync を使います。
     "Dim dummy =" はコンパイラーの警告回避用です(汗

    Sub worker1()
        Dim dummy = Me.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, _
                               Sub()
                                   Button1.Content = Date.Now.ToString
                               End Sub)
    End Sub
    

     Invoke 相当の動作にするためには、"Dim dummy =" の部分を "Await" に変えるか、次の行に "Await dummy" を追加して待たせます。
     以下は "Await dummy" を追加してみた例。(Sub のところの Async も忘れずに)

    Async Sub worker1()
        Dim dummy = Me.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, _
                               Sub()
                                   Button1.Content = Date.Now.ToString
                               End Sub)
        Await dummy
    End Sub
    

     また、ストアアプリではワーカースレッドの生成に Threading.Thread が使えないので、Threading.Tasks.Task で生成しています。

    Private Sub Button1_Click(...
        Dim t = New Threading.Tasks.Task(AddressOf worker1)
        t.Start()
    End Sub
    

1 Comment to "[VB.NET] ワーカースレッドから コントロール(UI スレッド)へのアクセス その1"

  1. [VB.NET] ワーカースレッドから コントロール(UI スレッド)へのアクセス その2 | オールトの雲

    [...] [VB.NET] ワーカースレッドから コントロール(UI スレッド)へのアクセス その1 [...]

コメントを投稿する

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


«   »
 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org