2016-09-30 15 views
0

私はWinformアプリケーションで作業して以来、私の専門はAsp.net /ウェブサイトで働いています。最近、.Net 1.1から.Net 4.6にアップグレードするためのアプリケーションが提供されました。アプリケーションは、クロススレッド操作で問題が発生しているMDIアプリケーションです。具体的には、ユーザーコントロール内のボタンイベントをクリックすると、メインMDIchildフォーム(cfrmOverview)が表示されますが、picDisplayというPictureboxコントロールにアクセスするとエラーが発生するため、エラーが発生します。追加されたコードがあっても、私はまだエラーが発生しています。 CheckForIllegalCrossThreadCallsを使用しないようにしました。これは、プログラムやMSDNでも他の部分に影響するためです。洞察力が必要です。親コントロールと子コントロールのMDIクロススレッド例外usercontrol.net 1.1から4.6へのボタン

Public Delegate Sub Mydelegate(ByVal AControl As PictureBox) 
Public Shared Sub CreateEnableControl(ByVal AControl As PictureBox) 
    AControl.Visible = True 
    AControl.Enabled = True 
End Sub 
Public Shared Sub NavigateTo(ByVal sender As System.Windows.Forms.UserControl, ByVal aNavTarget As String, Optional ByVal param As Object = Nothing) 
    Dim aType As Type 
    Dim Types() As Type 
    Dim aobject As Object 

    Try 
     If IsNothing(System.Reflection.Assembly.GetEntryAssembly) Then 
      aobject = sender.ParentForm 
      Types = System.Reflection.Assembly.GetAssembly(aobject.GetType).GetTypes 
     Else 
      Types = System.Reflection.Assembly.GetEntryAssembly.GetTypes 
     End If 
     Dim aForm As Windows.Forms.Form 
     For Each aType In Types 
      If aType.BaseType Is GetType(MdiChild) Then 
       If aType.Name = aNavTarget Then 
        Dim aMdiParent As Windows.Forms.Form 
        If TypeOf (sender.ParentForm) Is MdiParent Then 
         aMdiParent = sender.ParentForm 
        Else 
         aMdiParent = sender.ParentForm.ParentForm 
        End If 
        For Each aForm In aMdiParent.MdiChildren 
         If aType.FullName Is aForm.GetType.FullName Then 
          aForm.Tag = param 

          'Added Code below to try to prevent Cross-Thread exception on PicDisplay found in the Main cfrmOverview Form 
          'that has designed time user control embedded. 

          'New Code Start---------------------------------------------------------------------- 
          For Each aControl As Windows.Forms.Control In aForm.Controls.Find("picDisplay", True) 
           If aControl.InvokeRequired Then 
            Dim myArray(0) As Object 
            myArray(0) = New PictureBox 
            aControl.BeginInvoke(New Mydelegate(AddressOf CreateEnableControl), myArray) 
           End If 
          Next 
          'New Code End------------------------------------------------------------------------ 

          aForm.Show() 'Cross-thread exception for picDisplay is here. 
          GoTo Success 

         End If 
+0

'InvokeRequired'をテストし、そのコードで' BeginInvoke'を呼び出すという事実は、UIスレッド上で実行されるかどうかを示唆しています。つまり、そのコード内のフォームや他のコントロールのメンバーにアクセスするべきではありません。 'aForm'の' Show'メソッドはフォームのメンバなので、制限はありません。同様のテストを行い、そのフォーム上でUIスレッド上で 'Show'を呼び出すよう呼び出す必要があります。 – jmcilhinney

答えて

1

あなたがすべき/コントロールが作成されたスレッド上のコントロールにアクセスし1つののInvokeコーディングする必要があります。

Control.Invokeとdelegate.BeginInvokeを混在させないでください。エラーがしかし

aForm.Invoke(Sub() aForm.Show()) 

に変更することができ提起What's the difference between Invoke() and BeginInvoke()

ラインを参照してください、あなたは常に呼び出し、すでに適切なスレッド上でコードを実行された場合、たとえば、起動したくない場合がありますコールは無駄です。そのため、コントロールにはInvokeRequiredというプロパティがあります。フォームを表示するためのinvoke-if-invokerequiredパターンの具体的な実装を次に示します。

Private Sub showForm(ByVal f As Form) 
    If f.InvokeRequired Then 
     f.Invoke(New Action(Of Form)(AddressOf showForm), f) 
    Else 
     f.Show() 
    End If 
End Sub 

' usage: 
showForm(aForm) 

多くのUIプログラミングを行っている場合は、これらのメソッドをたくさん書いていることがあります。したがって、パターンを自動化することができます

この拡張メソッドをモジュールに入れることができます。それは、あなたが好きなんデリゲートを渡すことができ、および例外を発生させないであろう間違ったスレッドからのコントロールにアクセスして、いくつかのケースでは

<Extension()> _ 
Public Sub InvokeIfRequired(ByVal control As Control, action As MethodInvoker) 
    If control.InvokeRequired Then 
     control.Invoke(action) 
    Else 
     action() 
    End If 
End Sub 

' usage: 
aForm.InvokeIfRequired(Sub() aForm.Show()) 

を、必要な場合には、コントロールのスレッドで呼び出されます断続的な例外が発生する可能性があります。私の経験では、それは非決定的です。たとえば、間違ったスレッドでTextBox.Textを取得するのは通常問題ありませんが、通常はTextBox.Textに設定すると例外が発生します。このため、独自のイベントハンドラ以外のコントロールを使用する場合や、同じフォームのコントロールのイベントハンドラを使用しない場合は、invoke-if-invokerequiredパターンを使用することをお勧めします。

+0

私はあなたの最初の提案を試みましたが、これはクロススレッドの例外を排除しましたが、MDIの子cfrmOverviewはかなりの時間をかけてロードされます。 – Blackie

+0

クロススレッド例外のため、以前はロードされていませんでしたか?たぶん 'cfrmOverview.cfrmOverview_Load()'はちょうど多くのことをしています。 – djv

関連する問題