Results 1 to 10 of 10

Thread: [RESOLVED] Type of argument for .Invoke()

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2007
    Location
    cobwebbed to PC
    Posts
    311

    Resolved [RESOLVED] Type of argument for .Invoke()

    Hi folks

    The MDSN page for the Control.Invoke method specifies:

    Control.Invoke Method (Delegate)

    Now I was given in my admittedly limited knowledge to understand that a delegate is just a variable that holds a reference to a function or sub and using a lamda in place ends up passing the same thing when used as a parameter; a reference to a function. (I think of this as similar to passing function pointers in C and a lambda parameter just passes a pointer for a function that's written as an argument)

    This could be where the following confusion stems from I guess but here goes:

    The argument is asked for as a delegate. Using 'SomeControl.Invoke(Sub() somesub(someargs))' works fine. seems to me that's because the argument is a lambda that is a Sub that calls some other sub.
    Yet trying trying to use a Function lambda or a multi-line lambda does not work because (and here's the screen head-butting bit) "the expression does not produce a value"
    ...
    But a lamda produces a value surely, the reference to the anonymous function?
    And if not then how did the original single line Sub lambda work? If lambdas don't fulfil this requirement then how can any form of them work at all? Seems like it is supposed to take delegates but only works for particular types of them or when they're declared in particular ways??

    Anyway what I'd like to end up with is being able to go:

    vb Code:
    1. SomeControl.Invoke(Sub()
    2.     Foo()
    3.     If (Something) then
    4.         Bar()
    5.     End If
    6. End Sub)

    Instead of

    vb Code:
    1. Private Sub StupidHelperSub()
    2.     Bar()
    3.     If (something) Then
    4.         Foo()
    5.     End If
    6. End sub
    7.  
    8. ...
    9.  
    10. SomeControl.Invoke(Sub() StupidHelperSub())
    Last edited by wolf99; Dec 11th, 2015 at 12:06 PM.
    Thanks

  2. #2

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2007
    Location
    cobwebbed to PC
    Posts
    311

    Re: Type of argument for .Invoke()

    Furthermore, and separately: if the argument should be a delegate

    How come neither of the following work?

    vb Code:
    1. somecontrol.Invoke(Foo())
    2.  
    3. SomeControl.Invoke(AddressOf Foo())
    Thanks

  3. #3

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2007
    Location
    cobwebbed to PC
    Posts
    311

    Re: Type of argument for .Invoke()

    So I went back to the example on the Control.Invoke() MSDN page and used the exact syntax there (give or take some names!):

    vb Code:
    1. Delegate Sub StupidHelperDelegate()
    2.  
    3. Sub StupidHelpersub()
    4.     Foo()
    5.     If (SomeCondition) Then
    6.         Bar()
    7.     End If
    8. End Sub
    9.  
    10. ...
    11.  
    12. Dim LordHelpUsAtThisLevelOfUselessSyntax As StupidHelperDelegate = New StupidHelperDelegate(AddressOf StupidHelperSub)
    13. SomeControl.Invoke(LordHelpUsAtThisLevelOfUselessSyntax)

    This works. but as you might be able to tell, my opinion on having a type and a variable of that type to hold a reference to an address to 4 lines of code just to run those 4 lines of code in a language that has lambdas is the height of stupidity.
    Surely there must be a more succinct method?
    Thanks

  4. #4
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,424

    Re: Type of argument for .Invoke()

    Code:
    Delegate Sub StupidEnquirerDelegate()
     
    Sub StupidEnquirersub()
        If StupidEnquirerControl.InvokeRequired Then
            'if the control needs invoking on the thread, the delegate recalls this method
            StupidEnquirerControl.Invoke(New StupidEnquirerDelegate(AddressOf StupidEnquirersub))
        Else 
            'if invoking has completed or is not necessary, this runs   
            StupidCodeName() 'such as Foo or Bar
        End If
    End Sub
    Last edited by .paul.; Dec 11th, 2015 at 02:17 PM.

  5. #5
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Type of argument for .Invoke()

    Oooh. I don't know the answer to this, offhand. Which naturally means it sounds really fun to find the answer. Let's start with #2, which I CAN answer.

    First sample:
    Code:
    someControl.Invoke(Foo())
    The reason this is an error is because tacking a parameter list onto Foo means you're telling VB that you want to execute the method, and use the value it returns as the Delegate parameter to Invoke. That's also the reason this doesn't work:
    Code:
    someControl.Invoke(AddressOf Foo())
    That's saying something similar, but we have to understand what AddressOf does: behind the scenes, it creates a Delegate for the method you give it, and returns that Delegate. So this line says, "Execute Foo(), then convert the Delegate it returns to a Delegate for Invoke()." But Foo() doesn't return a Delegate, so it fails. The appropriate syntax is:
    Code:
    someControl.Invoke(AddressOf Foo)
    Sometimes parenthesis are optional in VB .NET, and the language fills them in for you. In this case, and a couple of others, they're mandatory and leaving them out has significance. This is why it's a joke that people say "VB is easy to learn", this rule's more like Perl than anything else. You could actually write a Function Foo() that returns a Delegate and your above code would work, I'm just not sure /which/ of the two lines it'd be.

    Your #3 description is the way we had to do it in the Bad Old Days of .NET 1. Somewhere around VS 2005, AddressOf got a little more useful, and then when lambdas came out in VS 2008 many of the use cases for defining your own Delegate types went away. It's a syntax that always works, but I agree it's a bit much. (We also had to do this for all event handlers if we made our own events back then!)

    So let's go back to #1. I was surprised this causes an error, so I had to test it myself. When I tried this code, it worked with no error:
    Code:
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Button1.Invoke(Sub()
                           Foo()
                           If (True) Then
                               Bar()
                           End If
                       End Sub)
    End Sub
    But I don't think you're crazy. I've seen this error before when dealing with things that take various Delegates, and I think it's more common when something's taking Action() or Func(Of T), those have different conversion rules than Delegate.

    If you have some code that's creating the error, I'm sure I could tell you what's going on if you post exactly that code.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  6. #6
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,598

    Re: Type of argument for .Invoke()

    Would it be useful to know which version of VB.Net the OP is using, or anything 2010 and after should behave the same so doesn't matter?

  7. #7
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Type of argument for .Invoke()

    True, I tested my code in VS 2010, but versions earlier than that might behave differently. I think VS 2005 didn't support lambdas?
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  8. #8

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2007
    Location
    cobwebbed to PC
    Posts
    311

    Re: Type of argument for .Invoke()

    Hi Folks,

    Thanks for the discussion! I am using VS 2010.

    So basically my use of invoke is down to the events fired off by a FileSystemWatcher being on a separate thread. When these events happen I want to read the files in the watched directory and update related items listed in a ComboBox. If one of the files is already open then the serialised object should also be updated, and any other controls bound to it.

    After reading Sitten Spynne's post I tried the lambda sub again to find that it builds without issue, though I could swear this is exactly what I did first time around! Chalk it up to Friday frustrations maybe

    vb Code:
    1. Private Sub FileWatcher_Changed(sender As System.Object, e As System.IO.FileSystemEventArgs) Handles _
    2.     FileWatcher.Changed, FileWatcher.Created, FileWatcher.Deleted, FileWatcher.Renamed
    3.     If ProductComboBox.InvokeRequired Then
    4.         ProductComboBox.Invoke(Sub()
    5.                                                ScanProfiles()
    6.                                                If (WorkingProfile IsNot Nothing) Then
    7.                                                    UpdateBindings(WorkingProfile)
    8.                                               End If
    9.                                            End Sub)
    10.     Else
    11.         ScanProfiles()
    12.         If (WorkingProfile IsNot Nothing) Then
    13.             UpdateBindings(WorkingProfile)
    14.         End If
    15.     End If
    16. End Sub
    Thanks

  9. #9
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Type of argument for .Invoke()

    Quote Originally Posted by Sitten Spynne View Post
    True, I tested my code in VS 2010, but versions earlier than that might behave differently. I think VS 2005 didn't support lambdas?
    It didn't.
    If I remember right the progression was something like this:
    VB2008 - Lambdas introduced, but only as functions, and only single-lined
    VB2010 - Multi-line lambdas introduced, sub support also added


    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  10. #10
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: [RESOLVED] Type of argument for .Invoke()

    To make you feel better: sometimes Intellisense/whatever does the syntax checking gets confused, and a good reboot makes things right again. It's rare, but given the amount of time we spend at these tools, "rare" has to be /very/ rare for us to not see it.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width