表单和错误消息中的任务函数

时间:2016-07-28 18:30:47

标签: vb.net

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

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删除我的循环表单时,我看到一条错误消息。我假设发生错误时,错误消息窗口不会显示在前面,但它隐藏在循环表单后面。

以下是问题:您是否知道如何修复它,以便在发生错误时,错误信息显示在前面,以便用户可以确认,然后圆形表格将被关闭?

1 个答案:

答案 0 :(得分:0)

如果您想提醒用户发生了某些事情,您可以从圆形表单中显示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上的OK。

你的整个问题源于你没有在创建表单的同一个线程上调用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?