Solved

Form not instantiated on inter-thread call OR how to load a form w/o making visible

Posted on 2006-11-06
4
247 Views
Last Modified: 2010-05-18

Hey, I have an MDI application with a child window that is sort of an "output" window.  I also have buttons that start processes on background threads, and sometimes when the process is done it needs to send text to the output window.  So I made my Write functions thread-safe as follows (pretty much parroting another answer from this great site -- I don't understand this as well as I should).

In my OutputWindow form:

    Public Sub Write(ByVal txt As String)
        AppendLine(txt)
    End Sub

    Delegate Sub SetTextCallback(ByVal [text] As String)

    Private Sub AppendLine(ByVal txt As String)

        ' InvokeRequired required compares the thread ID of the
        ' calling thread to the thread ID of the creating thread.
        ' If these threads are different, it returns true.

        If Me.RichTextBox1.InvokeRequired Then
            Dim d As New SetTextCallback(AddressOf RawAppendLine)
            Me.Invoke(d, New Object() {txt})
        Else
            RawAppendLine(txt)
        End If

    End Sub

    Private Sub RawAppendLine(ByVal txt As String)

        RichTextBox1.AppendText(vbCrLf + txt)
        ScrollToEnd()

    End Sub

Now... when I start my application, I *New* the form but I do not set Visible=True (which I think means the form and constituent controls do not actually get loaded) unless the user has set an option that he wants it visible on startup.  If this option is not set and it is not made visible, calls to Write from an alternate thread fail with the following exception:

"Invoke or BeginInvoke cannot be called on a control until the window handle has been created."

Now, BEFORE this error the program uses the Write function at startup from the same thread (for messages like "Program started") and when the user eventually shows the window it appears with all the messages, which seems to mean the RichTextBox was loaded.  So this succeeds:

1) Starts invisible (New but no Visible=True)
2) Write from same thread
3) User calls Visible=True (from menu item) (previous writes are visible, which seems to mean it was instantiated?)
4) Write from other thread

And this fails

1) Starts invisible (New but no Visible=True)
2) Write from same thread  (why didn't this instantiate the control, i.e., "create the window handle"?)
3) Write from other thread   <-- above exception!

Anybody have any good theories which fit these observations??  I'd like to (1) fix this and (2) understand a little better.  

Thanks in advance...






0
Comment
Question by:riceman0
  • 2
4 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 17881954
   Public Sub Write(ByVal txt As String)
        AppendLine(txt)
    End Sub

In this function you can test whether form handle is created. You can subscribe to Control.HandleCreated Event and set some flag in the handler for this. If form is not created yet, accumulate all text in some container for example, StringBuilder or List<String>.
When form is shown first time, show information from container to RichTextBox1. From this moment, Write function can call AppendLine and safely use Invoke and RichTextBox1.

Unfortunately, .NET doesn't allow to create valid visible form - you cannot work normally with form controls and execute Invoke unless form is shown first time.
0
 

Author Comment

by:riceman0
ID: 17882021

Oh, man: subscribing to events, creating a flag.  

Seems like a bad oversight that they didn't allow you to start a window invisible, would save a lot of headache.

Question before I try all that... I suspect my window HAS been created, since the previous same-thread Write calls work, yes?  Why then this error?



0
 
LVL 48

Accepted Solution

by:
AlexFM earned 500 total points
ID: 17882867
Well, possibly Form allows to set control properties before handle is created. But Invoke cannot work before handle is created. Handle is created only when Form.Show function is called, and this immediately makes form visible.
I think that when form is hidden (after it was shown initially), Invoke can fail as well. At least I know, that when form is hidden and shown again, its handle may change.
So, to make this working, I suggest the following algorithm (pseudo-code):

dim handleExists as boolean = false

HandleCreated:
    handleExists = true;
    Add text from container to RichTextBox
    Clear container

HandleDestroyed:
    handleExists = false;

AppendLine:
    if handle doesn't exist: add line to container
    else: existing code
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Calling web service and its methods dynamically 2 73
vb.net help 4 34
Access Schema 6 23
How to repeat the data 4 14
Well, all of us have seen the multiple EXCEL.EXE's in task manager that won't die even if you call the .close, .dispose methods. Try this method to kill any excels in memory. You can copy the kill function to create a check function and replace the …
Article by: Kraeven
Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
This video shows how to quickly and easily add an email signature for all users on Exchange 2016. The resulting signature is applied on a server level by Exchange Online. The email signature template has been downloaded from: www.mail-signatures…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

808 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question