2

계산 작업이 많은 작업을 처리하는 일반적인 VB 방법은 기본 스레드가 UI를 계속 처리하는 동안 백그라운드 작업자 스레드에 넣는 것입니다.Visual Basic.NET : UI를 업데이트하는 스레드를 만드는 방법

이유가 무엇이든 나는 다른 방법으로이 작업을 수행해야한다고 말하면됩니다. 메인 스레드는 툴툴 거리는 작업을 수행하고 배경은 UI를 업데이트합니다.

여기까지 제가 지금까지 가지고 있습니다. 유일한 문제는 UI 창 (Form1)이 다시 그려지는 동안 움직이거나 크기를 조정하지 않고도 상호 작용할 수 없다는 것입니다 (마우스 커서가 모래 시계 모양으로 바뀌고 클릭하지 않음).

Public Class ProgressDisplay 

Private trd As Thread 

    Public Sub New() 
     trd = New Thread(AddressOf threadtask) 
     trd.Start() 
    End Sub 

    Private Sub threadtask() 
     Dim f1 As Form1 
     f1 = New Form1 
     f1.Show() 
     Do 
      f1.Update() 
      Thread.Sleep(100) 
     Loop 
    End Sub 

End Class 

편집 : 이상적으로는 클라이언트는 다음과 같이 호출 할 클라이언트

Public Class ProgressDisplay 
    Public Sub New() 
    Public Sub Update(byval progress as int) 
End Class 

에 다음과 같은 인터페이스를 제공합니다 (실제로는 COM을 통해 관리되지 않는 C++에서 그러나 당신은 그림을 얻는다) :

Dim prog = new ProgressDisplay() 
DoLotsOfWork(addressof prog.update) ' DoLotsOfWork method takes a callback argument to keep client informed of progress 
+0

문제는 내 코드에서 수행되지 않은 긴 작업입니다.이 클래스의 클라이언트에서 문제가 발생했습니다. 그래서, 나는 그것이 일어나는 곳을 제어 할 수 없다. 그것은 주 스레드에있다. 클라이언트가해야 할 일은 처음에는'SetupProgressIndicator' 메소드를 호출하고 때때로 IncrementProgressIndicator 메소드를 호출하는 것입니다. 그 일을 할 수 있습니까? –

+0

자세한 상황을 설명해주십시오. 당신이 의미하는 바를 이해하는 것은 어렵습니다. –

+0

업데이트 감사 참조 :) –

답변

1

문제를 명확하게 다시 말하면 - 자신의 프로그램 내에서이를 사용할 클라이언트에게 시각적 구성 요소를 제공해야합니다. 클라이언트 프로그램은 컨트롤 외부에서 메인 (즉 : UI) 스레드를 연결하며 클라이언트의 프로그램이 고정되어있는 동안 비주얼 컴포넌트가 계속 작동하도록해야합니다.

CAN 이렇게하면되지만, 아마도 가장 우아하고 권장되는 해결책은 아닙니다. 기본 UI 스레드 옆에서 계속 실행될 수있는 두 번째 응용 프로그램 컨텍스트와 새 메시지 루프를 만들어야합니다. 이 같은 클래스 뭔가 작동합니다 : 당신이 (스레드에게 메시지 루프를 제공하는) 새로운 STA 스레드에서 새 응용 프로그램 컨텍스트를 만드는 위의 클래스로 수행하는 본질적으로 무엇을

Imports System.Threading 

Public Class SecondUIClass 

    Private appCtx As ApplicationContext 
    Private formStep As Form 
    Private trd As Thread 
    Private pgBar As ProgressBar 
    Delegate Sub dlgStepIt() 

    Public Sub New() 
     trd = New Thread(AddressOf NewUIThread) 
     trd.SetApartmentState(ApartmentState.STA) 
     trd.IsBackground = True 
     trd.Start() 
    End Sub 

    Private Sub NewUIThread() 
     formStep = New Form() 
     pgBar = New ProgressBar() 
     formStep.Controls.Add(pgBar) 
     appCtx = New ApplicationContext(formStep) 
     Application.Run(appCtx) 
    End Sub 

    Public Sub StepTheBar() 
     formStep.Invoke(New dlgStepIt(AddressOf tStepIt)) 
    End Sub 

    Private Sub tStepIt() 
     pgBar.PerformStep() 
    End Sub 

End Class 

. 이 컨텍스트에는 메인 UI 스레드와 별도로 계속 작동 할 수있는 기본 폼 (스레드 소유권과 메시지 처리 책임이 있음)이 포함되어 있습니다. 이것은 프로그램 내에서 프로그램을 갖는 것과 매우 흡사합니다. 두 개의 UI 스레드는 상호 배타적 인 컨트롤 집합을 가지고 있습니다.

새 UI 스레드 (또는 해당 양식)가 소유 한 컨트롤과 상호 작용하는 호출은 새 UI 스레드가 상호 작용을하는 스레드인지 확인하기 위해 기본 UI 스레드 (또는 기타)의 Control.Invoke으로 마샬링되어야합니다 . 여기서 BeginInvoke을 사용할 수도 있습니다.

이 클래스에는 클린업 코드가없고, 안전성 검사 등 (경고)이 없으며 정상적으로 완료 될지조차 잘 모르겠다. 나는 그 일을 너에게 맡긴다. 이것은 시작하는 방법을 보여줍니다.

Public Class Form1 

    Private pgClass As New SecondUIClass 

    Private Sub Button1_Click(ByVal sender As System.Object, _ 
    ByVal e As System.EventArgs) Handles Button1.Click 
     Dim i As Integer 
     For i = 1 To 10 
      System.Threading.Thread.Sleep(1000) 
      pgClass.StepTheBar() 
     Next 
    End Sub 
End Class 

Form1뿐만 아니라 pgClass 만든 두 번째 폼을 만들 것입니다 응용 프로그램을 실행 : 기본 폼에서 당신은 같은 일을 할 것입니다. 을 누르면 Form1은 루프를 통과하는 동안 Form1을 잠글 것이지만 두 번째 양식은 여전히 ​​살아 있고 반응 형이어서 Form1이라는 메시지가 표시 될 때마다 진행률 막대가 .StepTheBar()이 될 때마다 업데이트됩니다.

이 경우 가장 좋은 해결책은 '클라이언트'가 제대로 프로그래밍하고 처음에이 수수께끼에 얽매이지 않도록하는 방법을 배우는 것입니다. 그게 완전히 불가능한 경우에 당신은 그들에게 위의 접근법이 당신의 유일한 수단 일 뿐이라는 잘못된 코드에도 불구하고 살아 남을 구성 요소를 만들어야 만합니다.

1

UI는 기본 이벤트 발송 스레드가 아닌 다른 스레드에서 업데이트 할 수 없습니다. 그래서 당신은 일하지 않을 무언가를하려고 노력하고 있습니다.

+0

Ok. 이 문제를 처리 할 수있는 다른 프로세스 *를 해고 할 수있는 방법이 있습니까? –

2

UI는 해당 스레드를 생성 한 스레드를 통해서만 업데이트 할 수 있습니다. 모든 스레드는 Control.Invoke 메서드를 사용하여 UI를 업데이트 할 수 있도록 UI 스레드에서 메서드를 호출하도록 요청할 수 있지만 UI 스레드가 더 이상 사용되지 않을 때까지 기다리고 대기합니다. UI 스레드가 사용 중이면 아무거나 누군가에 의해 UI를 업데이트 할 수 없습니다. UI는 주 메시지 루프 (AKA Application.Run)가 대기열의 창 메시지를 처리하고이를 처리 할 때만 업데이트됩니다. UI 스레드가 사용 중이거나 루프에 걸려 있거나 서버의 응답을 기다리는 경우 DoEvents을 호출하지 않는 한 해당 창 메시지를 처리 ​​할 수 ​​없습니다. 가능한 경우 권장하지 않습니다. 예, UI가 바쁠 때 잠겨 있습니다. 그것이 모든 사람이 엄청난 비즈니스 로직을 별도의 스레드에서 수행하는 것을 제안하는 전체 이유입니다. 그게 문제가 아니었다면, 왜 누군가가 쓰레드를 만드는 것을 괴롭 히겠습니까?