首页 > 解决方案 > 后台任务表单未按预期工作并冻结 GUI

问题描述

我有我的程序的主窗口形式。我想把一个很长的任务放到不同的线程中。我有另一个小表单(FrmCircularProgress),当该任务运行时,它会在顶部显示给用户,这是普通的简单表单,其中没有任何内容。问题是当长任务正在运行并且我的等待表单出现(FrmCircularProgress)时,它似乎没有响应(冻结),因为例如在此过程中我无法移动它。我不知道为什么因为任务在不同的线程等待表单上运行应该是响应式的。请多多支持。

请注意,有趣的是,我在许多其他地方使用完全相同的方法 - 使用这个 _pic.Shown,AddressOf XXX,其中 XXX 的内部方法我放置了我想放在不同线程上的代码,所有工作都意味着 FrmCircularProgress 是响应式的。这是第一次发生,我不知道它的原因。

在主表单类之上:

Private WithEvents _pic As FrmCircularProgress
Private _tsk As Task(Of Boolean)
Button handler where long running task is raised:

Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
      Try
         _pic = New FrmCircularProgress(eCircularProgressType.Donut)
         AddHandler _pic.Shown, AddressOf DoTheJob
         _pic.ShowDialog()
      Catch ex As Exception
      Finally
         RemoveHandler _pic.Shown, AddressOf DoTheJob
      End Try
End Sub

任务本身:

Public Sub DoTheJob(sender As Object, e As EventArgs)
        _tsk = Task.Run(Function()
        '--Run lenghty task
        Dim resu = False
        Try
           InitGrid()
           resu = True
        Catch ex As Exception
          _pic.Invoke(New Action(Sub() MessageBoxEx.Show(_pic, ex.ToString())
        Finally
          '--Close form once done (on GUI thread)
          _pic.Invoke(New Action(Sub() _pic.Close()))
        End Try
        Return resu
End Function)
End Sub

由于它位于不同的线程中,因此不确定您是否需要它们查看,但我正在向它们展示:

初始化网格:

Public Sub InitGrid() Handles _editDictionaryForm.Updated, _addDictionaryForm.Updated
      If InvokeRequired Then
           Invoke(New MethodInvoker(AddressOf InitGrid))
      Else
           Try
              BindArticlesData()
              InitializeGridBasiscSettings()
           Catch ex As Exception
           End Try
      End If
End Sub

Private Sub BindArticlesData()
       If InvokeRequired Then
              Invoke(New MethodInvoker(AddressOf BindArticlesData))
       Else
          Try
             RemoveHandler gridDic.DataBindingComplete, AddressOf SuperGridControl1DataBindingComplete
             AddHandler gridDic.DataBindingComplete, AddressOf SuperGridControl1DataBindingComplete
             gridDic.PrimaryGrid.DataSource = Nothing
             Dim dada = CInt(DirectCast(cbLang.SelectedItem, DataRowView).Item("Id"))
             gridDic.PrimaryGrid.DataSource = _dictionary.GetDataSet(dada, txtFilterDE.Text)
          Catch ex As Exception
          End Try
        End If
End Sub

Private Sub InitializeGridBasiscSettings()
       If InvokeRequired Then
                Invoke(New MethodInvoker(AddressOf InitializeGridBasiscSettings))
       Else
           //simple grid layout adjustments
       End If
End Sub

到目前为止我做了什么:

因为到目前为止我意识到在从不同线程处理时使用invoke()是正确的,但它仍然阻塞主线程,因此我认为扩展变量数据可能很好,将其填充到Invoke中,但是将数据设置到网格的数据源之外调用以不阻止 GUI。尽管如此,由于某种原因,问题似乎仍然相同。

Private Sub BindArticlesData()

    Dim data As DataSet  ' <=======put outside Invoke
    Invoke(Sub()
    RemoveHandler gridDic.DataBindingComplete, AddressOf SuperGridControl1DataBindingComplete
    AddHandler gridDic.DataBindingComplete, AddressOf SuperGridControl1DataBindingComplete
    gridDic.PrimaryGrid.DataSource = Nothing
    Dim dada = CInt(DirectCast(cbLang.SelectedItem, DataRowView).Item("Id"))
    data = _dictionary.GetDataSet(dada, txtFilterDE.Text)
    End Sub)

    gridDic.PrimaryGrid.DataSource = data   'fill outside Invoke the result

End Sub

编辑进一步讨论:

Private Sub BindArticlesData()
        Dim data As DataSet
        RemoveHandler gridDic.DataBindingComplete, AddressOf SuperGridControl1DataBindingComplete
        AddHandler gridDic.DataBindingComplete, AddressOf SuperGridControl1DataBindingComplete

        gridDic.PrimaryGrid.DataSource = Nothing

        Invoke(Sub()
              Dim dada = CInt(DirectCast(cbLang.SelectedItem, DataRowView).Item("Id"))

              data = _dictionary.GetDataSet(dada, txtFilterDE.Text)
         End Sub)

         gridDic.PrimaryGrid.DataSource = data

End Sub

标签: vb.net

解决方案


推荐阅读