后台任务表单无法按预期工作并冻结了GUI

时间:2018-12-07 18:19:41

标签: vb.net

我的程序有主窗口形式。我要把一个漫长的任务放在不同的线程中。我还有另一个小表格(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

由于它处于不同线程中,因此不确定是否需要他们查看,但我正在向他们显示:

InitGrid:

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

0 个答案:

没有答案