Прогрессбар зависает при загрузке другой формы
У меня 3 формы;
Форма 1 - Основная форма
Форма 2 - Форма Sub (содержит индикатор выполнения и таймер)
Форма 3 - Форма с тяжелым содержимым, которая требует времени для загрузки (например, анализ данных с веб-страницы и запись их в Datagridview при событии загрузки формы)
Мне нужно показать form2 с индикатором выполнения во время загрузки form3
У меня есть следующие коды в Form1;
Me.Hide
Form2.Show()
Form3.Show()
коды из формы 2;
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LoadingTimer.Enabled = True
End Sub
Private Sub LoadingTimer_Tick(sender As Object, e As EventArgs) Handles LoadingTimer.Tick
If MyProgressBar.Value <= MyProgressBar.Maximum - 1 Then
MyProgressBar.Value += 10
End If
If MyProgressBar.Value = 100 Then
LoadingTimer.Enabled = False
Me.Close()
End If
If Label1.ForeColor = Color.LimeGreen Then
Label1.ForeColor = Color.White
Else
Label1.ForeColor = Color.LimeGreen
End If
End Sub
End Class
Проблема в том, что индикатор запускается, но вначале зависает, пока загружается Form3
Есть идеи для решения?
2 ответа
Если вы новичок в программировании, то это может немного сбить с толку, но ответ состоит в том, чтобы вытолкнуть код из Load
обработчик события Form3
в Async
метод и жду его. Ваш пользовательский интерфейс зависает, потому что вы выполняете работу синхронно в потоке пользовательского интерфейса. Вам нужно либо явно использовать вторичный поток, либо использовать Async
/Await
, Это:
Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Do some work.
End Sub
станет этим:
Private Async Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Await DoWork()
End Sub
Private Async Function DoWork() As Task
Await Task.Run(Sub()
'Do some work.
End Sub).ConfigureAwait(False)
End Function
На самом деле, это, вероятно, более сложно, чем необходимо, и это должно работать нормально:
Private Async Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Await Task.Run(Sub()
'Do some work.
End Sub).ConfigureAwait(False)
End Sub
Перечитав свой вопрос, вам, вероятно, нужно сделать так, чтобы ваш асинхронный метод был функцией, которая извлекает и возвращает данные с веб-страницы или чего-либо еще, а затем вы загружаете эти данные в свой DataGridView
синхронно после, например,
Private Async Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
DataGridView1.DataSource = Await GetDataAsync()
End Sub
Private Async Function GetDataAsync() As Task(Of DataTable)
Return Await Task.Run(Function()
Dim table As New DataTable
'Populate table here.
Return table
End Function).ConfigureAwait(False)
End Function
Итак GetDataAsync
метод возвращает Task(Of DataTable)
т.е. Task
который асинхронно выполняет функцию, которая возвращает DataTable
, в Load
обработчик события, вы вызываете этот метод и ожидаете Task
, что означает, что ваш код будет ждать до Task
выполнил и возвратил свои данные, но без блокировки потока пользовательского интерфейса, как это сделал бы синхронный вызов. Синхронный эквивалент будет следующим:
Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
DataGridView1.DataSource = GetData()
End Sub
Private Function GetData() As DataTable
Dim table As New DataTable
'Populate table here.
Return table
End Function
Попробуйте сделать процесс асинхронным, в моем понимании, отметка таймера уже асинхронна, но в форме1 вы могли бы использовать этот код внутри Задачи.
Me.Hide
Task.Run(Function() Form2.Show())
Form3.Show()
Я никогда не заходил так далеко на vb.net, так как начал программировать на C#, но это должно сработать