【问题标题】:Task function within form and error messages表单和错误消息中的任务功能
【发布时间】:2016-07-28 18:30:47
【问题描述】:

我有一个表单,它的作用是在用户等待完成特定任务时向用户显示循环进度图形。这是它的简单代码:

Public Class FrmCircularProgress
    Sub New(progressType As DevComponents.DotNetBar.eCircularProgressType)
        InitializeComponent()
        CircularProgress1.ProgressBarType = progressType
        StartCircular()
    End Sub

    Public Sub StartCircular()
        Me.CircularProgress1.IsRunning = True
    End Sub

    Public Sub StopCircular()
        Me.CircularProgress1.IsRunning = False
    End Sub
End Class

以下是我如何使用它的示例(在本例中为两个地方)

 Dim createArticle As New Artikel

                    'http://stackoverflow.com/questions/33030706/put-long-running-method-into-task-showing-new-form-meantime-and-closing-it-once
                    Dim pic As New FrmCircularProgress(eCircularProgressType.Donut)
                    Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
                                                                                        '--Run lenghty task
                                                                                        Dim resu = False
                                                                                        Try
                                                                                            resu = createArticle.ProcessArticle(_artikelsAndTheirVariationsFinal)
                                                                                            '--Close form once done (on GUI thread)

                                                                                        Catch sqlex As Exception
                                                                                            pic.Invoke(Sub() MessageBox.Show(pic, sqlex.Message))
                                                                                            ' pic.Invoke(Sub() MessageBox.Show(pic, ex.Message))
                                                                                            'pic.Invoke(Sub() TaskDialog.Show(pic, New TaskDialogInfo("Information", eTaskDialogIcon.BlueStop, "WizardPageDescriptionUberblick_BeforePageDisplayed", ex.ToString, eTaskDialogButton.Ok, eTaskDialogBackgroundColor.Blue, Nothing, Nothing, Nothing, "Jakis footer text", Nothing)))
                                                                                        Finally

                                                                                        End Try

                                                                                        pic.Invoke(New Action(Sub() pic.StopCircular()))
                                                                                        pic.Invoke(New Action(Sub() pic.Close()))
                                                                                        Return resu
                                                                                    End Function)

                    '--Show the form
                    pic.ShowDialog()
                    Task.WaitAll(tsk)

                    If tsk.Result = True Then
                        TaskDialog.Show(New TaskDialogInfo("Information", eTaskDialogIcon.BlueStop, "Infor", "New articel and every data has been added correctly", eTaskDialogButton.Ok, eTaskDialogBackgroundColor.Blue, Nothing, Nothing, Nothing, "Jakis footer text", Nothing))

                        'http://stackoverflow.com/questions/33030706/put-long-running-method-into-task-showing-new-form-meantime-and-closing-it-once
                        pic = New FrmCircularProgress(eCircularProgressType.Line)
                        Dim work As Task = Task.Factory.StartNew(Sub()
                                                                     '--Run lenghty task
                                                                     PrepareUberblick()
                                                                     '--Close form once done (on GUI thread)
                                                                     pic.Invoke(New Action(Sub() pic.StopCircular()))
                                                                     pic.Invoke(New Action(Sub() pic.Close()))
                                                                 End Sub)

                        '--Show the form
                        pic.ShowDialog()
                        Task.WaitAll(work)

                        If WYSWIG_Uberblick.Document IsNot Nothing Then
                            WYSWIG_Uberblick.Document.Write(String.Empty)
                        End If

                        '--Pobranie wszystkich html'ow wszystkich podsekcji artykulow (w tym wypadku numerów artykułów jako podsekcji) (dla sekcji Uberblick)
                        WYSWIG_Uberblick.DocumentText = _htmlFactory.GetAllUberblickHTML
                    Else
                        TaskDialog.Show(New TaskDialogInfo("Information", eTaskDialogIcon.NoEntry, "Infor", "Critical error occured", eTaskDialogButton.Ok, eTaskDialogBackgroundColor.Blue, Nothing, Nothing, Nothing, "Jakis footer text", Nothing))
                        e.Cancel = True
                    End If

ProcessArticle 函数:

Public Function ProcessArticle(artikel As ArticlesVariations) As Boolean

        Dim result = True
        Dim strcon = New AppSettingsReader().GetValue("ConnectionString", GetType(System.String)).ToString()

        Using connection As New SqlConnection(strcon)
            '-- Open generall connection for all the queries
            connection.Open()
            '-- Make the transaction.
            Dim transaction As SqlTransaction
            transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted)

            Dim newArticleRowId As Integer = 0
            Dim articleIndex As Integer = 0
            Try
                For Each kvp As KeyValuePair(Of Integer, Artikel) In artikel.collection
                    Dim ckey As Integer = kvp.Key
                    articleIndex = kvp.Key              'save article key
                    Dim data As Artikel = kvp.Value

                    '-- If given article contains images list (artikel_images is a list with pictures associated with article)
                    If Not IsNothing(artikel.collection(articleIndex).ArtikelImages) Then
                        For Each img In artikel.collection(articleIndex).ArtikelImages
                            '--Insert article's images if exists
                            Using cmd As New SqlCommand("INSERT INTO T_Article_Image (Path, FK_Artikel_ID, Position) VALUES (@Path, @FK_Artikel_ID, @Position)", connection)
                                cmd.CommandType = CommandType.Text
                                cmd.Connection = connection
                                cmd.Transaction = transaction
                                cmd.Parameters.AddWithValue("@Path", img.Path)
                                cmd.Parameters.AddWithValue("@FK_Artikel_ID", newArticleRowId)
                                cmd.Parameters.AddWithValue("@Position", img.Position)
                                cmd.ExecuteScalar()
                            End Using
                        Next
                    End If

                    '-- If given article contains articles variations list (artikel_variation_attributes is a list with variations associated with article)
                    If Not IsNothing(artikel.collection(articleIndex)._artikel_variation_attributes) Then
                        For Each var In artikel.collection(articleIndex)._artikel_variation_attributes

                            '--Insert article's images if exists
                            Using cmd As New SqlCommand("INSERT INTO T_Artikel_T_Variation (FK_Variation_VariationAttribute_ID, FK_Artikel_ID, Position) VALUES (@FK_Variation_VariationAttribute_ID, @FK_Artikel_ID, @Position)", connection)
                                cmd.CommandType = CommandType.Text
                                cmd.Connection = connection
                                cmd.Transaction = transaction
                                cmd.Parameters.AddWithValue("@FK_Variation_VariationAttribute_ID", New Variation_VariationAttribute(var.FkVariationId, var.FkVariationAttributeId).GetId())
                                cmd.Parameters.AddWithValue("@FK_Artikel_ID", newArticleRowId)
                                cmd.Parameters.AddWithValue("@Position", var.Position)
                                cmd.ExecuteScalar()
                            End Using
                        Next
                    End If

                Next
                transaction.Commit()
            Catch ex As Exception
                result = False
                '-- Roll the transaction back.
                Try
                    transaction.Rollback()
                Catch ex2 As Exception
                    ' This catch block will handle any errors that may have occurred
                    ' on the server that would cause the rollback to fail, such as
                    ' a closed connection.
                    'Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType())
                    'Console.WriteLine("  Message: {0}", ex2.Message)
                End Try

            End Try
        End Using

        Return result
    End Function

然而,当涉及到错误或这些方法中的任何问题时,一切正常(来自我们的示例):

Dim resu As Boolean = createArticle.ProcessArticle(_artikelsAndTheirVariationsFinal)

或者这个方法:

PrepareUberblick()

我的循环表单没有关闭,但它仍在运行(卡住了)。当我使用Alt+F4 杀死我的圆形表单时,我看到一条错误消息。我假设发生错误时,错误消息窗口不会显示在前面,而是隐藏在圆形表单后面。

这里的问题是:你知道如何解决它,所以当发生错误时,错误消息会显示在前面,以便用户可以确认然后关闭循环表单?

【问题讨论】:

  • 错误信息是什么?
  • 它关于我使用的特定功能。在这种情况下,如果错误来自 Dim resu As Boolean = createArticle.ProcessArticle(_artikelsAndTheirVariationsFinal) 或第二个 PrepareUberblick() 错误将与此有关.. 它更像是关于如何处理的错误并不重要添加额外的代码来改进我的循环使用的当前实现,所以当任务中发生错误时,如何在应用程序前面显示它而不是在后面,所以我不需要杀死循环表单来查看它。

标签: vb.net


【解决方案1】:

如果你想提醒用户发生了什么事,你可以从你的圆形表单中显示 MessageBox,它应该出现在它的顶部,因为它是在同一个线程上生成的。您可以在Catch中显示MessageBox

Try
    '--Run lenghty task
    resu = createArticle.ProcessArticle(_artikelsAndTheirVariationsFinal)
Catch ex As Exception
    pic.Invoke(Sub() MessageBox.Show(ex.message))
End Try
'--Close form once done (on GUI thread)        
pic.Invoke(New Action(Sub() pic.StopCircular()))
pic.Invoke(New Action(Sub() pic.Close()))

这样,用户需要在循环表单关闭之前点击 MessageBox 上的“确定”。

您的整个问题源于您没有在创建表单的同一线程上调用 MessageBox.Show() 。从您的示例中不清楚表单的创建位置,无论它是否在 UI 线程上。在任何一种情况下,创建表单的任何线程都必须与引发消息框的线程相同,以便 MessageBox 成为表单的模态。通过调用pic.Invoke(Sub() MessageBox.Show(ex.message)),您可以确保它显示在表单的线程上,并且是模态的。您通常可以使用 overload 强制父窗口具有

Public Shared Function Show (
    owner As IWin32Window,
    text As String
) As DialogResult

应该是

pic.Invoke(Sub() MessageBox.Show(pic, ex.message))

另见:

Does MessageBox.Show() automatically marshall to the UI Thread?

Why use a owner window in MessageBox.Show?

【讨论】:

  • 你的意思是如果我把 msgbox(ex.tostring) 放在那个 catch 语句中,它会在那个循环表单的顶部显示给用户吗?它会从 Task.WaitAll(tsk) 开始,还是会卡在那里?在这种情况下,您是否也可以展示如何实现这样的结构?
  • 它不会显示在表单顶部,因为它是从任务生成的,即不是从 UI 线程生成的。见stackoverflow.com/questions/559252/…。但是您可以将一个方法放在循环形式中,以便在发生错误时调用该方法。我将编辑我的答案。
  • 嗨,谢谢。实施您的解决方案仍有问题。情况如下:有我放置用户控件的主窗体,在这个用户控件上我有一些向导控件,所以我可以返回/下一步。并且这个循环表单被放置在向导上(等等用户控件)。当我只使用这个时: pic.Invoke(Sub() MessageBox.Show(pic, ex.message)) 我没有看到任何错误消息(我检查了一些错误的员工)。我假设我也必须重载,正如您在我的用户控件上提到的 Show 一样,但是这里面应该有什么工作?你能帮我解决一下吗?
  • 应该有一个。它通过一个最小的例子对我有用,所以你必须有其他事情发生。不清楚。
  • hmm.. 这个公共共享功能显示是完整的功能还是应该在里面填写一些东西?如果是这样,我将其置于用户控制之下并且无法正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-19
  • 2011-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多