2016-09-30 2 views
0

Winform 응용 프로그램을 작성한 이후로는 결코 그렇지 않았습니다. 나의 전문 분야는 Asp.net/Websites와 협력 해왔다. 최근에 .Net 1.1에서 .Net 4.6으로 업그레이드하는 응용 프로그램이 제공되었습니다. 응용 프로그램은 크로스 스레드 작업에 문제가있는 MDI 응용 프로그램입니다. 특히 사용자 정의 컨트롤 내의 버튼 이벤트를 클릭하면 주 MDIchild 폼 (cfrmOverview)이 표시되지만 picDisplay라는 Picturebox 컨트롤에 액세스하면 오류가 발생하기 때문에 오류가 발생합니다. 추가 된 코드를 사용해도 여전히 오류가 발생합니다. CheckForIllegalCrossThreadCalls은 프로그램의 다른 부분에도 영향을 미치고 MSDN은 그렇지 않기 때문에 사용하지 않기로 결정했습니다. 통찰력이 필요했습니다.usercontrol .net 1.1 ~ 4.6의 단추를 통해 부모와 자식간에 MDI 크로스 스레드 예외가 발생했습니다.

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 호출 코드입니다.

Control.Invoke와 delegate.BeginInvoke가 섞이지 않도록하십시오. 항상 당신이 적절한 스레드에서 코드를 실행하는 경우 이미 예를 들어, 호출을 호출 할이되지 않을 수 What's the difference between Invoke() and BeginInvoke()

오류가 그러나

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

로 변경 될 수 있습니다 제기 라인을 참조하십시오 전화가 낭비입니다. 이것이 컨트롤에 InvokeRequired 속성이있는 이유입니다. 다음은 폼을 표시하기위한 invoke-if-invokrecquired 패턴의 특정 구현입니다.

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) 

많은 프로그래밍을하고 있다면이 방법을 많이 쓰는 것을 알 수 있습니다. 따라서 패턴을 자동화 할 수 있습니다.

이 확장 방법을 모듈에 넣을 수 있습니다. 그것은 당신이 당신이 원하는대로 수행하는 대리자를 통과 할 수 있으며 예외를 발생하지 않습니다 잘못된 스레드에서 컨트롤에 접근, 어떤 경우에는

<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()) 

1 필요한 경우는 컨트롤의 스레드에서 호출됩니다 간헐적 인 예외가 발생할 수 있습니다. 내 경험에 비 결정적입니다. 예를 들어, 잘못된 스레드에서 TextBox.Text을 검색하는 것은 일반적으로 문제가되지 않지만 TextBox.Text을 설정하면 일반적으로 예외가 발생합니다. 이러한 이유로 자체 이벤트 처리기 외부의 컨트롤을 사용하거나 적어도 동일한 양식의 컨트롤에 대한 이벤트 처리기 외부에서 수행 할 때마다 invoke-if-invokrecquired 패턴을 사용하는 것이 좋습니다.

+0

첫 번째 제안을 시도했지만 이것이 크로스 스레드 예외를 제거했지만 이제 MDI 하위 cfrmOverview에로드하는 데 상당한 시간이 걸립니다. – Blackie

+0

크로스 스레드 예외로 인해 이전에로드되지 않았습니다. 맞습니까? 아마도'cfrmOverview.cfrmOverview_Load()'는 많은 일을하고있을 것입니다. – djv

관련 문제