yu_ominae
yu_ominae

Reputation: 2935

Running a form on a separate thread waiting for main UI thread to complete

In .NET 4.0 I'm dealing with an app which has a long loading time (about 20 seconds), so I wanted to display a swish scrolling marquee on a form that comes on top of the application whilst it is loading.

Since the main UI thread is doing all the loading of data UI elements, I couldn't get that to execute on a separate thread, so I ended up trying to run the form on a new thread. I ended up sticking this code in the form itself, to have it show itself on a new thread, like this:

Public Class frmWait

Public Property Message As String
    Get
        Return Me.lblMessage.Text
    End Get
    Set(value As String)
        If Not String.IsNullOrEmpty(value) Then
            Me.lblMessage.Text = value
        Else
            Me.lblMessage.Text = DefaultMessage
        End If
    End Set
End Property

Private OwnerThread As Thread
Private OwnerForm As Form
Private Const DefaultMessage As String = "しばらくお待ちください..."

Public Sub New(ByVal ParentForm As Form)

    InitializeComponent()

    Me.Message = DefaultMessage
    Me.OwnerForm = ParentForm

End Sub

Public Sub New(ByVal Message As String, ByVal ParentForm As Form)

    Call InitializeComponent()

    Me.Message = Message
    Me.OwnerForm = ParentForm

End Sub

Public Sub ShowOnThread()

    ' Position the form in the center of the owner
    With Me.OwnerForm
        Dim ownerCenter As New Point(.Location.X + CInt(.Width / 2), .Location.Y + CInt(.Height / 2))
        Me.Location = New Point(ownerCenter.X - CInt(Me.Width / 2), ownerCenter.Y - CInt(Me.Height / 2))
    End With

    Me.OwnerThread = New Thread(New ThreadStart(AddressOf Me.ShowDialog))
    Call Me.OwnerThread.Start()

End Sub

Public Shadows Sub Close()

    If Me.OwnerThread IsNot Nothing AndAlso Me.OwnerThread.IsAlive Then
        Call Me.OwnerThread.Abort()
    Else
        Call MyBase.Close()
    End If

End Sub

End Class

This is probably quite clumsy, but I am showing it in different places in the application, so this seemed the most code-efficient way of doing this...

It actually works quite well, but I am encountering problems from time to time with this and need some help on how to address these issues.

Any suggestions on how to resolve this would be most appreciated. Because I know virtually nothing about threading I probably coded this like a monkey, so if there is a better method to get this done, I would very much like to know about it.

The code I list is in VB.NET, but answer code in C# is fine too (for any overzealous retaggers)

UPDATE:

I realise now that I should have given a lot more details in my question... The wait form is actually not the first form I am displaying the app. There first is a login screen. When the user is authenticated, the login form launches the main interface of the app, which is the form which actually takes a long time to load.

I am displaying the wait form in between the login form and the main interface. I also use this form to cover for any long running tasks launched on the main interface by the user.

Upvotes: 0

Views: 2309

Answers (4)

tcarvin
tcarvin

Reputation: 10855

You could use the ApplicationContext class to allow the splash screen to be run first and then swap in the Main form when it is ready. You use it in place of your main form in the call to Application.Run:

Application.Run(new MyApplicationCtx())

Just googled up a article for you as well:

http://www.codeproject.com/Articles/5756/Use-the-ApplicationContext-Class-to-Fully-Encapsul

Upvotes: 0

Chris McKelt
Chris McKelt

Reputation: 1388

Have a look at TaskFactory.New

Run your threaded code of a different thread to keep the UI responsive

http://msdn.microsoft.com/en-us/library/ee782519.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-3

Upvotes: 0

J...
J...

Reputation: 31393

VisualStudio can do this for you. You can certainly write your own, of course, but if you look at your project options under Application there is a setting for Splash Screen. You can assign any form (other than the startup form) to be your splash screen. This runs on its own thread and you can marshall calls to it during startup to advance a progress bar, etc.

MSDN : Splash Screen

Upvotes: 1

Matt Wilko
Matt Wilko

Reputation: 27322

Instead of trying to show a dialog on a separate thread you should be moving your loading code to a separate thread / background worker.

Then just start your threads and show the progressbar on form_load and hide the progressbar when the thread completes:

Dim _progressForm As frmLoading

    Private Sub frmMain_Load(sender As System.Object, e As System.EventArgs) Handles Me.Load
        'start loading on a separate thread
        BackgroundWorker1.RunWorkerAsync()
        'show a marquee animation while loading
        _progressForm = New frmLoading
        _progressForm.ShowDialog(Me)
    End Sub

    Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        'simulate a long load
        For i As Integer = 1 To 10
            System.Threading.Thread.Sleep(1000)
        Next
    End Sub

    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        _progressForm.Close()
    End Sub

Upvotes: 1

Related Questions