Экран потоковой загрузки (ожидания)

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

Я хочу, чтобы это было как можно более общим и простым, чтобы мне не пришлось реализовывать множество 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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
3 593
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

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

Какая нить? Приложение является однопоточным (= поток графического интерфейса пользователя), который уже использует Application.Run для отображения основной формы.

Vincent Van Den Berghe 25.11.2008 14:06

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

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

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

Vincent Van Den Berghe 25.11.2008 13:55

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

Vincent Van Den Berghe 25.11.2008 13:57
Ответ принят как подходящий

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

Спасибо! Я разберусь с этим и вернусь к вам :-)

Vincent Van Den Berghe 02.12.2008 13:47

Очень и очень полезно. Отличное объяснение на простом английском языке. Спасибо!

Matt Hanson 05.12.2008 05:32

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