0

I have a form whose role is to show the user a circular progress graphic while the user is waiting on particular stuff to be done. This is the simple code of it:

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

Below is an example of how I use it (in this case two places)

 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 function:

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

Everything works correctly, however, when it comes to error or whatever within those methods (from our example):

Dim resu As Boolean = createArticle.ProcessArticle(_artikelsAndTheirVariationsFinal)

or this method:

PrepareUberblick()

My circural form is not closing, but it's still running (it's stuck). When I do Alt+F4 to kill my circular form, I see an error message. I assume that when an error occurs, the error message window is not going to be shown in front but it's hidden behind the circular form.

Here's the question: do you know how to fix it so when an error occurs, an error message show up in front, so user could acknowledge and then the circular form would be closed?

  • What is the error message? – Tim Jul 28 '16 at 18:32
  • its about specific function i use. In this case if error came out from Dim resu As Boolean = createArticle.ProcessArticle(_artikelsAndTheirVariationsFinal) or in second one PrepareUberblick() the error will be about this one.. Its more like doesn't matter what error is about it's about how to add additional code to improve current implementation of my circural usage so when there is error occur in task, how to show it in front of app and not to be behind so i would dont need to kill circural form to see it. –  Jul 28 '16 at 18:35

1 Answers1

0

If you want to alert the user that something happened, you could show the MessageBox from your circular form, which should appear on top of it because it's generated on the same thread. You can show the MessageBox in the Catch

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()))

This way, the user will need to click OK on the MessageBox before the circular form closes.

Your whole issue stemmed from the fact that you were not calling MessageBox.Show() on the same thread that the form was created on. It's not clear from your example where the form is created, whether it's on the UI thread or not. In either case, whichever thread the form is created on must be the same one that the message box is raised on, in order for the MessageBox to be modal to the form. By calling pic.Invoke(Sub() MessageBox.Show(ex.message)), you ensure it's shown on the form's thread, and will be modal to it. You can typically force the parent window by using the overload which has

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

which would be

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

Also see:

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

Why use a owner window in MessageBox.Show?

Community
  • 1
  • 1
djv
  • 15,168
  • 7
  • 48
  • 72
  • do you mean if i put msgbox(ex.tostring) in that catch statment will it be shown to user on top of that circural form? and will it go next from Task.WaitAll(tsk) or it would also stuck there?Is it also possible from your side to show how to implement such struct in this case? –  Jul 28 '16 at 21:26
  • It won't be shown on top of the form because it would be generated from a Task, i.e. not from the UI thread. See http://stackoverflow.com/questions/559252/does-messagebox-show-automatically-marshall-to-the-ui-thread. But you could maybe put a method in the circular form which you could call in the event of an error. I'll edit my answer. – djv Jul 29 '16 at 01:06
  • Hi, thx at first place. Have still problems to implement your solution. The situation is as follows: Have Main form in which i placed user control and on this user control i have some wizard control so i can do back/next. And this circural form is placed on wizard (so on user control). When i use this only: pic.Invoke(Sub() MessageBox.Show(pic, ex.message)) i dont see any error message (i checked placing some wrong staff). I assume i have to overload also as you mentioned Show on my user control, but what should be inside this to work? Can you help me out with it? –  Jul 29 '16 at 13:48
  • There should be one. It works on my end with a minimal example, so you must have something else going on. It's not clear. – djv Jul 29 '16 at 15:00
  • hmm.. is this Public Shared Function Show thats complete function or there something between should be filled out inside? If so i putted it in USer control and not working. –  Jul 30 '16 at 19:55
  • Forget about that, I have confused you. Just use the code I put above in place of yours. – djv Jul 30 '16 at 20:03
  • I've modified bit main post and paste you whole code to get better overlook. As mentioned if i get error in createArticle.ProcessArticle(_artikelsAndTheirVariationsFinal) this will be not shown: pic.Invoke(Sub() MessageBox.Show(ex.message)). What i am getting is message "Critical error occured" but this is already after as you can see in my code. What can be still wrong in my code i don't see message i should? –  Jul 31 '16 at 11:54