Чтобы четко сформулировать проблему - вам необходимо предоставить визуальный компонент клиенту, который будет использовать его в своей собственной программе. Программа клиента, вне вашего контроля, связывает ее основной (т. Е. Пользовательский) поток, и вам необходимо, чтобы ваш визуальный компонент продолжал работать, пока программа клиента заморожена.
Вы CAN сделайте это, но это, вероятно, не самое элегантное или рекомендуемое решение. Вам нужно создать второй контекст приложения и новый цикл сообщений, который может продолжать работать рядом с основным потоком пользовательского интерфейса. Класс-то, как это будет работать:
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
По существу, что вы делаете с выше класса создает новый контекст приложения внутри нового STA нити (давая что нить цикл обработки сообщений). Этот контекст содержит основную форму (дающую право собственности на нее и ответственность за ее обработку сообщений), которая может продолжать работать в стороне от основного потока пользовательского интерфейса. Это очень похоже на наличие программы в рамках программы - два потока пользовательского интерфейса, каждый из которых имеет свой собственный взаимоисключающий набор элементов управления.
Звонки, которые взаимодействуют с любыми элементами управления, принадлежащими новому потоку пользовательского интерфейса (или его форме), должны быть сопоставлены с 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
. Нажав Button1
на Form1
, вы закроете Form1, пока он пройдет через его цикл, но вторая форма все равно останется живой и отзывчивой, обновив ее индикатор выполнения каждый раз, когда Form1
называется .StepTheBar()
.
Лучшее решение в этом случае, действительно, состоит в том, чтобы «клиент» научился правильно программировать и не застревать в этой головоломке в первую очередь. В случае, когда это совершенно невозможно, и вы ДОЛЖНЫ создать для них компонент, который останется живым, несмотря на их плохой код, то вышеупомянутый подход, вероятно, является вашим единственным средством.
Проблема заключается в том, что в моем коде длинная работа не выполняется - это происходит в клиенте для этого класса. Таким образом, я не могу контролировать, где это происходит - это в основном потоке. То, что нужно сделать клиенту, это вызвать метод «SetupProgressIndicator» в начале и метод «IncrementProgressIndicator» время от времени. Можно ли заставить его работать? –
Пожалуйста, опишите ситуацию более подробно. Трудно понять, что вы имеете в виду. –
См. Update thanks :) –