Вопрос

Я ищу универсальный метод для реализации экрана ожидания во время длительных операций.Я уже несколько раз использовал потоковую обработку, но у меня такое ощущение, что я реализовал это либо очень плохо, либо со слишком большими хлопотами (а копирование / вставка - ужас!).

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

Вот что я хотел бы сделать - пожалуйста, обратите внимание, что это может отличаться от того, что на самом деле возможно / лучшая практика / что угодно - используя VB.NET, Framework 2.0 (поэтому никаких анонимных методов):

  Private Sub HandleBtnClick(sender as Object, e as EventArgs) Handles Button.Click
      LoadingScreen.Show()

      'Do stuff here, this takes a while!'
      Dim Result as Object = DoSomethingTakingALongTime(SomeControl.SelectedObject)

      LoadingScreen.Hide()

      ProcessResults(Result)
  End Sub

Приложение теперь полностью однопоточное, поэтому все выполняется в потоке GUI.Мне нужно иметь возможность доступа к объектам в DoSomethingTakingALongTime() без получения исключений из разных потоков.Поток графического интерфейса ожидает завершения выполнения некоторого метода (что занимает много времени), в то время как LoadingScreen Форма должна оставаться отзывчивой (она анимирована / имеет панель выполнения / и т.д.).

Является ли это выполнимым / хорошим подходом или я вижу этот способ слишком упрощенным?Какова наилучшая практика в этом вопросе?И самое главное:как я мог бы внедрить такую систему?Как я уже упоминал, у меня очень мало опыта работы с потоками, поэтому, пожалуйста, будьте помягче :-)

Это было полезно?

Решение

Ваша проблема в том, что вы получаете исключение перекрестного потока при попытке передать данные вашего рабочего потока в ваш поток пользовательского интерфейса.что вам нужно сделать, это проверить InvokeRequired и begininvoke перед установкой элементов управления в вашем пользовательском интерфейсе, чтобы вы не получили ошибку, подобную этой:

Private Sub work_CrossThreadEvent(ByVal sender As Object, ByVal e As System.EventArgs) Handles work.CrossThreadEvent

       If Me.InvokeRequired Then
           Me.BeginInvoke(New EventHandler(AddressOf work_CrossThreadEvent), New Object() {sender, e})
           Return
       End If

      Me.Text = "Cross Thread"

End Sub

просто измените New EventHandler часть используемого вами обработчика событий.

Также я думаю, что использование фонового рабочего не является плохим методом для ваших рабочих классов, просто создайте класс для своей работы и используйте фонового рабочего для выполнения потоковых операций примерно так:

Public MustInherit Class Worker

    Protected WithEvents worker As BackgroundWorker

    Public Sub New()

        worker = New BackgroundWorker()
        worker.WorkerReportsProgress = True
        worker.WorkerSupportsCancellation = True

    End Sub

    Public Sub Start()

        If (Not worker.IsBusy AndAlso Not worker.CancellationPending) Then
            worker.RunWorkerAsync()
        End If

    End Sub

    Public Sub Cancel()
        If (worker.IsBusy AndAlso Not worker.CancellationPending) Then
            worker.CancelAsync()
        End If
    End Sub

    Protected MustOverride Sub Work()

    Private Sub OnDoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
        Work()
    End Sub

    Public Event WorkCompelted As RunWorkerCompletedEventHandler
    Private Sub OnRunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
        OnRunWorkerCompleted(e)
    End Sub
    Protected Overridable Sub OnRunWorkerCompleted(ByVal e As RunWorkerCompletedEventArgs)
        RaiseEvent WorkCompelted(Me, e)
    End Sub

    Public Event ProgressChanged As ProgressChangedEventHandler
    Private Sub OnProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles worker.ProgressChanged
        OnProgressChanged(e)
    End Sub
    Protected Overridable Sub OnProgressChanged(ByVal e As ProgressChangedEventArgs)
        RaiseEvent ProgressChanged(Me, e)
    End Sub

End Class

Public Class ActualWork
    Inherits Worker

    Public Event CrossThreadEvent As EventHandler

    Protected Overrides Sub Work()

        'do work here'
        WorkABit()
        worker.ReportProgress(25)

        WorkABit()
        worker.ReportProgress(50)

        WorkABit()
        worker.ReportProgress(75)

        WorkABit()
        worker.ReportProgress(100)

    End Sub

    Private Sub WorkABit()

        If worker.CancellationPending Then Return
        Thread.Sleep(1000)
        RaiseEvent CrossThreadEvent(Me, EventArgs.Empty)

    End Sub

End Class

Отказ от ответственности..немного подзабылось с vb, но вы должны уловить идею.

Другие советы

В вашем потоке используйте Application.Запустите (yourform), чтобы получить то, что вы хотите.

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

Я надеюсь, вы не сочтете это бесполезным, но я бы задался вопросом, зачем вам нужен экран ожидания с потоковой передачей?Причина использования многопоточности в первую очередь заключается в том, что пользовательский интерфейс остается отзывчивым, а длительные операции выполняются в фоновом режиме.

В противном случае, вы могли бы с таким же успехом просто иметь ProgressBar в вашем элементе управления FormLoading и иметь DoSomethingTakingALongTime для периодического обновления его.Для этого вообще не понадобились бы потоки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top