Solved

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

Posted on 2006-11-06
4
248 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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
write xml in vb.net 2 41
ASP/VB email question 4 58
Obtain cell value using column ID in DataGrid using VB.NET 2 34
VB.Net - MemoryMappedFiles - Confirm receipt 2 35
Since .Net 2.0, Visual Basic has made it easy to create a splash screen and set it via the "Splash Screen" drop down in the Project Properties.  A splash screen set in this manner is automatically created, displayed and closed by the framework itsel…
The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

679 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