Обновление пользовательского интерфейса из другого потока - PullRequest
1 голос
/ 14 декабря 2011

У нас есть проблема с приложением, когда мы выполняем вызов асинхронного процесса на LostFocus в TextBox, тогда асинхронный процесс должен иметь возможность обновлять основной интерфейс формы (или отображать диалоговое окно из основного интерфейса формы). ) при асинхронном запуске.

Мы думали о обратных вызовах и о том, что они действительно асинхронные, но нам нужно, чтобы все выполнялось в правильном порядке, и это для системы ввода данных, где важна скорость и точность ввода данных.

Пример кода показывает, что мы пытаемся сделать, и если вы переключитесь на BeginInvoke, порядок обработки будет неправильным.

Публичный класс Form1

Private Sub TextBox1_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.LostFocus

    ' execute the server subroutine
    Dim dlgt As New MethodInvoker(AddressOf Me.AsyncProcess)

    TextBox1.Text = "1"
    ' textbox should say 1

    ' call the server subroutine asynchronously, so the main thread is free
    Dim ar As IAsyncResult = dlgt.BeginInvoke(Nothing, Nothing)

    While ar.IsCompleted = False
        ' Application.DoEvents()
    End While
    ' textbox should now say 2

    TextBox1.Text = "3"
    ' textbox should now say 3
End Sub

Public Sub AsyncProcess()
    UpdateTextBox()
End Sub

Public Sub UpdateTextBox()
    If Me.InvokeRequired Then
        Me.Invoke(New MethodInvoker(AddressOf UpdateTextBox), "2")
    Else
        TextBox1.Text = "2"
    End If
End Sub

Конечный класс

Кто-нибудь знает, как мы можем вызывать что-то еще в главном потоке формы, пока все еще занят обработкой события LostFocus?

Спасибо заранее.

Ответы [ 2 ]

2 голосов
/ 14 декабря 2011

Проверьте класс BackgroundWorker .Вы можете использовать этот класс для выполнения долгосрочных задач в фоновом режиме и сообщать о состоянии обратно в пользовательский интерфейс через события.Класс поддерживает событие «ProgressChanged» и событие «RunWorkerCompleted».Ниже приведен пример кода, чтобы показать, как его использовать для достижения того, что вы пытаетесь сделать.

Imports System.ComponentModel
Imports System.Threading

Public Class Form1

    Private Sub TextBox1_LostFocus(ByVal sender As Object, 
        ByVal e As System.EventArgs) Handles TextBox1.LostFocus

        TextBox1.Text = "1"

        ' Execute the long-running task in the background
        BackgroundWorker1.RunWorkerAsync()

    End Sub

    Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, 
        ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork

        ' Do your heavy lifting in this method; report progress as needed by 
        ' calling ReportProgress, which will in turn call Progress_Changed
        ' safely on the UI thread.  (DO NOT update the UI directly from here.)

        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)

        ' Simulate processing for a second
        Thread.Sleep(1000)

        ' Report progress to the UI (the first arg is the percentage complete;
        ' the secong arg can be a string or any object)
        worker.ReportProgress(50, "2")

        ' Simulate processing for another second
        Thread.Sleep(1000)

    End Sub

    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, 
        ByVal e As ProgressChangedEventArgs) 
        Handles BackgroundWorker1.ProgressChanged

        ' Update the UI with progress from the background task
        TextBox1.Text = CType(e.UserState, String)

    End Sub

    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object,
        ByVal e As RunWorkerCompletedEventArgs) 
        Handles BackgroundWorker1.RunWorkerCompleted

        ' Update the UI when the background task is finished
        TextBox1.Text = "3"

    End Sub
End Class
0 голосов
/ 14 декабря 2011

Я думаю, что вам лучше всего не пытаться дождаться синхронного завершения метода.Измените оставшуюся часть метода-обработчика LostFocus, который вы хотите реализовать после асинхронного вызова, на обратный вызов и передайте его BeginInvoke.Это позволяет потоку пользовательского интерфейса оставаться отзывчивым при сохранении порядка операций.

...