Резьбовой экран загрузки (ожидания) - PullRequest
4 голосов
/ 25 ноября 2008

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

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

Вот что я хотел бы сделать - обратите внимание, что это может отличаться от того, что на самом деле возможно / передовой опыт / что угодно - с использованием 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() без получения исключений между потоками. Поток GUI ожидает завершения какого-либо метода (который занимает много времени), в то время как форма LoadingScreen должна оставаться отзывчивой (она анимирована / имеет индикатор выполнения / и т.д.).

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

Ответы [ 3 ]

4 голосов
/ 01 декабря 2008

Ваша проблема в том, что вы получаете межпотоковое исключение при попытке передать данные вашего рабочего потока в ваш поток пользовательского интерфейса. что вам нужно сделать, это проверить 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, но вы должны понять.

0 голосов
/ 25 ноября 2008

Надеюсь, вы не найдете это бесполезным, но я бы спросил, ПОЧЕМУ вам нужен экран ожидания с резьбой? Во-первых, причина использования многопоточности заключается в том, что пользовательский интерфейс остается отзывчивым, а длинные операции выполняются в фоновом режиме.

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

0 голосов
/ 25 ноября 2008

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

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

...