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

    Question

  • This is throwing me for a loop.

    I have a modeless form open with a richtextobx. I am using FileSystemWatch to monitor changes on a text log file. When changes are found I check to see how much the file has grown, and then read and append the new portion to the RTB. The log watcher form comes up, does its initial paint (which is NOT driven by FSW) all is OK. Some moments later when the log file first changes, and FSW gives the event, I marshal it back to the GUI thread for updating the RTB, but get this odd error. I have done this pretty much already in previous VS.NET without a hitch.

    As far as I know my window handle has been created at the time I call "Me.BeginInvoke" in the FSW event on the form, so what exactly is this trying to tell me???
    Friday, September 09, 2005 5:52 PM

Answers

  • I can't see anything specific that would cause the problems you've described with that code.  The only thing I can think of is that the file changed event firing is occuring before the Form's Load event is completed.  I wouldn't make the RefreshFile method Shared.

    Because you're using BeginInvoke/Invoke you don't need SyncLock (you're ensuring that only one specific thread will run the GUI update logic.  Plus, Form.InvokeRequired will allow you to avoid keeping track of threads.  I would write the code as follows:

     


    Public Class MyLogViewer
       Inherits System.Windows.Forms.Form

       Public Sub New()
          MyBase.New()
          ' other init code called here
       End Sub

       Private Delegate Sub RefreshFileDelegate(ByVal frm As MyLogViewer)
       Private rfd As RefreshFileDelegate = New RefreshFileDelegate(AddressOf RefreshFile)

       Private Sub RefreshFile()
          If InvokeRequired Then
             BeginInvoke(rfd)
          Else
             ' Do GUI Updates here
          End If
       End Sub

       Private Sub mFileMonitor_Changed( _
          ByVal sender As Object, _
          ByVal e As System.IO.FileSystemEventArgs) _
             Handles mFileMonitor.Changed
          RefreshFile()
       End Sub

    End Class

     

    Saturday, September 10, 2005 1:43 PM
  • Yes, the message would seem to imply the form is not yet loaded to me as well. But it has been up, and done the initial load from the log file, and maybe 10-15 seconds have passed before my inducing an update of the log file, and ultimately the FSW event.

    I took the synclock protection out, and reverted it back to non-shared, and still this persists. These don't seem to be material to the issue.

    As mentioned, this was originally done in VS2003, and I brought the source for the log watch form into the project. Perhaps there was some kind of import/conversion to VS2005 that did not happen when I added the form to the project??? I am going to try and re-write this newly from scratch in VS2005 to see if this makes a different.

    That did not help either. Behaves the same way.

    Hmmm... There is a property I have on the form, which is the path to the file. When the property is set by the caller who creates the form. At this time I set the form.Text to the path of the file.  I changed the way this works. Now in the property I only save the name of the file in a form variable. I defer the GUI update into the Activated event (with protection to keep it from running more than once). Now it all works perfectly.

    I have my problem taken care of, so I am a happy camper. But what seems to be different from VS2003 to VS2005 is a behavior that if I modify a graphic element after the form is instanced, but before it is actually shown, that there is this delayed problem on BeginInit and one gets the subject-line error.

    Well shoot, that is not quite it either. I tried making a simple program with exactly these parameters, and it would not exhibit the problem. Perhaps the initialization of the FSW in the property-set ties into this somehow?  I can't seem to make it happen again in something simple, but I do know for sure that moving the code from the property-set to the activated-event made the problem go away. But I can not identify what I touched in the property-set that causes this condition that I fell into much later on when I did my first BeginInvoke.
    Monday, September 12, 2005 3:15 PM

All replies

  • How is the event handler defined, Shared?
    Friday, September 09, 2005 6:39 PM
  • It was not SHARED so I tried making it so. It made no difference.

    I notice many examples use shared routines for delegates, but I have not previously found the need to make them shared. Maybe I missed it, but I have not seen it stated in documentation this is required. So I am not sure what this is about, but it doesn't help here, regardless.
    Friday, September 09, 2005 7:20 PM
  • Sounds like you're confusing the delegate and the event handler.
    Here's some sample code that deals with an FSW object:


    Delegate Sub FileChangedDelegate()
    Private Sub FileChanged()
            ' Do something
    End Sub
    Private Sub FileSystemWatcher1_Changed(ByVal sender As Object _
    , ByVal e As System.IO.FileSystemEventArgs) _
    Handles FileSystemWatcher1.Changed
        BeginInvoke(New FileChangedDelegate(AddressOf FileChanged))
    End Sub

     


    How is it different from your code?
    Friday, September 09, 2005 7:38 PM
  • The difference between mine and yours is that I only invoked the delegate constructor once, rather than on each invocation as you do. 

    Paraphrasing a bit, I basically have this.  And at the risk of repeating, this does work for me in VS2003, so it appears more likely to be a behavioural difference, rather than a new-code problem. What do you think?



    Public
    Class MyLogViewer
       Inherits System.Windows.Forms.Form

       Public
    GUIThread As Thread

       Public Sub New()
          
    MyBase.New()
          ' other init code called here
          GUIThread = System.Threading.Thread.CurrentThread
       End Sub

       Friend Delegate Sub RefreshFileDelegate(ByVal frm As MyLogViewer)
       Friend rfd As RefreshFileDelegate = New RefreshFileDelegate(AddressOf RefreshFile)

       Public Shared Sub RefreshFile(ByVal frm As MyLogViewer)
          
    If Thread.CurrentThread Is frm.GUIThread Then
             
    SyncLock frm
                
    ' Do various GUI updates here
             
    End SyncLock
          
    Else
             
    frm.BeginInvoke(frm.rfd, New Object() {frm})
          
    End If
       End Sub

       Private Sub mFileMonitor_Changed( _
          ByVal sender As Object, _
          ByVal e As System.IO.FileSystemEventArgs) _
             Handles mFileMonitor.Changed
          RefreshFile(
    Me)
       End Sub

    End Class

     



    Originally the marshalled GUI update SUB was not shared, and so, as such, did not need the form instance parameter. I see you wrote your FileChanged as NOT shared!

    Friday, September 09, 2005 10:11 PM
  • I can't see anything specific that would cause the problems you've described with that code.  The only thing I can think of is that the file changed event firing is occuring before the Form's Load event is completed.  I wouldn't make the RefreshFile method Shared.

    Because you're using BeginInvoke/Invoke you don't need SyncLock (you're ensuring that only one specific thread will run the GUI update logic.  Plus, Form.InvokeRequired will allow you to avoid keeping track of threads.  I would write the code as follows:

     


    Public Class MyLogViewer
       Inherits System.Windows.Forms.Form

       Public Sub New()
          MyBase.New()
          ' other init code called here
       End Sub

       Private Delegate Sub RefreshFileDelegate(ByVal frm As MyLogViewer)
       Private rfd As RefreshFileDelegate = New RefreshFileDelegate(AddressOf RefreshFile)

       Private Sub RefreshFile()
          If InvokeRequired Then
             BeginInvoke(rfd)
          Else
             ' Do GUI Updates here
          End If
       End Sub

       Private Sub mFileMonitor_Changed( _
          ByVal sender As Object, _
          ByVal e As System.IO.FileSystemEventArgs) _
             Handles mFileMonitor.Changed
          RefreshFile()
       End Sub

    End Class

     

    Saturday, September 10, 2005 1:43 PM
  • Yes, the message would seem to imply the form is not yet loaded to me as well. But it has been up, and done the initial load from the log file, and maybe 10-15 seconds have passed before my inducing an update of the log file, and ultimately the FSW event.

    I took the synclock protection out, and reverted it back to non-shared, and still this persists. These don't seem to be material to the issue.

    As mentioned, this was originally done in VS2003, and I brought the source for the log watch form into the project. Perhaps there was some kind of import/conversion to VS2005 that did not happen when I added the form to the project??? I am going to try and re-write this newly from scratch in VS2005 to see if this makes a different.

    That did not help either. Behaves the same way.

    Hmmm... There is a property I have on the form, which is the path to the file. When the property is set by the caller who creates the form. At this time I set the form.Text to the path of the file.  I changed the way this works. Now in the property I only save the name of the file in a form variable. I defer the GUI update into the Activated event (with protection to keep it from running more than once). Now it all works perfectly.

    I have my problem taken care of, so I am a happy camper. But what seems to be different from VS2003 to VS2005 is a behavior that if I modify a graphic element after the form is instanced, but before it is actually shown, that there is this delayed problem on BeginInit and one gets the subject-line error.

    Well shoot, that is not quite it either. I tried making a simple program with exactly these parameters, and it would not exhibit the problem. Perhaps the initialization of the FSW in the property-set ties into this somehow?  I can't seem to make it happen again in something simple, but I do know for sure that moving the code from the property-set to the activated-event made the problem go away. But I can not identify what I touched in the property-set that causes this condition that I fell into much later on when I did my first BeginInvoke.
    Monday, September 12, 2005 3:15 PM
  • It's unclear, did you solve your problem?

    If not, maybe you can post the simple program that you re-created and get more detail.

    Monday, September 12, 2005 3:29 PM
  • I no longer get the error.

    I got to this point by modifying the original VS2003 to work around the new VS2005 problem behavior. The interaction is too subtle for me to identify exactly what caused this. I doubt this is common, and I suspect it may not be worth either of our time to persue.

    The thing I learned is that there is something, somewhere, when done at the wrong time will place the form in a state such that calling BeginInvoke will fail with the subject-line error message, well after the windows form handle has been initialized, and the form is visible, and working on the screen. The condition the error message reports seems to have nothing to do with the core of the problem. In the future I would be very wary of this error when it occurs after the form is displayed, and immediately look at what is being done after the form is loaded, but prior to it being displayed for the first time. A much-prior action can lead to this error. A bit like stepping in doo-doo, much after the cause.

    Monday, September 12, 2005 4:01 PM
  • I am getting similarly odd and unpredictable behavior with the invoke command on a form in a different context.  It can be hours after the form is loaded.

     I'm going to get rid of all the code in my form load event based on what you wrote at the end and see if that helps.  Has anyone found anything further about what causes this?

    Monday, July 10, 2006 5:04 PM
  • I had the same problem before. I got the same error message. Later I found the problem was because I initiated a form class object inside the event raising class. Once the event was raised, the event handler, which is a method of the form class, gets called. BUT, be careful HERE. In this case the method called is a member of the new form object not the real GUI form. Because the new form instance I created for handling the event, never displayed. For sure, it has no window handle. After I moved the event registration part to the form class. This problem was solved.

     Something like this:

     public CCIMain: Form

     public CCIMain()

    {

         FileImporter.ImportCompleted += new FileImporter.ImportCompleted (ImportCompleteHandler);

    }

    public void ImportCompleteHandler(arg1, arg2)

    {
        this.invoke(new EventHandler(updateResultText);

    }

    private void updateResultText(object 0, EventArgs e)

    {

        txtResult.Text ="Importing completed.";

    }

    Hope this can help

    Hugo Shuai

     

     

     

    Thursday, December 28, 2006 12:42 AM
  • Hi,

    I had the same error message and got rid of it like this: -

    The error pops up if the code is formed in this structure: -

    'this is a form with a label on it (please ignore the sloppy syntax this code is to demonstrate structure only)

    Public Class Form

    Shared ValueLabel As Label = New System.Windows.Forms.Label

    Dim MySeperateThreadObject As SeperateThreadObject

    Public Sub Go()

    MySeperateThreadObject = New SeperateThreadObject

    MySeperateThreadObject.NewThread.Start()

    End Sub

    End Class

    'this is a class which contains a routine which runs on a seperate thread

    Public Class SeperateThreadObject

    Public NewThread As Thread

    Public Sub New()

    NewThread = New Thread(AddressOf Me.BackgroundSub)

    End Sub

    Public Sub BackgroundSub()

    Form.ValueLabel.Invoke(New ValueDelegate(AddressOf Me.SetText), New Object() {"hello"})

    End Sub

    Public Delegate Sub ValueDelegate(ByVal str As String)

    Public Sub SetText(ByVal str As String)

    Form.ValueLabel.Text = str

    End Sub

    End Class

    If I move the highlighted subroutine into the Form class the message disappears: -

    Public Class Form

    Shared ValueLabel As Label = New System.Windows.Forms.Label

    Dim MySeperateThreadObject As SeperateThreadObject

    Public Sub Go()

    MySeperateThreadObject = New SeperateThreadObject

    MySeperateThreadObject.NewThread.Start()

    End Sub

    Public Sub SetText(ByVal str As String)

    Form.ValueLabel.Text = str

    End Sub

    End Class

    Public Class SeperateThreadObject

    Public NewThread As Thread

    Public Sub New()

    NewThread = New Thread(AddressOf Me.BackgroundSub)

    End Sub

    Public Sub BackgroundSub()

    Form.ValueLabel.Invoke(New ValueDelegate(AddressOf Form.SetText), New Object() {"hello"})

    End Sub

    Public Delegate Sub ValueDelegate(ByVal str As String)

    End Class

    You may see some similarities in your own code which you can address.

    Monday, February 05, 2007 11:50 PM
  • It is possible this error is related to the current state of the computer after an installation of a product.  If there is a setup update waiting in the background to process, there seem to be a host of items that set this off.  The most common one I discovered related to reintroducing a machine to a network after an upgrade where there were orphaned SIDs.

    • Edited by Crakdkorn Saturday, September 12, 2009 1:26 PM most common found was...
    Sunday, August 30, 2009 6:04 PM