Top / .NET備忘録 / 99.小ネタ / 11.ControlProxy

.NET 移行に際し、進捗ゲージ等を、別スレッドで表示するよう修正しました。

困ったのが、別スレッドのウインドウは直接操作できず、Invoke メソッドを経由しなければならないことです。

いちいち書いてられないので透過プロキシを使います。

Imports System
Imports System.Windows.Forms
Imports System.Runtime.Remoting.Proxies
Imports System.Runtime.Remoting.Messaging
Imports System.Reflection

Public Class ControlProxy
    Inherits RealProxy

    Private _Target As Control

    Private Sub New(target As Control)
        MyBase.New(target.GetType())
        _Target = target
    End Sub

    Public Overrides Function Invoke(msg As IMessage) As IMessage
        Try
            Dim mm As IMethodMessage = TryCast(msg, IMethodMessage)
            Dim args As Object() = mm.Args
            Dim method As MethodInfo = DirectCast(mm.MethodBase, MethodInfo)
            Dim ret As Object
            If _Target.InvokeRequired Then
                Dim d As ControlDelegate = AddressOf ControlInvoke
                ret = _Target.Invoke(d, method, args)
            Else
                ret = method.Invoke(_Target, args)
            End If
            Return New ReturnMessage(ret, args, args.Length, mm.LogicalCallContext, DirectCast(msg, IMethodCallMessage))
        Catch ex As Exception
            If ex.InnerException IsNot Nothing Then
                Return New ReturnMessage(ex.InnerException, DirectCast(msg, IMethodCallMessage))
            End If
            Return New ReturnMessage(ex, DirectCast(msg, IMethodCallMessage))
        End Try
    End Function

    Delegate Function ControlDelegate(ByVal mi As MethodInfo, ByVal arg As Object()) As Object

    Private Function ControlInvoke(ByVal mi As MethodInfo, ByVal arg As Object()) As Object
        Return mi.Invoke(_Target, arg)
    End Function

    Public Shared Function CreateTransparentProxy(Of T As Control)(ByVal obj As T) As T
        Dim proxy As New ControlProxy(obj)
        Return DirectCast(proxy.GetTransparentProxy(), T)
    End Function

End Class

使い方はこんな感じになります。

Imports System.Threading

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim th As New Thread(New ParameterizedThreadStart(AddressOf OtherThread))
        th.SetApartmentState(ApartmentState.STA)
        Dim proxy As Form1 = ControlProxy.CreateTransparentProxy(Me)
        th.Start(proxy) ' Me を渡すとエラーが発生する
    End Sub

    Public Sub HogeHoge()
        MessageBox.Show(Me, "ほげほげ")
    End Sub

    Private Sub OtherThread(ByVal obj As Object)
        Dim parentForm As Form1 = DirectCast(obj, Form1)
        parentForm.HogeHoge() ' 他スレッドから HogeHoge メソッドを呼び出す
    End Sub

End Class



トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   最終更新のRSS
Last-modified: 2016-03-07 (月) 17:32:25 (648d)